| | |
| | | SourceCode/Bond/EAPSimulator/x64/ |
| | | Document/___CEID_________________.csv |
| | | Document/______CEID__.csv |
| | | SourceCode/Bond/x64/Debug/HsmsPassive.cache |
| | | SourceCode/Bond/x64/Debug/MasterState.dat |
| | | SourceCode/Bond/x64/Debug/Recipe/EQ10_Unit0.recipelist |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <cstdint> |
| | | namespace DAQCfg { |
| | | inline constexpr const char* Version = "1.0.1"; |
| | | inline constexpr uint32_t KickIfNoVersionSec = 5; |
| | | inline constexpr uint32_t RecvLoopIntervalMs = 5; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // BufferManager.cpp |
| | | #include "BufferManager.h" |
| | | |
| | | BufferManager::BufferManager(uint32_t id, std::string name, RetentionPolicy defaultPolicy) |
| | | : id_(id), name_(std::move(name)), defPolicy_(defaultPolicy) {} |
| | | |
| | | std::string BufferManager::name() const { |
| | | std::shared_lock lk(mtx_); |
| | | return name_; |
| | | } |
| | | void BufferManager::rename(const std::string& newName) { |
| | | std::unique_lock lk(mtx_); |
| | | name_ = newName; |
| | | } |
| | | |
| | | void BufferManager::start() { |
| | | std::unique_lock lk(mtx_); |
| | | for (auto& kv : map_) kv.second->clear(); |
| | | running_.store(true); |
| | | } |
| | | void BufferManager::stop() { |
| | | running_.store(false); |
| | | } |
| | | void BufferManager::clearAll() { |
| | | std::unique_lock lk(mtx_); |
| | | for (auto& kv : map_) kv.second->clear(); |
| | | } |
| | | |
| | | SampleBuffer& BufferManager::getOrCreate(uint32_t channelId) { |
| | | auto it = map_.find(channelId); |
| | | if (it != map_.end()) return *it->second; |
| | | auto buf = std::make_unique<SampleBuffer>(defPolicy_); |
| | | auto& ref = *buf; |
| | | map_[channelId] = std::move(buf); |
| | | return ref; |
| | | } |
| | | |
| | | void BufferManager::push(uint32_t channelId, int64_t ts_ms, double v) { |
| | | if (!running_.load()) return; // 忢æ¶ä¸¢å¼æ°æ°æ® |
| | | std::unique_lock lk(mtx_); |
| | | getOrCreate(channelId).push(ts_ms, v); |
| | | } |
| | | |
| | | std::vector<Sample> BufferManager::getSince(uint32_t channelId, int64_t tsExclusive, size_t maxCount) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = map_.find(channelId); |
| | | if (it == map_.end()) return {}; |
| | | return it->second->getSince(tsExclusive, maxCount); |
| | | } |
| | | std::vector<Sample> BufferManager::getRange(uint32_t channelId, int64_t from_ts, int64_t to_ts, size_t maxCount) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = map_.find(channelId); |
| | | if (it == map_.end()) return {}; |
| | | return it->second->getRange(from_ts, to_ts, maxCount); |
| | | } |
| | | |
| | | void BufferManager::setDefaultPolicy(const RetentionPolicy& p, bool applyToExisting) { |
| | | std::unique_lock lk(mtx_); |
| | | defPolicy_ = p; |
| | | if (applyToExisting) { |
| | | for (auto& kv : map_) kv.second->setPolicy(p); |
| | | } |
| | | } |
| | | void BufferManager::setPolicy(uint32_t channelId, const RetentionPolicy& p) { |
| | | std::unique_lock lk(mtx_); |
| | | getOrCreate(channelId).setPolicy(p); |
| | | } |
| | | RetentionPolicy BufferManager::getPolicy(uint32_t channelId) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = map_.find(channelId); |
| | | if (it == map_.end()) return defPolicy_; |
| | | return it->second->getPolicy(); |
| | | } |
| | | |
| | | std::vector<uint32_t> BufferManager::listChannels() const { |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<uint32_t> ids; ids.reserve(map_.size()); |
| | | for (auto& kv : map_) ids.push_back(kv.first); |
| | | return ids; |
| | | } |
| | | |
| | | void BufferManager::setChannelName(uint32_t channelId, const std::string& name) { |
| | | std::unique_lock lk(mtx_); |
| | | channelNames_[channelId] = name; |
| | | // 强å¶å建对åºç SampleBufferï¼å¯éï¼ |
| | | (void)getOrCreate(channelId); |
| | | } |
| | | |
| | | std::string BufferManager::getChannelName(uint32_t channelId) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = channelNames_.find(channelId); |
| | | if (it != channelNames_.end() && !it->second.empty()) return it->second; |
| | | // é»è®¤å |
| | | return "Ch-" + std::to_string(channelId); |
| | | } |
| | | |
| | | std::vector<BufferManager::ChannelInfo> BufferManager::listChannelInfos() const { |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<ChannelInfo> out; |
| | | out.reserve(map_.size()); |
| | | // 以âå·²æç¼å²å¨çééâ为åºåååºï¼å¦éååºææâå½åè¿ä½å°æªäº§çæ°æ®âçééï¼ä¹å¯éå channelNames_ åå¹¶ |
| | | for (auto& kv : map_) { |
| | | const uint32_t ch = kv.first; |
| | | auto it = channelNames_.find(ch); |
| | | out.push_back(ChannelInfo{ ch, (it != channelNames_.end() && !it->second.empty()) |
| | | ? it->second |
| | | : ("Ch-" + std::to_string(ch)) }); |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | BufferManager::ChannelStat BufferManager::getChannelStat(uint32_t channelId) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = map_.find(channelId); |
| | | if (it == map_.end()) return ChannelStat{ channelId, 0, 0, 0 }; |
| | | const auto& buf = *it->second; |
| | | return ChannelStat{ channelId, buf.size(), buf.earliestTs(), buf.latestTs() }; |
| | | } |
| | | |
| | | std::vector<BufferManager::ChannelStat> BufferManager::listChannelStats() const { |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<ChannelStat> out; out.reserve(map_.size()); |
| | | for (auto& kv : map_) { |
| | | const auto& buf = *kv.second; |
| | | out.push_back(ChannelStat{ kv.first, buf.size(), buf.earliestTs(), buf.latestTs() }); |
| | | } |
| | | return out; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "SampleBuffer.h" |
| | | #include <unordered_map> |
| | | #include <memory> |
| | | #include <shared_mutex> |
| | | #include <string> |
| | | #include <atomic> |
| | | #include <vector> |
| | | |
| | | class BufferManager { |
| | | public: |
| | | struct ChannelStat { |
| | | uint32_t id; |
| | | size_t size; |
| | | int64_t earliestTs; |
| | | int64_t latestTs; |
| | | }; |
| | | |
| | | public: |
| | | BufferManager(uint32_t id, std::string name, RetentionPolicy defaultPolicy = {}); |
| | | |
| | | // æ è¯ |
| | | uint32_t id() const { return id_; } |
| | | std::string name() const; |
| | | void rename(const std::string& newName); |
| | | |
| | | // ééæ§å¶ |
| | | void start(); |
| | | void stop(); |
| | | bool isRunning() const { return running_.load(); } |
| | | void clearAll(); |
| | | |
| | | // æ°æ®å读 |
| | | void push(uint32_t channelId, int64_t ts_ms, double v); |
| | | std::vector<Sample> getSince(uint32_t channelId, int64_t tsExclusive, size_t maxCount = 4096) const; |
| | | std::vector<Sample> getRange(uint32_t channelId, int64_t from_ts, int64_t to_ts, size_t maxCount = 4096) const; |
| | | |
| | | // çç¥ |
| | | void setDefaultPolicy(const RetentionPolicy& p, bool applyToExisting = false); |
| | | void setPolicy(uint32_t channelId, const RetentionPolicy& p); |
| | | RetentionPolicy getPolicy(uint32_t channelId) const; |
| | | |
| | | // éé管ç |
| | | std::vector<uint32_t> listChannels() const; |
| | | |
| | | // ===== æ°å¢ï¼ééï¼æ²çº¿ï¼åç§° ===== |
| | | void setChannelName(uint32_t channelId, const std::string& name); // 设置/æ´æ° |
| | | std::string getChannelName(uint32_t channelId) const; // è¥æªè®¾ç½®ï¼è¿å "Ch-<id>" |
| | | struct ChannelInfo { uint32_t id; std::string name; }; |
| | | std::vector<ChannelInfo> listChannelInfos() const; // æ¹ä¾¿ UI å表 |
| | | |
| | | std::vector<ChannelStat> listChannelStats() const; |
| | | // å个éé |
| | | ChannelStat getChannelStat(uint32_t channelId) const; |
| | | private: |
| | | SampleBuffer& getOrCreate(uint32_t channelId); |
| | | |
| | | mutable std::shared_mutex mtx_; |
| | | std::unordered_map<uint32_t, std::unique_ptr<SampleBuffer>> map_; |
| | | |
| | | // ===== æ°å¢ï¼ééå称表 ===== |
| | | std::unordered_map<uint32_t, std::string> channelNames_; |
| | | |
| | | uint32_t id_; |
| | | std::string name_; |
| | | RetentionPolicy defPolicy_; |
| | | std::atomic<bool> running_{ false }; |
| | | |
| | | |
| | | |
| | | |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // BufferRegistry.cpp |
| | | #include "BufferRegistry.h" |
| | | |
| | | BufferManager& BufferRegistry::getOrCreate(uint32_t managerId, const std::string& name, const RetentionPolicy& defPolicy) { |
| | | std::unique_lock lk(mtx_); |
| | | auto it = managers_.find(managerId); |
| | | if (it != managers_.end()) return *it->second; |
| | | auto bm = std::make_unique<BufferManager>(managerId, name, defPolicy); |
| | | auto& ref = *bm; |
| | | managers_[managerId] = std::move(bm); |
| | | return ref; |
| | | } |
| | | |
| | | std::vector<uint32_t> BufferRegistry::listManagers() const { |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<uint32_t> ids; ids.reserve(managers_.size()); |
| | | for (auto& kv : managers_) ids.push_back(kv.first); |
| | | return ids; |
| | | } |
| | | |
| | | BufferManager* BufferRegistry::find(uint32_t managerId) { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = managers_.find(managerId); |
| | | return (it == managers_.end()) ? nullptr : it->second.get(); |
| | | } |
| | | const BufferManager* BufferRegistry::find(uint32_t managerId) const { |
| | | std::shared_lock lk(mtx_); |
| | | auto it = managers_.find(managerId); |
| | | return (it == managers_.end()) ? nullptr : it->second.get(); |
| | | } |
| | | |
| | | void BufferRegistry::remove(uint32_t managerId) { |
| | | std::unique_lock lk(mtx_); |
| | | managers_.erase(managerId); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // BufferRegistry.h |
| | | #pragma once |
| | | #include "BufferManager.h" |
| | | #include <unordered_map> |
| | | #include <memory> |
| | | #include <shared_mutex> |
| | | |
| | | class BufferRegistry { |
| | | public: |
| | | // è·å/å建æå°æºå¨ç BufferManager |
| | | BufferManager& getOrCreate(uint32_t managerId, const std::string& name, const RetentionPolicy& defPolicy = {}); |
| | | |
| | | // æ¥è¯¢ |
| | | std::vector<uint32_t> listManagers() const; |
| | | BufferManager* find(uint32_t managerId); |
| | | const BufferManager* find(uint32_t managerId) const; |
| | | |
| | | // ç§»é¤ä¸ä¸ªç®¡çå¨ï¼å¯éï¼ |
| | | void remove(uint32_t managerId); |
| | | |
| | | private: |
| | | mutable std::shared_mutex mtx_; |
| | | std::unordered_map<uint32_t, std::unique_ptr<BufferManager>> managers_; |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // SampleBuffer.cpp |
| | | #include "SampleBuffer.h" |
| | | #include <algorithm> |
| | | |
| | | void SampleBuffer::push(int64_t ts_ms, double v) { |
| | | std::unique_lock lk(mtx_); |
| | | if (!data_.empty() && ts_ms < data_.back().ts_ms) { |
| | | ts_ms = data_.back().ts_ms; // ç®åçº æ£ä¸ºééåï¼ä¸¥æ ¼åºæ¯å¯æ¹ä¸ºä¸¢å¼/æå
¥æåº |
| | | } |
| | | data_.push_back({ ts_ms, v }); |
| | | pruneUnlocked(ts_ms); // ç¨å½ååå
¥æ¶é´ä½ä¸ºåèæ¶é´ |
| | | } |
| | | |
| | | std::vector<Sample> SampleBuffer::getSince(int64_t tsExclusive, size_t maxCount) const { |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<Sample> out; |
| | | if (data_.empty()) return out; |
| | | const size_t start = lowerBoundIndex(tsExclusive); |
| | | if (start >= data_.size()) return out; |
| | | const size_t n = std::min(maxCount, data_.size() - start); |
| | | out.reserve(n); |
| | | for (size_t i = 0; i < n; ++i) out.push_back(data_[start + i]); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<Sample> SampleBuffer::getRange(int64_t from_ts, int64_t to_ts, size_t maxCount) const { |
| | | if (to_ts < from_ts) return {}; |
| | | std::shared_lock lk(mtx_); |
| | | std::vector<Sample> out; |
| | | if (data_.empty()) return out; |
| | | const size_t L = lowerBoundInclusive(from_ts); |
| | | const size_t R = upperBoundInclusive(to_ts); |
| | | if (L >= R) return out; |
| | | const size_t n = std::min(maxCount, R - L); |
| | | out.reserve(n); |
| | | for (size_t i = 0; i < n; ++i) out.push_back(data_[L + i]); |
| | | return out; |
| | | } |
| | | |
| | | size_t SampleBuffer::size() const { std::shared_lock lk(mtx_); return data_.size(); } |
| | | bool SampleBuffer::empty() const { std::shared_lock lk(mtx_); return data_.empty(); } |
| | | int64_t SampleBuffer::latestTs() const { |
| | | std::shared_lock lk(mtx_); |
| | | return data_.empty() ? 0 : data_.back().ts_ms; |
| | | } |
| | | void SampleBuffer::clear() { |
| | | std::unique_lock lk(mtx_); |
| | | data_.clear(); |
| | | } |
| | | |
| | | void SampleBuffer::setPolicy(const RetentionPolicy& p) { |
| | | std::unique_lock lk(mtx_); |
| | | policy_ = p; |
| | | // ç«å³ææ°çç¥æ¸
䏿¬¡ï¼ä»¥âå½åææ° tsâ为åèï¼ |
| | | pruneUnlocked(data_.empty() ? 0 : data_.back().ts_ms); |
| | | } |
| | | RetentionPolicy SampleBuffer::getPolicy() const { |
| | | std::shared_lock lk(mtx_); |
| | | return policy_; |
| | | } |
| | | |
| | | void SampleBuffer::pruneUnlocked(int64_t ref_now_ms) { |
| | | switch (policy_.mode) { |
| | | case RetainMode::ByCount: |
| | | if (policy_.maxSamples > 0) { |
| | | while (data_.size() > policy_.maxSamples) data_.pop_front(); |
| | | } |
| | | break; |
| | | case RetainMode::ByRollingAge: { |
| | | if (policy_.maxAge.count() > 0) { |
| | | const int64_t cutoff = ref_now_ms - policy_.maxAge.count(); |
| | | while (!data_.empty() && data_.front().ts_ms < cutoff) data_.pop_front(); |
| | | } |
| | | break; |
| | | } |
| | | case RetainMode::ByAbsoluteRange: { |
| | | const bool valid = (policy_.absTo >= policy_.absFrom); |
| | | if (valid) { |
| | | // 丢å¼çªå£ä¹å¤çæ°æ®ï¼ä¸¤ç«¯é½è£ï¼ |
| | | while (!data_.empty() && data_.front().ts_ms < policy_.absFrom) data_.pop_front(); |
| | | while (!data_.empty() && data_.back().ts_ms > policy_.absTo) data_.pop_back(); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | size_t SampleBuffer::lowerBoundIndex(int64_t tsExclusive) const { |
| | | size_t L = 0, R = data_.size(); |
| | | while (L < R) { |
| | | size_t m = (L + R) >> 1; |
| | | if (data_[m].ts_ms <= tsExclusive) L = m + 1; else R = m; |
| | | } |
| | | return L; // 第ä¸ä¸ª > tsExclusive |
| | | } |
| | | size_t SampleBuffer::lowerBoundInclusive(int64_t tsInclusive) const { |
| | | size_t L = 0, R = data_.size(); |
| | | while (L < R) { |
| | | size_t m = (L + R) >> 1; |
| | | if (data_[m].ts_ms < tsInclusive) L = m + 1; else R = m; |
| | | } |
| | | return L; // 第ä¸ä¸ª >= tsInclusive |
| | | } |
| | | size_t SampleBuffer::upperBoundInclusive(int64_t tsInclusive) const { |
| | | size_t L = 0, R = data_.size(); |
| | | while (L < R) { |
| | | size_t m = (L + R) >> 1; |
| | | if (data_[m].ts_ms <= tsInclusive) L = m + 1; else R = m; |
| | | } |
| | | return L; // æåä¸ä¸ª <= tsInclusive çä¸ä¸ä¸ªä½ç½® |
| | | } |
| | | |
| | | int64_t SampleBuffer::earliestTs() const { |
| | | std::shared_lock lk(mtx_); |
| | | return data_.empty() ? 0 : data_.front().ts_ms; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // SampleBuffer.h |
| | | #pragma once |
| | | #include "../core/DataTypes.h" |
| | | #include <deque> |
| | | #include <vector> |
| | | #include <shared_mutex> |
| | | #include <chrono> |
| | | |
| | | enum class RetainMode { |
| | | ByCount, // ææ ·æ¬æ°ä¸é |
| | | ByRollingAge, // ææ»å¨æ¶é´çªå£ï¼maxAgeï¼ |
| | | ByAbsoluteRange // æç»å¯¹æ¶é´æ®µ [absFrom, absTo] |
| | | }; |
| | | |
| | | struct RetentionPolicy { |
| | | RetainMode mode = RetainMode::ByCount; |
| | | size_t maxSamples = 100000; // ByCount ç¨ |
| | | std::chrono::milliseconds maxAge{ std::chrono::hours(1) }; // ByRollingAge ç¨ |
| | | int64_t absFrom = 0; // ByAbsoluteRange ç¨ |
| | | int64_t absTo = 0; // ByAbsoluteRange ç¨ï¼absTo>=absFrom ææï¼ |
| | | }; |
| | | |
| | | class SampleBuffer { |
| | | public: |
| | | explicit SampleBuffer(RetentionPolicy policy = {}) : policy_(policy) {} |
| | | |
| | | // åï¼ææ¶é´æ³é墿¨å
¥ï¼ä¹±åºä¼è¢«ç®åçº æ£ä¸ºééåï¼ |
| | | void push(int64_t ts_ms, double v); |
| | | |
| | | // è¯»ï¼æâtsExclusive ä¹åâçæ°æ°æ® |
| | | std::vector<Sample> getSince(int64_t tsExclusive, size_t maxCount = 4096) const; |
| | | |
| | | // è¯»ï¼æåºé´ [from, to]ï¼å
å«è¾¹çï¼ |
| | | std::vector<Sample> getRange(int64_t from_ts, int64_t to_ts, size_t maxCount = 4096) const; |
| | | |
| | | // æ¥è¯¢ / ç»´æ¤ |
| | | size_t size() const; |
| | | bool empty() const; |
| | | int64_t latestTs() const; |
| | | void clear(); |
| | | |
| | | // é
ç½® |
| | | void setPolicy(const RetentionPolicy& p); |
| | | RetentionPolicy getPolicy() const; |
| | | |
| | | int64_t earliestTs() const; // æ æ°æ®æ¶è¿å 0 |
| | | |
| | | private: |
| | | void pruneUnlocked(int64_t ref_now_ms); // æçç¥æ¸
ç |
| | | size_t lowerBoundIndex(int64_t tsExclusive) const; // äºåï¼ç¬¬ä¸ä¸ª > tsExclusive |
| | | size_t lowerBoundInclusive(int64_t tsInclusive) const; // 第ä¸ä¸ª >= tsInclusive |
| | | size_t upperBoundInclusive(int64_t tsInclusive) const; // æåä¸ä¸ª <= tsInclusive çä¸ä¸ä¸ªä½ç½® |
| | | |
| | | mutable std::shared_mutex mtx_; |
| | | std::deque<Sample> data_; |
| | | RetentionPolicy policy_; |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "Collector.h" |
| | | #include <iostream> |
| | | #include <chrono> |
| | | |
| | | #include "../DAQConfig.h" |
| | | #include "../core/ConnEvents.h" |
| | | using namespace DAQEvt; |
| | | |
| | | // åè®®ç¼è§£ç |
| | | #include "../proto/Protocol.h" |
| | | #include "../proto/ProtocolCodec.h" |
| | | |
| | | using namespace Proto; |
| | | |
| | | Collector::Collector() {} |
| | | |
| | | void Collector::startLoop(uint32_t intervalMs) { |
| | | if (running.load()) return; |
| | | running.store(true); |
| | | worker = std::thread([this, intervalMs]() { |
| | | while (running.load()) { |
| | | this->poll(); |
| | | std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | void Collector::stopLoop() { |
| | | if (!running.load()) return; |
| | | running.store(false); |
| | | if (worker.joinable()) worker.join(); |
| | | } |
| | | |
| | | Collector::~Collector() { |
| | | stopLoop(); |
| | | disconnect(); |
| | | } |
| | | |
| | | std::vector<Collector::ClientSummary> Collector::getClientList() { |
| | | std::lock_guard<std::mutex> lk(mClients); |
| | | std::vector<ClientSummary> out; |
| | | out.reserve(clients.size()); |
| | | for (const auto& c : clients) { |
| | | out.push_back(ClientSummary{ c.ip, c.port, c.versionOk, c.sock }); |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | void Collector::createServer(uint16_t port) { |
| | | if (socketComm.createServerSocket(port)) { |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::ServerListening), |
| | | "Collector server listening on port " + std::to_string(port)); |
| | | onConnectionEstablished(); |
| | | } |
| | | } |
| | | |
| | | void Collector::disconnect() { |
| | | { |
| | | std::lock_guard<std::mutex> lk(mClients); |
| | | for (auto& c : clients) { |
| | | socketComm.closeClient(c.sock); |
| | | if (cbClientEvent) cbClientEvent(c.ip, c.port, /*connected*/false); |
| | | } |
| | | clients.clear(); |
| | | } |
| | | socketComm.closeSocket(); |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::ServerStopped), "Collector server stopped"); |
| | | onConnectionLost(); |
| | | } |
| | | |
| | | void Collector::poll() { |
| | | // 1) æ¥æ°å®¢æ·ç«¯ |
| | | while (true) { |
| | | SOCKET cs; std::string ip; uint16_t port; |
| | | if (!socketComm.acceptOne(cs, ip, port)) break; |
| | | |
| | | ClientInfo ci; |
| | | ci.sock = cs; ci.ip = ip; ci.port = port; |
| | | ci.tsConnected = std::chrono::steady_clock::now(); |
| | | |
| | | { |
| | | std::lock_guard<std::mutex> lk(mClients); |
| | | clients.push_back(ci); |
| | | } |
| | | |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::ClientAccepted), |
| | | "Client connected: " + ip + ":" + std::to_string(port)); |
| | | if (cbClientEvent) cbClientEvent(ip, port, /*connected*/true); |
| | | } |
| | | |
| | | // 2) 轮询å客æ·ç«¯ |
| | | auto now = std::chrono::steady_clock::now(); |
| | | std::lock_guard<std::mutex> lk(mClients); |
| | | for (size_t i = 0; i < clients.size(); ) { |
| | | auto& c = clients[i]; |
| | | |
| | | // 2a) çæ¬æ¡æè¶
æ¶ |
| | | if (!c.versionOk) { |
| | | auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - c.tsConnected).count(); |
| | | if (elapsed >= DAQCfg::KickIfNoVersionSec) { |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::VersionTimeoutKick), |
| | | "Kick client (no version within 5s): " + c.ip + ":" + std::to_string(c.port)); |
| | | socketComm.closeClient(c.sock); |
| | | if (cbClientEvent) cbClientEvent(c.ip, c.port, /*connected*/false); |
| | | clients.erase(clients.begin() + i); |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | // 2b) æ¶æ°æ® |
| | | std::vector<uint8_t> buf; |
| | | bool peerClosed = false; |
| | | if (socketComm.recvFrom(c.sock, buf, peerClosed)) { |
| | | if (!buf.empty()) { |
| | | if (rawDumpEnabled && cbRaw) cbRaw(buf); |
| | | |
| | | // 帧ç»è£
|
| | | c.fr.push(buf); |
| | | std::vector<uint8_t> frame; |
| | | while (c.fr.nextFrame(frame)) { |
| | | if (rawDumpEnabled && cbRaw) cbRaw(frame); |
| | | handleClientData(c, frame); |
| | | } |
| | | } |
| | | } |
| | | else if (peerClosed) { |
| | | // å¯¹ç«¯ä¸»å¨æå¼ |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::ClientDisconnected), |
| | | "Client disconnected: " + c.ip + ":" + std::to_string(c.port)); |
| | | socketComm.closeClient(c.sock); |
| | | if (cbClientEvent) cbClientEvent(c.ip, c.port, /*connected*/false); |
| | | clients.erase(clients.begin() + i); |
| | | continue; |
| | | } |
| | | |
| | | ++i; |
| | | } |
| | | } |
| | | |
| | | void Collector::sendSampleData(double sample) { |
| | | (void)sample; |
| | | #ifdef _DEBUG |
| | | if (cbStatus) cbStatus(0, "sendSampleData() no-op."); |
| | | #endif |
| | | } |
| | | |
| | | void Collector::sendWindowData(const std::vector<std::string>& fields) { |
| | | (void)fields; |
| | | #ifdef _DEBUG |
| | | if (cbStatus) cbStatus(0, "sendWindowData() no-op."); |
| | | #endif |
| | | } |
| | | |
| | | void Collector::onConnectionEstablished() { |
| | | std::cout << "[Collector] ready.\n"; |
| | | } |
| | | void Collector::onConnectionLost() { |
| | | std::cout << "[Collector] stopped.\n"; |
| | | } |
| | | |
| | | // å
¼å®¹æ§é¨ç¦å½æ° |
| | | bool Collector::isVersionRequest(const std::vector<uint8_t>& data) const { |
| | | if (data.size() < 4 + 4 + 2 + 2 + 1) return false; |
| | | if (!(data[0] == 0x11 && data[1] == 0x88 && data[2] == 0x11 && data[3] == 0x88)) return false; |
| | | size_t cmdPos = 4 + 4 + 2; |
| | | uint16_t cmd = (uint16_t(data[cmdPos]) << 8) | data[cmdPos + 1]; |
| | | return (cmd == CMD_REQ_VERSION); |
| | | } |
| | | |
| | | // ========== BufferRegistry ֱͨ ========== |
| | | BufferManager& Collector::registryAddMachine(uint32_t machineId, const std::string& name, |
| | | const RetentionPolicy& defPolicy) { |
| | | return registry_.getOrCreate(machineId, name, defPolicy); |
| | | } |
| | | BufferManager* Collector::registryFind(uint32_t machineId) { return registry_.find(machineId); } |
| | | const BufferManager* Collector::registryFind(uint32_t machineId) const { return registry_.find(machineId); } |
| | | std::vector<uint32_t> Collector::registryListMachines() const { return registry_.listManagers(); } |
| | | |
| | | void Collector::buffersPush(uint32_t machineId, uint32_t channelId, int64_t ts_ms, double v) { |
| | | auto& bm = registry_.getOrCreate(machineId, "Machine-" + std::to_string(machineId)); |
| | | bm.push(channelId, ts_ms, v); // æª start() æ¶å°è¢«å
é¨å¿½ç¥ |
| | | } |
| | | |
| | | std::vector<Sample> Collector::buffersGetSince(uint32_t machineId, uint32_t channelId, |
| | | int64_t tsExclusive, size_t maxCount) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return {}; |
| | | return bm->getSince(channelId, tsExclusive, maxCount); |
| | | } |
| | | std::vector<Sample> Collector::buffersGetRange(uint32_t machineId, uint32_t channelId, |
| | | int64_t from_ts, int64_t to_ts, size_t maxCount) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return {}; |
| | | return bm->getRange(channelId, from_ts, to_ts, maxCount); |
| | | } |
| | | |
| | | void Collector::buffersStart(uint32_t machineId) { |
| | | auto& bm = registry_.getOrCreate(machineId, "Machine-" + std::to_string(machineId)); |
| | | bm.start(); // æ¸
空 + å
许å |
| | | } |
| | | void Collector::buffersStop(uint32_t machineId) { |
| | | if (auto* bm = registry_.find(machineId)) bm->stop(); |
| | | } |
| | | void Collector::buffersClear(uint32_t machineId) { |
| | | if (auto* bm = registry_.find(machineId)) bm->clearAll(); |
| | | } |
| | | bool Collector::buffersIsRunning(uint32_t machineId) const { |
| | | auto* bm = registry_.find(machineId); |
| | | return bm ? bm->isRunning() : false; |
| | | } |
| | | |
| | | void Collector::buffersSetDefaultPolicy(uint32_t machineId, const RetentionPolicy& p, bool applyExisting) { |
| | | auto& bm = registry_.getOrCreate(machineId, "Machine-" + std::to_string(machineId)); |
| | | bm.setDefaultPolicy(p, applyExisting); |
| | | } |
| | | void Collector::buffersSetPolicy(uint32_t machineId, uint32_t channelId, const RetentionPolicy& p) { |
| | | auto& bm = registry_.getOrCreate(machineId, "Machine-" + std::to_string(machineId)); |
| | | bm.setPolicy(channelId, p); |
| | | } |
| | | void Collector::buffersSetChannelName(uint32_t machineId, uint32_t channelId, const std::string& name) { |
| | | auto& bm = registry_.getOrCreate(machineId, "Machine-" + std::to_string(machineId)); |
| | | bm.setChannelName(channelId, name); |
| | | } |
| | | std::string Collector::buffersGetChannelName(uint32_t machineId, uint32_t channelId) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return {}; |
| | | return bm->getChannelName(channelId); |
| | | } |
| | | std::vector<BufferManager::ChannelInfo> Collector::buffersListChannelInfos(uint32_t machineId) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return {}; |
| | | return bm->listChannelInfos(); |
| | | } |
| | | std::vector<BufferManager::ChannelStat> Collector::buffersListChannelStats(uint32_t machineId) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return {}; |
| | | return bm->listChannelStats(); |
| | | } |
| | | BufferManager::ChannelStat Collector::buffersGetChannelStat(uint32_t machineId, uint32_t channelId) const { |
| | | auto* bm = registry_.find(machineId); |
| | | if (!bm) return BufferManager::ChannelStat{ channelId, 0, 0, 0 }; |
| | | return bm->getChannelStat(channelId); |
| | | } |
| | | |
| | | // ====== æ¹æ¬¡ç®¡ç ====== |
| | | // æ°å®ç°ï¼æ ¹æ® expectedDurationMs è®¡ç® expectedEndTs |
| | | void Collector::batchStart(uint32_t machineId, |
| | | const std::string& batchId, |
| | | uint64_t expectedDurationMs) |
| | | { |
| | | const uint64_t startTs = nowMs(); |
| | | const uint64_t expectedEndTs = (expectedDurationMs > 0) ? (startTs + expectedDurationMs) : 0; |
| | | |
| | | { |
| | | std::lock_guard<std::mutex> lk(mBatches); |
| | | auto& br = batches_[machineId]; |
| | | br.state = BatchState::Active; |
| | | br.activeBatchId = batchId; |
| | | br.activeStartTs = startTs; |
| | | br.expectedEndTs = expectedEndTs; |
| | | } |
| | | |
| | | // æ¹æ¬¡å¼å§ï¼æ¸
空并å¼å§éé |
| | | buffersStart(machineId); |
| | | |
| | | if (cbStatus) cbStatus(0, "batchStart: machine " + std::to_string(machineId) + |
| | | " batch=" + batchId + |
| | | " durMs=" + std::to_string(expectedDurationMs)); |
| | | } |
| | | |
| | | // å
¼å®¹æ§ç¾åï¼å¿½ç¥ startTsï¼æ expectedEndTs å½âæ¶é¿â |
| | | void Collector::batchStart(uint32_t machineId, |
| | | const std::string& batchId, |
| | | uint64_t /*startTs_ignored*/, |
| | | uint64_t expectedEndTs_orDuration) |
| | | { |
| | | // è¥è°ç¨æ¹è¯¯ä¼ äºç»å¯¹çâç»ææ¶é´æ³âï¼è¿éä¼è¢«å½ä½âæ¶é¿âï¼ |
| | | // å¦éä¸¥æ ¼åºåï¼ä½ ä¹å¯ä»¥å ä¸ä¸ªéå¼å¤æï¼æ¯å¦å¤§äº 10^12 认为æ¯ç»å¯¹æ¶é´æ³ï¼ |
| | | // ç¶å转æ¢ï¼duration = max(0, endTs - now) |
| | | |
| | | uint64_t durationMs = expectedEndTs_orDuration; |
| | | |
| | | // å¯éï¼å个ç®åçâåç»å¯¹æ¶é´æ³âç夿并èªå¨è½¬ä¸ºæ¶é¿ |
| | | // ä»¥æ¯«ç§æ¶é´æ³éå¼ä¸¾ä¾ï¼~2001-09-09ï¼ï¼1e12 |
| | | if (expectedEndTs_orDuration > 1000000000000ULL) { |
| | | uint64_t now = nowMs(); |
| | | if (expectedEndTs_orDuration > now) |
| | | durationMs = expectedEndTs_orDuration - now; |
| | | else |
| | | durationMs = 0; // å·²è¿æï¼å½æªç¥å¤ç |
| | | } |
| | | |
| | | batchStart(machineId, batchId, durationMs); |
| | | } |
| | | |
| | | void Collector::batchStop(uint32_t machineId, uint64_t /*endTs*/) { |
| | | { |
| | | std::lock_guard<std::mutex> lk(mBatches); |
| | | auto it = batches_.find(machineId); |
| | | if (it != batches_.end()) { |
| | | it->second.state = BatchState::Idle; |
| | | it->second.activeBatchId.clear(); |
| | | it->second.activeStartTs = 0; |
| | | it->second.expectedEndTs = 0; |
| | | } |
| | | else { |
| | | batches_[machineId] = BatchRec{}; // çæä¸æ¡ Idle |
| | | } |
| | | } |
| | | |
| | | // 忢ééï¼ä½ä¸æ¸
æ°æ® |
| | | buffersStop(machineId); |
| | | |
| | | if (cbStatus) cbStatus(0, "batchStop: machine " + std::to_string(machineId)); |
| | | } |
| | | |
| | | Collector::BatchRec Collector::getBatch(uint32_t machineId) const { |
| | | std::lock_guard<std::mutex> lk(mBatches); |
| | | auto it = batches_.find(machineId); |
| | | if (it != batches_.end()) return it->second; |
| | | return BatchRec{}; // é»è®¤ Idle |
| | | } |
| | | |
| | | // ========== ä¸å¡åå ========== |
| | | void Collector::handleClientData(ClientInfo& c, const std::vector<uint8_t>& data) { |
| | | // çæ¬æ ¡éª |
| | | if (!c.versionOk) { |
| | | ReqVersion vreq{}; |
| | | if (decodeRequestVersion(data, vreq)) { |
| | | c.versionOk = true; |
| | | if (cbStatus) cbStatus(static_cast<int>(DAQEvt::ConnCode::VersionOk), |
| | | "Client " + c.ip + ":" + std::to_string(c.port) + " version OK"); |
| | | |
| | | RspVersion vrst; |
| | | vrst.dataId = vreq.dataId; // åæ¾ |
| | | vrst.version = DAQCfg::Version; // éä¸é
ç½® |
| | | auto rsp = encodeResponseVersion(vrst); |
| | | socketComm.sendTo(c.sock, rsp); |
| | | } |
| | | return; // æªéè¿çæ¬æ ¡éªï¼å
¶å®å¿½ç¥ |
| | | } |
| | | |
| | | // éè¿çæ¬æ ¡éªåï¼æ cmd åå |
| | | const uint16_t cmd = peek_cmd(data); |
| | | |
| | | // 0x0101 ââ åééå¢éæå |
| | | if (cmd == CMD_REQ_SINCE) { |
| | | ReqSince req; |
| | | if (!decodeRequestSince(data, req)) return; |
| | | |
| | | auto vec = buffersGetSince(req.machineId, req.channelId, |
| | | static_cast<int64_t>(req.sinceTsExclusive), req.maxCount); |
| | | |
| | | uint64_t lastTsSent = req.sinceTsExclusive; |
| | | if (!vec.empty()) lastTsSent = static_cast<uint64_t>(vec.back().ts_ms); |
| | | |
| | | auto stat = buffersGetChannelStat(req.machineId, req.channelId); |
| | | uint8_t more = (stat.latestTs > static_cast<int64_t>(lastTsSent)) ? 1 : 0; |
| | | |
| | | RspSince rsp; |
| | | rsp.dataId = req.dataId; // åæ¾ |
| | | rsp.machineId = req.machineId; |
| | | rsp.channelId = req.channelId; |
| | | rsp.lastTsSent = lastTsSent; |
| | | rsp.more = more; |
| | | rsp.samples.reserve(vec.size()); |
| | | for (auto& s : vec) rsp.samples.push_back({ static_cast<uint64_t>(s.ts_ms), s.value }); |
| | | |
| | | auto pkt = encodeResponseSince(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // 0x0103 ââ ç»è®¡/ééå表 |
| | | if (cmd == CMD_REQ_STATS) { |
| | | ReqStats req; |
| | | if (!decodeRequestStats(data, req)) return; |
| | | |
| | | auto* bm = registry_.find(req.machineId); |
| | | if (!bm) { |
| | | // 示ä¾ï¼å¯åé误帧 |
| | | // sendErrorTo(c, req.dataId, CMD_REQ_STATS, req.machineId, ErrCode::NoActiveBatch, "machine not found"); |
| | | return; |
| | | } |
| | | |
| | | RspStats rsp; |
| | | rsp.dataId = req.dataId; |
| | | rsp.machineId = req.machineId; |
| | | |
| | | auto stats = bm->listChannelStats(); |
| | | rsp.channels.reserve(stats.size()); |
| | | for (auto& s : stats) { |
| | | ChannelStatInfo ci; |
| | | ci.channelId = s.id; |
| | | ci.earliestTs = static_cast<uint64_t>(s.earliestTs); |
| | | ci.latestTs = static_cast<uint64_t>(s.latestTs); |
| | | ci.size = static_cast<uint32_t>(s.size); |
| | | ci.name = bm->getChannelName(s.id); // UTF-8 |
| | | rsp.channels.push_back(std::move(ci)); |
| | | } |
| | | |
| | | auto pkt = encodeResponseStats(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // 0x0104 ââ æºå°å表 |
| | | if (cmd == CMD_REQ_MACHINES) { |
| | | ReqMachines req; |
| | | if (!decodeRequestMachines(data, req)) return; |
| | | |
| | | RspMachines rsp; |
| | | rsp.dataId = req.dataId; |
| | | |
| | | auto mids = registry_.listManagers(); |
| | | rsp.machines.reserve(mids.size()); |
| | | for (auto id : mids) { |
| | | auto* bm = registry_.find(id); |
| | | if (!bm) continue; |
| | | rsp.machines.push_back(MachineInfo{ id, bm->name() }); |
| | | } |
| | | |
| | | auto pkt = encodeResponseMachines(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // 0x0105 ââ æ´æºå¤ééå¢éæå |
| | | if (cmd == CMD_REQ_SINCE_ALL) { |
| | | ReqSinceAll req; |
| | | if (!decodeRequestSinceAll(data, req)) return; |
| | | |
| | | RspSinceAll rsp; |
| | | rsp.dataId = req.dataId; // åæ¾ |
| | | rsp.machineId = req.machineId; |
| | | rsp.moreAny = 0; |
| | | |
| | | auto* bm = registry_.find(req.machineId); |
| | | if (!bm) { |
| | | auto pkt = encodeResponseSinceAll(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // é¿å
è¶
è¿ 2 åèé¿åº¦ï¼æ£æ ~60KB |
| | | constexpr size_t kMaxBody = 60 * 1024; |
| | | |
| | | rsp.blocks.clear(); |
| | | auto stats = bm->listChannelStats(); |
| | | for (auto& s : stats) { |
| | | auto vec = bm->getSince(s.id, static_cast<int64_t>(req.sinceTsExclusive), req.maxPerChannel); |
| | | if (vec.empty()) continue; |
| | | |
| | | ChannelBlock blk; |
| | | blk.channelId = s.id; |
| | | blk.lastTsSent = static_cast<uint64_t>(vec.back().ts_ms); |
| | | |
| | | auto st = bm->getChannelStat(s.id); |
| | | blk.more = (st.latestTs > static_cast<int64_t>(blk.lastTsSent)) ? 1 : 0; |
| | | |
| | | blk.samples.reserve(vec.size()); |
| | | for (auto& sm : vec) { |
| | | blk.samples.push_back({ static_cast<uint64_t>(sm.ts_ms), sm.value }); |
| | | } |
| | | |
| | | rsp.blocks.push_back(std::move(blk)); |
| | | auto tentative = encodeResponseSinceAll(rsp); |
| | | if (tentative.size() > (4 + 4 + 2) + kMaxBody + 1) { |
| | | // è¶
ä½ç§¯ï¼ææåä¸åæ¿åºæ¥ï¼å
ååé¢ç |
| | | auto last = std::move(rsp.blocks.back()); |
| | | rsp.blocks.pop_back(); |
| | | |
| | | auto pkt = encodeResponseSinceAll(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | |
| | | rsp.blocks.clear(); |
| | | rsp.blocks.push_back(std::move(last)); |
| | | } |
| | | } |
| | | |
| | | rsp.moreAny = 0; |
| | | for (const auto& b : rsp.blocks) { |
| | | if (b.more) { rsp.moreAny = 1; break; } |
| | | } |
| | | |
| | | auto pkt = encodeResponseSinceAll(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // 0x0120 ââ æ¹æ¬¡ä¿¡æ¯ |
| | | if (cmd == CMD_REQ_BATCH_INFO) { |
| | | ReqBatchInfo req; |
| | | if (!decodeRequestBatchInfo(data, req)) return; |
| | | |
| | | RspBatchInfo rsp; |
| | | rsp.dataId = req.dataId; |
| | | rsp.machineId = req.machineId; |
| | | |
| | | const auto br = getBatch(req.machineId); |
| | | rsp.state = br.state; |
| | | rsp.activeBatchId = br.activeBatchId; |
| | | rsp.activeStartTs = br.activeStartTs; |
| | | rsp.expectedEndTs = br.expectedEndTs; |
| | | |
| | | auto pkt = encodeResponseBatchInfo(rsp); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | return; |
| | | } |
| | | |
| | | // å
¶å®æä»¤ï¼æéæ©å± |
| | | } |
| | | |
| | | // ç»ä¸é误åå
|
| | | void Collector::sendErrorTo(ClientInfo& c, |
| | | uint32_t dataId, |
| | | uint16_t refCmd, |
| | | uint32_t machineId, |
| | | ErrCode code, |
| | | const std::string& message) |
| | | { |
| | | RspError er; |
| | | er.dataId = dataId; |
| | | er.refCmd = refCmd; |
| | | er.machineId = machineId; |
| | | er.code = code; |
| | | er.message = message; |
| | | |
| | | auto pkt = encodeResponseError(er); |
| | | socketComm.sendTo(c.sock, pkt); |
| | | } |
| | | |
| | | // å·¥å
·ï¼å½å epoch æ¯«ç§ |
| | | uint64_t Collector::nowMs() { |
| | | using namespace std::chrono; |
| | | return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #ifndef COLLECTOR_H |
| | | #define COLLECTOR_H |
| | | |
| | | #include "CommBase.h" |
| | | #include "../net/SocketComm.h" |
| | | |
| | | #include <functional> |
| | | #include <chrono> |
| | | #include <thread> |
| | | #include <atomic> |
| | | #include <mutex> |
| | | #include <vector> |
| | | #include <string> |
| | | #include <unordered_map> |
| | | |
| | | #include "../buffer/BufferRegistry.h" |
| | | #include "../net/FrameAssembler.h" |
| | | |
| | | // å议常é/ç»æï¼å¿
é¡»å
å«ï¼ä¾æ¬å¤´æä»¶ä½¿ç¨ Proto:: ç±»åï¼ |
| | | #include "../proto/Protocol.h" |
| | | |
| | | class Collector : public CommBase { |
| | | public: |
| | | Collector(); |
| | | ~Collector(); |
| | | |
| | | // ===== CommBase æ¥å£ ===== |
| | | void sendSampleData(double sample) override; |
| | | void sendWindowData(const std::vector<std::string>& dataFields) override; |
| | | |
| | | void connectServer(const std::string& /*ip*/, uint16_t /*port*/) override {} // éé端ä¸ä½ä¸ºå®¢æ·ç«¯ |
| | | void createServer(uint16_t port) override; |
| | | void disconnect() override; |
| | | |
| | | void onConnectionEstablished() override; |
| | | void onConnectionLost() override; |
| | | |
| | | // è¿æ¥/åå§æ°æ®åè°ï¼UIï¼ |
| | | void setConnectionStatusCallback(std::function<void(int, std::string)> cb) override { cbStatus = std::move(cb); } |
| | | void setRawDataCallback(std::function<void(const std::vector<uint8_t>&)> cb) override { cbRaw = std::move(cb); } |
| | | void setRawDumpEnabled(bool enabled) override { rawDumpEnabled = enabled; } |
| | | |
| | | // åå°è½®è¯¢ï¼ä¸é»å¡ UIï¼ |
| | | void startLoop(uint32_t intervalMs = 10); |
| | | void stopLoop(); |
| | | void poll(); |
| | | |
| | | // 客æ·ç«¯è¿å
¥/æå¼äºä»¶ |
| | | void setClientEventCallback(std::function<void(const std::string& ip, uint16_t port, bool connected)> cb) { |
| | | cbClientEvent = std::move(cb); |
| | | } |
| | | |
| | | // 客æ·ç«¯å¿«ç
§ |
| | | struct ClientSummary { |
| | | std::string ip; |
| | | uint16_t port = 0; |
| | | bool versionOk = false; |
| | | SOCKET sock = INVALID_SOCKET; |
| | | }; |
| | | std::vector<ClientSummary> getClientList(); |
| | | |
| | | // ===== ç¼å²/ééç¸å
³ ===== |
| | | void buffersSetChannelName(uint32_t machineId, uint32_t channelId, const std::string& name); |
| | | std::string buffersGetChannelName(uint32_t machineId, uint32_t channelId) const; |
| | | std::vector<BufferManager::ChannelInfo> buffersListChannelInfos(uint32_t machineId) const; |
| | | |
| | | BufferManager& registryAddMachine(uint32_t machineId, const std::string& name, |
| | | const RetentionPolicy& defPolicy = {}); |
| | | BufferManager* registryFind(uint32_t machineId); |
| | | const BufferManager* registryFind(uint32_t machineId) const; |
| | | std::vector<uint32_t> registryListMachines() const; |
| | | |
| | | void buffersPush(uint32_t machineId, uint32_t channelId, int64_t ts_ms, double v); |
| | | |
| | | std::vector<Sample> buffersGetSince(uint32_t machineId, uint32_t channelId, |
| | | int64_t tsExclusive, size_t maxCount = 4096) const; |
| | | std::vector<Sample> buffersGetRange(uint32_t machineId, uint32_t channelId, |
| | | int64_t from_ts, int64_t to_ts, size_t maxCount = 4096) const; |
| | | |
| | | void buffersStart(uint32_t machineId); // æ¸
空该æºåå²å¹¶å¼å§ |
| | | void buffersStop(uint32_t machineId); // æåï¼push 忽ç¥ï¼ |
| | | void buffersClear(uint32_t machineId); // æ¸
空åå²ï¼ä¸æ¹ running ç¶æ |
| | | bool buffersIsRunning(uint32_t machineId) const; |
| | | |
| | | void buffersSetDefaultPolicy(uint32_t machineId, const RetentionPolicy& p, bool applyExisting = true); |
| | | void buffersSetPolicy(uint32_t machineId, uint32_t channelId, const RetentionPolicy& p); |
| | | |
| | | std::vector<BufferManager::ChannelStat> buffersListChannelStats(uint32_t machineId) const; |
| | | BufferManager::ChannelStat buffersGetChannelStat(uint32_t machineId, uint32_t channelId) const; |
| | | |
| | | // ===== æ¹æ¬¡ç®¡çï¼æ°å¢ï¼ ===== |
| | | struct BatchRec { |
| | | Proto::BatchState state = Proto::BatchState::Idle; // Idle / Active |
| | | std::string activeBatchId; // Idle æ¶ä¸ºç©º |
| | | uint64_t activeStartTs = 0; // ms epoch |
| | | uint64_t expectedEndTs = 0; // 0: δ֪ |
| | | }; |
| | | |
| | | // æ°ï¼ä»
ä¼ âé¢è®¡æ¶é¿msâï¼0=æªç¥ï¼ï¼å¼å§æ¶é´å
é¨å nowMs() |
| | | void batchStart(uint32_t machineId, |
| | | const std::string& batchId, |
| | | uint64_t expectedDurationMs = 0); |
| | | |
| | | // ï¼å¯éå
¼å®¹ï¼æ§ç¾åä¿çï¼ä½æ 记为å¼ç¨ï¼å
é¨è½¬è°æ°ç¾å |
| | | void batchStart(uint32_t machineId, |
| | | const std::string& batchId, |
| | | uint64_t startTs /*ignored*/, |
| | | uint64_t expectedEndTs /*treated as duration or absolute?*/); |
| | | |
| | | // ç»æå½åæ¹æ¬¡ï¼ä¿ææ°æ®ï¼ç¶æè½¬ Idleï¼ |
| | | void batchStop(uint32_t machineId, |
| | | uint64_t endTs = 0); // å¤ç¨ |
| | | |
| | | // æ¥è¯¢è¯¥æºå½åæ¹æ¬¡ï¼è¥ä¸åå¨ï¼è¿å Idle 空记å½ï¼ |
| | | BatchRec getBatch(uint32_t machineId) const; |
| | | |
| | | private: |
| | | struct ClientInfo { |
| | | SOCKET sock = INVALID_SOCKET; |
| | | std::string ip; |
| | | uint16_t port = 0; |
| | | std::chrono::steady_clock::time_point tsConnected{}; |
| | | bool versionOk = false; |
| | | FrameAssembler fr; // æ¯ä¸ªå®¢æ·ç«¯ä¸ä¸ªå¸§ç»è£
å¨ |
| | | }; |
| | | |
| | | SocketComm socketComm; |
| | | std::vector<ClientInfo> clients; |
| | | |
| | | std::function<void(int, std::string)> cbStatus; |
| | | std::function<void(const std::vector<uint8_t>&)> cbRaw; |
| | | bool rawDumpEnabled = true; |
| | | |
| | | std::function<void(const std::string&, uint16_t, bool)> cbClientEvent; |
| | | |
| | | std::thread worker; |
| | | std::atomic<bool> running{ false }; |
| | | std::mutex mClients; // ä¿æ¤ clients |
| | | |
| | | BufferRegistry registry_; // ä¸ä¸ª Collector ç®¡æææºå° |
| | | |
| | | // æ¹æ¬¡ç¶æ |
| | | std::unordered_map<uint32_t, BatchRec> batches_; |
| | | mutable std::mutex mBatches; |
| | | |
| | | // å
é¨å½æ° |
| | | void handleClientData(ClientInfo& c, const std::vector<uint8_t>& data); |
| | | bool isVersionRequest(const std::vector<uint8_t>& data) const; |
| | | |
| | | // ç»ä¸é误åå
ï¼6 åæ°ï¼ |
| | | void sendErrorTo(ClientInfo& c, |
| | | uint32_t dataId, |
| | | uint16_t refCmd, |
| | | uint32_t machineId, |
| | | Proto::ErrCode code, |
| | | const std::string& message); |
| | | |
| | | // å·¥å
·ï¼å½å epoch æ¯«ç§ |
| | | static uint64_t nowMs(); |
| | | }; |
| | | |
| | | #endif // COLLECTOR_H |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #ifndef COMM_BASE_H |
| | | #define COMM_BASE_H |
| | | |
| | | #include <string> |
| | | #include <vector> |
| | | #include <functional> |
| | | |
| | | class CommBase { |
| | | public: |
| | | virtual void sendSampleData(double sample) = 0; |
| | | virtual void sendWindowData(const std::vector<std::string>& dataFields) = 0; |
| | | virtual void connectServer(const std::string& ip, uint16_t port) = 0; |
| | | virtual void createServer(uint16_t port) = 0; |
| | | virtual void disconnect() = 0; |
| | | |
| | | // è¿æ¥ç¶æåè° |
| | | virtual void onConnectionEstablished() = 0; |
| | | virtual void onConnectionLost() = 0; |
| | | virtual void setConnectionStatusCallback(std::function<void(int, std::string)> callback) = 0; |
| | | |
| | | // æ°å¢ï¼åå§æ°æ®ä¸æï¼æ¶å°çâåèæµâç´æ¥åè°ç»åºç¨å±ï¼ |
| | | virtual void setRawDataCallback(std::function<void(const std::vector<uint8_t>&)> callback) = 0; |
| | | |
| | | // æ°å¢ï¼å¼å
³ï¼é»è®¤ trueï¼ |
| | | virtual void setRawDumpEnabled(bool enabled) = 0; |
| | | }; |
| | | |
| | | #endif // COMM_BASE_H |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <string> |
| | | |
| | | namespace DAQEvt { |
| | | |
| | | // ç¨æä¸¾å®ä¹ï¼å¤é¨åè°ä»ä»¥ int ä¼ é |
| | | enum class ConnCode : int { |
| | | // Collectorï¼æå¡ç«¯ï¼ |
| | | ServerListening = 100, // createServer æå |
| | | ServerStopped = 101, // disconnect/close |
| | | ClientAccepted = 110, // æ°å®¢æ·ç«¯æ¥å
¥ |
| | | ClientDisconnected = 111, // 客æ·ç«¯ä¸»å¨æå¼ |
| | | VersionOk = 120, // 客æ·ç«¯çæ¬æ ¡éªéè¿ |
| | | VersionTimeoutKick = 121, // 5 ç§æªæ¡æè¢«è¸¢ |
| | | |
| | | // Displayï¼å®¢æ·ç«¯ï¼ |
| | | DisplayConnected = 200, // connectServer æåï¼å·²å»ºè¿ï¼ |
| | | DisplayDisconnected = 201, // disconnect/close |
| | | |
| | | // éç¨/é误 |
| | | SocketError = 900 |
| | | }; |
| | | |
| | | // å¯éï¼æ code 转æé»è®¤å符串ï¼å¤ç¨ï¼ |
| | | inline const char* ToString(ConnCode c) { |
| | | switch (c) { |
| | | case ConnCode::ServerListening: return "Server listening"; |
| | | case ConnCode::ServerStopped: return "Server stopped"; |
| | | case ConnCode::ClientAccepted: return "Client accepted"; |
| | | case ConnCode::ClientDisconnected: return "Client disconnected"; |
| | | case ConnCode::VersionOk: return "Version OK"; |
| | | case ConnCode::VersionTimeoutKick: return "Version timeout kick"; |
| | | case ConnCode::DisplayConnected: return "Display connected"; |
| | | case ConnCode::DisplayDisconnected: return "Display disconnected"; |
| | | case ConnCode::SocketError: return "Socket error"; |
| | | default: return "Unknown"; |
| | | } |
| | | } |
| | | |
| | | } // namespace DAQEvt |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // DataTypes.h |
| | | #pragma once |
| | | #include <cstdint> |
| | | |
| | | struct Sample { |
| | | int64_t ts_ms = 0; // æ¶é´æ³ï¼æ¯«ç§ |
| | | double value = 0.0; |
| | | }; |
| | | #pragma once |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "Display.h" |
| | | #include <iostream> |
| | | #include "../DAQConfig.h" |
| | | #include "../core/ConnEvents.h" |
| | | using namespace DAQEvt; |
| | | |
| | | // å
Œ
±å议头 |
| | | #include "../proto/Protocol.h" |
| | | #include "../proto/ProtocolCodec.h" |
| | | #include "../net/FrameAssembler.h" |
| | | |
| | | using namespace Proto; |
| | | |
| | | Display::Display() {} |
| | | Display::~Display() { |
| | | stopRecvLoop(); |
| | | disconnect(); |
| | | } |
| | | |
| | | void Display::connectServer(const std::string& ip, uint16_t port) { |
| | | if (socketComm.createClientSocket(ip, port)) { |
| | | if (cbStatus) cbStatus(static_cast<int>(ConnCode::DisplayConnected), "Display connected to server"); |
| | | onConnectionEstablished(); |
| | | |
| | | // è¿æ¥åç«å»åéçæ¬è¯·æ±ï¼0x0001ï¼ï¼å¸¦ dataId åæ¾ |
| | | ReqVersion vreq; |
| | | vreq.dataId = m_nextDataId++; |
| | | auto pkt = encodeRequestVersion(vreq); |
| | | socketComm.sendDataSingle(pkt); |
| | | |
| | | startRecvLoop(DAQCfg::RecvLoopIntervalMs); |
| | | } |
| | | } |
| | | |
| | | void Display::disconnect() { |
| | | stopRecvLoop(); |
| | | socketComm.closeSocket(); |
| | | if (cbStatus) cbStatus(static_cast<int>(ConnCode::DisplayDisconnected), "Display disconnected"); |
| | | onConnectionLost(); |
| | | } |
| | | |
| | | void Display::startRecvLoop(uint32_t intervalMs) { |
| | | if (recvRunning.load()) return; |
| | | recvRunning.store(true); |
| | | recvThread = std::thread([this, intervalMs]() { |
| | | std::vector<uint8_t> chunk; |
| | | std::vector<uint8_t> frame; |
| | | FrameAssembler fr; |
| | | |
| | | while (recvRunning.load()) { |
| | | chunk.clear(); |
| | | if (socketComm.recvSingle(chunk) && !chunk.empty()) { |
| | | if (rawDumpEnabled && cbRaw) cbRaw(chunk); |
| | | fr.push(chunk); |
| | | while (fr.nextFrame(frame)) { |
| | | if (rawDumpEnabled && cbRaw) cbRaw(frame); |
| | | handleRawData(frame); |
| | | } |
| | | } |
| | | std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | void Display::stopRecvLoop() { |
| | | if (!recvRunning.load()) return; |
| | | recvRunning.store(false); |
| | | if (recvThread.joinable()) recvThread.join(); |
| | | } |
| | | |
| | | void Display::sendSampleData(double) { /* 客æ·ç«¯è¿è¾¹æä¸å */ } |
| | | void Display::sendWindowData(const std::vector<std::string>&) { /* åä¸ */ } |
| | | |
| | | void Display::onConnectionEstablished() { std::cout << "[Display] connected\n"; } |
| | | void Display::onConnectionLost() { std::cout << "[Display] disconnected\n"; } |
| | | |
| | | // ââ ä½å±æ¥å£ï¼æ¾å¼ dataId ââ |
| | | |
| | | // åé 0x0101ï¼å¢éæåï¼â åçï¼ä¸å¸¦ batchIdï¼ |
| | | void Display::requestSince(uint32_t dataId, uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, uint16_t maxCount) { |
| | | // è°å°å¸¦ batchId çéè½½ï¼ä¼ 空串 => ä¸éå batchId |
| | | requestSince(dataId, machineId, channelId, sinceTsExclusive, std::string(), maxCount); |
| | | } |
| | | |
| | | // åé 0x0101ï¼å¢éæåï¼â â
æ°ï¼å¸¦ batchId |
| | | void Display::requestSince(uint32_t dataId, uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, const std::string& batchId, uint16_t maxCount) { |
| | | ReqSince req; |
| | | req.dataId = dataId; |
| | | req.machineId = machineId; |
| | | req.channelId = channelId; |
| | | req.sinceTsExclusive = sinceTsExclusive; |
| | | req.maxCount = maxCount; |
| | | if (!batchId.empty()) { |
| | | req.flags = SINCE_FLAG_HAS_BATCH; |
| | | req.batchId = batchId; |
| | | } |
| | | else { |
| | | req.flags = 0; |
| | | req.batchId.clear(); |
| | | } |
| | | auto pkt = encodeRequestSince(req); |
| | | socketComm.sendDataSingle(pkt); |
| | | } |
| | | |
| | | void Display::requestMachines(uint32_t dataId) { |
| | | ReqMachines req; req.dataId = dataId; |
| | | auto pkt = encodeRequestMachines(req); |
| | | socketComm.sendDataSingle(pkt); |
| | | } |
| | | |
| | | void Display::requestStats(uint32_t dataId, uint32_t machineId) { |
| | | ReqStats req; req.dataId = dataId; req.machineId = machineId; req.flags = 0; |
| | | auto pkt = encodeRequestStats(req); |
| | | socketComm.sendDataSingle(pkt); |
| | | } |
| | | |
| | | // æ´æºå¤ééå¢é â åçï¼ä¸å¸¦ batchIdï¼ |
| | | void Display::requestSinceAll(uint32_t dataId, uint32_t machineId, uint64_t sinceTsExclusive, |
| | | uint16_t maxPerChannel) { |
| | | // è°å°å¸¦ batchId çéè½½ï¼ä¼ 空串 |
| | | requestSinceAll(dataId, machineId, sinceTsExclusive, std::string(), maxPerChannel); |
| | | } |
| | | |
| | | // æ´æºå¤ééå¢é â â
æ°ï¼å¸¦ batchId |
| | | void Display::requestSinceAll(uint32_t dataId, uint32_t machineId, uint64_t sinceTsExclusive, |
| | | const std::string& batchId, uint16_t maxPerChannel) { |
| | | ReqSinceAll req; |
| | | req.dataId = dataId; |
| | | req.machineId = machineId; |
| | | req.sinceTsExclusive = sinceTsExclusive; |
| | | req.maxPerChannel = maxPerChannel; |
| | | if (!batchId.empty()) { |
| | | req.flags = SINCE_FLAG_HAS_BATCH; |
| | | req.batchId = batchId; |
| | | } |
| | | else { |
| | | req.flags = 0; |
| | | req.batchId.clear(); |
| | | } |
| | | socketComm.sendDataSingle(encodeRequestSinceAll(req)); |
| | | } |
| | | |
| | | // ââ æ°å¢ï¼æ¹æ¬¡ä¿¡æ¯æå ââ |
| | | // æ¾å¼ dataId |
| | | void Display::requestBatchInfo(uint32_t dataId, uint32_t machineId) { |
| | | ReqBatchInfo req; req.dataId = dataId; req.machineId = machineId; |
| | | socketComm.sendDataSingle(encodeRequestBatchInfo(req)); |
| | | } |
| | | // 便æ·ï¼èªå¨ dataId |
| | | void Display::requestBatchInfo(uint32_t machineId) { |
| | | requestBatchInfo(m_nextDataId++, machineId); |
| | | } |
| | | |
| | | // ââ ä¾¿æ·æ¥å£ï¼èªå¨åé
dataId ââ |
| | | // ä¸ç»åªæ¯ç®åå°å¨å
é¨è°ç¨ä¸è¿°æ¾å¼ç |
| | | |
| | | void Display::requestMachines() { |
| | | requestMachines(m_nextDataId++); |
| | | } |
| | | |
| | | void Display::requestStats(uint32_t machineId) { |
| | | requestStats(m_nextDataId++, machineId); |
| | | } |
| | | |
| | | void Display::requestSince(uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, uint16_t maxCount) { |
| | | requestSince(m_nextDataId++, machineId, channelId, sinceTsExclusive, maxCount); |
| | | } |
| | | |
| | | void Display::requestSince(uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, const std::string& batchId, uint16_t maxCount) { |
| | | requestSince(m_nextDataId++, machineId, channelId, sinceTsExclusive, batchId, maxCount); |
| | | } |
| | | |
| | | void Display::requestSinceAll(uint32_t machineId, uint64_t sinceTsExclusive, uint16_t maxPerChannel) { |
| | | requestSinceAll(m_nextDataId++, machineId, sinceTsExclusive, maxPerChannel); |
| | | } |
| | | |
| | | void Display::requestSinceAll(uint32_t machineId, uint64_t sinceTsExclusive, |
| | | const std::string& batchId, uint16_t maxPerChannel) { |
| | | requestSinceAll(m_nextDataId++, machineId, sinceTsExclusive, batchId, maxPerChannel); |
| | | } |
| | | |
| | | // æ¶å
ååï¼å¨æ¥æ¶çº¿ç¨é被è°ç¨ï¼ |
| | | void Display::handleRawData(const std::vector<uint8_t>& rawData) { |
| | | // F001 çæ¬ååº |
| | | { |
| | | RspVersion vrsp; |
| | | if (decodeResponseVersion(rawData, vrsp)) { |
| | | if (cbStatus) cbStatus(static_cast<int>(ConnCode::VersionOk), |
| | | std::string("Server version: ") + vrsp.version); |
| | | // m_versionOk = true; |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // F101 ââ since æåååº |
| | | { |
| | | RspSince rsp; |
| | | if (decodeResponseSince(rawData, rsp)) { |
| | | if (cbSamples) cbSamples(rsp.machineId, rsp.channelId, rsp.lastTsSent, rsp.more, rsp.samples); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // F103 ââ ç»è®¡/éé |
| | | { |
| | | RspStats st; |
| | | if (decodeResponseStats(rawData, st)) { |
| | | if (cbStats) cbStats(st.machineId, st.channels); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // F104 ââ æºå°å表 |
| | | { |
| | | RspMachines ms; |
| | | if (decodeResponseMachines(rawData, ms)) { |
| | | if (cbMachines) cbMachines(ms.machines); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // F105 ââ å¤ééå¢é |
| | | { |
| | | RspSinceAll ra; |
| | | if (decodeResponseSinceAll(rawData, ra)) { |
| | | if (cbSamplesMulti) cbSamplesMulti(ra.machineId, ra.moreAny, ra.blocks); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // â
æ°å¢ï¼F120 ââ æ¹æ¬¡ä¿¡æ¯ |
| | | { |
| | | RspBatchInfo bi; |
| | | if (decodeResponseBatchInfo(rawData, bi)) { |
| | | if (cbBatchInfo) cbBatchInfo(bi); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // â
æ°å¢ï¼E100 ââ ç»ä¸é误ï¼èªæï¼ |
| | | { |
| | | RspError er; |
| | | if (decodeResponseError(rawData, er)) { |
| | | if (cbStatus) { |
| | | std::string s = "ERR ref=0x" + [](uint16_t x) { |
| | | char buf[8]; std::snprintf(buf, sizeof(buf), "%04X", (unsigned)x); return std::string(buf); |
| | | }(er.refCmd) + |
| | | " mid=" + std::to_string(er.machineId) + |
| | | " code=" + std::to_string((unsigned)er.code) + |
| | | " msg=" + er.message; |
| | | cbStatus(static_cast<int>(ConnCode::SocketError), s); |
| | | } |
| | | // éè¯¯èªæï¼NoActive / Mismatch â æä¸æ¬¡ BatchInfo |
| | | if (er.code == ErrCode::NoActiveBatch || er.code == ErrCode::BatchMismatch) { |
| | | requestBatchInfo(er.machineId); |
| | | } |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // å
¶å®ç±»åï¼å°æ¥æ©å±ï¼â¦â¦ |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #ifndef DISPLAY_H |
| | | #define DISPLAY_H |
| | | |
| | | #include "CommBase.h" |
| | | #include "../net/SocketComm.h" |
| | | #include <functional> |
| | | #include <thread> |
| | | #include <atomic> |
| | | #include "../proto/Protocol.h" |
| | | #include "../proto/ProtocolCodec.h" |
| | | |
| | | // åè°ï¼æ¶å°æ ·æ¬ç䏿ï¼UI ç¨å®ç»å¾/忬å°ï¼ |
| | | using SamplesCallback = std::function<void(uint32_t machineId, uint32_t channelId, |
| | | uint64_t lastTsSent, uint8_t more, |
| | | const std::vector<Proto::SamplePair>& samples)>; |
| | | using SamplesMultiCallback = std::function<void( |
| | | uint32_t machineId, uint8_t moreAny, |
| | | const std::vector<Proto::ChannelBlock>& blocks)>; |
| | | using MachinesCallback = std::function<void(const std::vector<Proto::MachineInfo>& machines)>; |
| | | using StatsCallback = std::function<void(uint32_t machineId, const std::vector<Proto::ChannelStatInfo>& channels)>; |
| | | |
| | | // â
æ°å¢ï¼æ¹æ¬¡ä¿¡æ¯åè° |
| | | using BatchInfoCallback = std::function<void(const Proto::RspBatchInfo&)>; |
| | | |
| | | class Display : public CommBase { |
| | | public: |
| | | Display(); |
| | | ~Display(); |
| | | |
| | | void sendSampleData(double sample) override; |
| | | void sendWindowData(const std::vector<std::string>& dataFields) override; |
| | | |
| | | void connectServer(const std::string& ip, uint16_t port) override; |
| | | void createServer(uint16_t /*port*/) override {} |
| | | void disconnect() override; |
| | | |
| | | void onConnectionEstablished() override; |
| | | void onConnectionLost() override; |
| | | |
| | | void handleRawData(const std::vector<uint8_t>& rawData); |
| | | |
| | | void setConnectionStatusCallback(std::function<void(int, std::string)> cb) override { cbStatus = std::move(cb); } |
| | | void setRawDataCallback(std::function<void(const std::vector<uint8_t>&)> cb) override { cbRaw = std::move(cb); } |
| | | void setRawDumpEnabled(bool enabled) override { rawDumpEnabled = enabled; } |
| | | |
| | | void startRecvLoop(uint32_t intervalMs = 10); |
| | | void stopRecvLoop(); |
| | | |
| | | void setSamplesCallback(SamplesCallback cb) { cbSamples = std::move(cb); } |
| | | void setSamplesMultiCallback(SamplesMultiCallback cb) { cbSamplesMulti = std::move(cb); } |
| | | void setMachinesCallback(MachinesCallback cb) { cbMachines = std::move(cb); } |
| | | void setStatsCallback(StatsCallback cb) { cbStats = std::move(cb); } |
| | | void setBatchInfoCallback(BatchInfoCallback cb) { cbBatchInfo = std::move(cb); } // â
æ°å¢ |
| | | |
| | | // ââ åæâéæ¾å¼ dataIdâçä½å±æ¥å£ï¼ä¿ç以å
¼å®¹ï¼ââ |
| | | void requestMachines(uint32_t dataId); |
| | | void requestStats(uint32_t dataId, uint32_t machineId); |
| | | void requestSince(uint32_t dataId, uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, uint16_t maxCount = 1024); |
| | | // â
æ°å¢ï¼å¸¦ batchId çæ¾å¼ dataId ç |
| | | void requestSince(uint32_t dataId, uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, const std::string& batchId, uint16_t maxCount = 1024); |
| | | |
| | | // 便æ·ï¼æ´æºå¤ééå¢éï¼æ¾å¼ dataIdï¼ |
| | | void requestSinceAll(uint32_t dataId, uint32_t machineId, uint64_t sinceTsExclusive, |
| | | uint16_t maxPerChannel = 1024); |
| | | // â
æ°å¢ï¼å¸¦ batchId çæ¾å¼ dataId ç |
| | | void requestSinceAll(uint32_t dataId, uint32_t machineId, uint64_t sinceTsExclusive, |
| | | const std::string& batchId, uint16_t maxPerChannel = 1024); |
| | | |
| | | // ââ æ°å¢ï¼æ¹æ¬¡ä¿¡æ¯æåï¼æ¾å¼/便æ·ï¼ââ |
| | | void requestBatchInfo(uint32_t dataId, uint32_t machineId); // æ¾å¼ dataId |
| | | void requestBatchInfo(uint32_t machineId); // 便æ·ï¼èªå¨ m_nextDataId++ |
| | | |
| | | // ââ æ°å¢ï¼ä¾¿æ·é«å±æ¥å£ï¼èªå¨åé
dataIdï¼ââ |
| | | void requestMachines(); // èªå¨ m_nextDataId++ |
| | | void requestStats(uint32_t machineId); |
| | | void requestSince(uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, uint16_t maxCount = 1024); |
| | | // â
æ°å¢ï¼ä¾¿æ·å¸¦ batchId |
| | | void requestSince(uint32_t machineId, uint32_t channelId, |
| | | uint64_t sinceTsExclusive, const std::string& batchId, uint16_t maxCount = 1024); |
| | | |
| | | // 便æ·ï¼æ´æºå¤ééå¢é |
| | | void requestSinceAll(uint32_t machineId, uint64_t sinceTsExclusive, |
| | | uint16_t maxPerChannel = 1024); |
| | | // â
æ°å¢ï¼ä¾¿æ·å¸¦ batchId |
| | | void requestSinceAll(uint32_t machineId, uint64_t sinceTsExclusive, |
| | | const std::string& batchId, uint16_t maxPerChannel = 1024); |
| | | |
| | | private: |
| | | SocketComm socketComm; |
| | | std::function<void(int, std::string)> cbStatus; |
| | | |
| | | // åå§æ°æ®åè° & å¼å
³ |
| | | std::function<void(const std::vector<uint8_t>&)> cbRaw; |
| | | bool rawDumpEnabled = true; |
| | | |
| | | std::thread recvThread; |
| | | std::atomic<bool> recvRunning{ false }; |
| | | SamplesCallback cbSamples; |
| | | SamplesMultiCallback cbSamplesMulti; |
| | | MachinesCallback cbMachines; |
| | | StatsCallback cbStats; |
| | | BatchInfoCallback cbBatchInfo; // â
æ°å¢ |
| | | |
| | | // dataId éå¢ï¼ç¨äºé
对请æ±/ååº |
| | | uint32_t m_nextDataId = 1; |
| | | bool m_versionOk = false; |
| | | }; |
| | | |
| | | #endif // DISPLAY_H |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <vector> |
| | | #include <cstdint> |
| | | #include <algorithm> |
| | | |
| | | class FrameAssembler { |
| | | public: |
| | | // 追å ä¸ååå§åè |
| | | void push(const std::vector<uint8_t>& chunk) { |
| | | buf_.insert(buf_.end(), chunk.begin(), chunk.end()); |
| | | } |
| | | void push(const uint8_t* p, size_t n) { |
| | | buf_.insert(buf_.end(), p, p + n); |
| | | } |
| | | |
| | | // æåä¸ä¸å¸§ï¼è¿å true 表示 out æ¿å°äºä¸å¸§å®æ´æ°æ® |
| | | bool nextFrame(std::vector<uint8_t>& out) { |
| | | const uint8_t HEAD[4] = { 0x11,0x88,0x11,0x88 }; |
| | | const uint8_t TAIL = 0x88; |
| | | for (;;) { |
| | | // éè¦è³å° 4B 头 + 4B dataId + 2B len + 1B å°¾ = 11B |
| | | if (buf_.size() < 11) return false; |
| | | |
| | | // æ¾å¤´åæ¥ |
| | | size_t i = 0; |
| | | while (i + 4 <= buf_.size() && !std::equal(HEAD, HEAD + 4, buf_.begin() + i)) ++i; |
| | | if (i + 4 > buf_.size()) { // 没æ¾å°å¤´ï¼æ¸
空 |
| | | buf_.clear(); |
| | | return false; |
| | | } |
| | | if (i > 0) buf_.erase(buf_.begin(), buf_.begin() + i); // 丢å¼å¤´ååªå£° |
| | | |
| | | if (buf_.size() < 11) return false; // è¿ä¸å¤æå°å¸§ |
| | | |
| | | // è¯»åæ£æé¿åº¦ï¼å¤§ç«¯ï¼ |
| | | uint16_t len = (uint16_t(buf_[8]) << 8) | buf_[9]; |
| | | size_t total = 4 + 4 + 2 + size_t(len) + 1; // æ´å¸§é¿åº¦ |
| | | if (buf_.size() < total) return false; // å帧ï¼ç䏿¬¡ |
| | | |
| | | // æ ¡éªå°¾ |
| | | if (buf_[total - 1] != TAIL) { |
| | | // å°¾ä¸å¯¹ï¼ä¸¢å¼ä¸ä¸ªåèï¼éæ°æ¾å¤´ï¼é¿å
æ»éï¼ |
| | | buf_.erase(buf_.begin()); |
| | | continue; |
| | | } |
| | | |
| | | // ååºå®æ´å¸§ |
| | | out.assign(buf_.begin(), buf_.begin() + total); |
| | | buf_.erase(buf_.begin(), buf_.begin() + total); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | void clear() { buf_.clear(); } |
| | | |
| | | private: |
| | | std::vector<uint8_t> buf_; |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "SocketComm.h" |
| | | |
| | | SocketComm::SocketComm() { |
| | | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { |
| | | std::cerr << "WSAStartup failed\n"; |
| | | } |
| | | } |
| | | SocketComm::~SocketComm() { |
| | | closeSocket(); |
| | | WSACleanup(); |
| | | } |
| | | |
| | | bool SocketComm::setNonBlocking(SOCKET s, bool nb) { |
| | | u_long mode = nb ? 1UL : 0UL; |
| | | return ioctlsocket(s, FIONBIO, &mode) == 0; |
| | | } |
| | | |
| | | bool SocketComm::createClientSocket(const std::string& serverIP, uint16_t serverPort) { |
| | | sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| | | if (sock == INVALID_SOCKET) return false; |
| | | |
| | | sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(serverPort); |
| | | if (InetPton(AF_INET, serverIP.c_str(), &addr.sin_addr) <= 0) return false; |
| | | |
| | | if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { |
| | | std::cerr << "connect failed: " << WSAGetLastError() << "\n"; |
| | | closesocket(sock); sock = INVALID_SOCKET; return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | bool SocketComm::createServerSocket(uint16_t port) { |
| | | listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| | | if (listenSock == INVALID_SOCKET) return false; |
| | | |
| | | // å¤ç¨å°å |
| | | BOOL yes = 1; setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)); |
| | | |
| | | sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); |
| | | if (bind(listenSock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) return false; |
| | | if (listen(listenSock, SOMAXCONN) == SOCKET_ERROR) return false; |
| | | |
| | | // éé»å¡çå¬ |
| | | setNonBlocking(listenSock, true); |
| | | std::cout << "Server listening on port " << port << "\n"; |
| | | return true; |
| | | } |
| | | |
| | | bool SocketComm::acceptOne(SOCKET& outClient, std::string& outIp, uint16_t& outPort) { |
| | | sockaddr_in caddr{}; int len = sizeof(caddr); |
| | | SOCKET cs = accept(listenSock, (sockaddr*)&caddr, &len); |
| | | if (cs == INVALID_SOCKET) { |
| | | int e = WSAGetLastError(); |
| | | if (e == WSAEWOULDBLOCK) return false; // å½åæ²¡ææ°è¿æ¥ |
| | | std::cerr << "accept error: " << e << "\n"; return false; |
| | | } |
| | | setNonBlocking(cs, true); |
| | | char ipbuf[INET_ADDRSTRLEN]{}; |
| | | InetNtop(AF_INET, &caddr.sin_addr, ipbuf, INET_ADDRSTRLEN); |
| | | outIp = ipbuf; outPort = ntohs(caddr.sin_port); |
| | | outClient = cs; |
| | | return true; |
| | | } |
| | | |
| | | bool SocketComm::recvFrom(SOCKET s, std::vector<uint8_t>& buffer, bool& peerClosed) { |
| | | peerClosed = false; |
| | | char tmp[4096]; |
| | | int r = recv(s, tmp, sizeof(tmp), 0); |
| | | if (r > 0) { |
| | | buffer.assign(tmp, tmp + r); |
| | | return true; |
| | | } |
| | | if (r == 0) { // 对端æ£å¸¸å
³é |
| | | peerClosed = true; |
| | | return false; |
| | | } |
| | | int e = WSAGetLastError(); |
| | | if (e == WSAEWOULDBLOCK) return false; // ææ æ°æ® |
| | | // å
¶å®é误ä¹è®¤ä¸ºè¿æ¥ä¸å¯ç¨äº |
| | | peerClosed = true; |
| | | return false; |
| | | } |
| | | |
| | | bool SocketComm::sendTo(SOCKET s, const std::vector<uint8_t>& data) { |
| | | int sent = send(s, reinterpret_cast<const char*>(data.data()), (int)data.size(), 0); |
| | | return sent == (int)data.size(); |
| | | } |
| | | |
| | | void SocketComm::closeClient(SOCKET s) { |
| | | if (s != INVALID_SOCKET) closesocket(s); |
| | | } |
| | | |
| | | void SocketComm::closeSocket() { |
| | | if (listenSock != INVALID_SOCKET) { closesocket(listenSock); listenSock = INVALID_SOCKET; } |
| | | if (sock != INVALID_SOCKET) { closesocket(sock); sock = INVALID_SOCKET; } |
| | | } |
| | | |
| | | bool SocketComm::sendDataSingle(const std::vector<uint8_t>& data) { |
| | | if (sock == INVALID_SOCKET) return false; |
| | | return sendTo(sock, data); |
| | | } |
| | | bool SocketComm::recvSingle(std::vector<uint8_t>& buffer) { |
| | | if (sock == INVALID_SOCKET) return false; |
| | | return recvFrom(sock, buffer); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #ifndef SOCKET_COMM_H |
| | | #define SOCKET_COMM_H |
| | | |
| | | #include <winsock2.h> |
| | | #include <ws2tcpip.h> |
| | | #include <string> |
| | | #include <vector> |
| | | #include <iostream> |
| | | |
| | | #pragma comment(lib, "ws2_32.lib") |
| | | |
| | | class SocketComm { |
| | | public: |
| | | SocketComm(); |
| | | ~SocketComm(); |
| | | |
| | | bool createClientSocket(const std::string& serverIP, uint16_t serverPort); // 客æ·ç«¯ |
| | | bool createServerSocket(uint16_t port); // æå¡ç«¯ï¼çå¬ï¼ |
| | | |
| | | // æ°å¢ï¼éé»å¡ accept/æ¶å/å
³éæå®å®¢æ·ç«¯ |
| | | bool acceptOne(SOCKET& outClient, std::string& outIp, uint16_t& outPort); |
| | | bool recvFrom(SOCKET s, std::vector<uint8_t>& buffer, bool& peerClosed); |
| | | |
| | | // å¯éï¼ä¸ºäºå
¼å®¹æ§è°ç¨ï¼ä¿çä¸ä¸ªå
èå
è£
ï¼å¦æå
¶å®å°æ¹è¿ç¨å°äºæ§ç¾åï¼ |
| | | inline bool recvFrom(SOCKET s, std::vector<uint8_t>& buffer) { |
| | | bool closed = false; |
| | | return recvFrom(s, buffer, closed); |
| | | } |
| | | bool sendTo(SOCKET s, const std::vector<uint8_t>& data); |
| | | void closeClient(SOCKET s); |
| | | |
| | | void closeSocket(); // å
³éç嬿åè¿æ¥ |
| | | |
| | | // ä¾ä¸å±å¤ææ¬å¯¹è±¡å½åæ¯å¦æ¯âç嬿¨¡å¼â |
| | | bool isListening() const { return listenSock != INVALID_SOCKET; } |
| | | bool sendDataSingle(const std::vector<uint8_t>& data); // 客æ·ç«¯åè¿æ¥åé |
| | | bool recvSingle(std::vector<uint8_t>& buffer); // 客æ·ç«¯åè¿æ¥æ¥æ¶ |
| | | |
| | | private: |
| | | SOCKET listenSock = INVALID_SOCKET; // çå¬ socketï¼æå¡ç«¯ï¼ |
| | | SOCKET sock = INVALID_SOCKET; // åè¿æ¥æ¨¡å¼ï¼å®¢æ·ç«¯æ¶ç¨ï¼ |
| | | WSADATA wsaData{}; |
| | | |
| | | bool setNonBlocking(SOCKET s, bool nb); |
| | | }; |
| | | |
| | | #endif // SOCKET_COMM_H |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <cstdint> |
| | | #include <string> |
| | | #include <vector> |
| | | |
| | | namespace Proto { |
| | | |
| | | // åºå®å¸§ |
| | | inline constexpr uint8_t kHead[4] = { 0x11, 0x88, 0x11, 0x88 }; |
| | | inline constexpr uint8_t kTail = 0x88; |
| | | |
| | | // æä»¤ç |
| | | enum : uint16_t { |
| | | // æ¡æ |
| | | CMD_REQ_VERSION = 0x0001, |
| | | CMD_RSP_VERSION = 0xF001, |
| | | |
| | | // åééå¢éæå |
| | | CMD_REQ_SINCE = 0x0101, |
| | | CMD_RSP_SINCE = 0xF101, |
| | | |
| | | // ç»è®¡/ééå表 |
| | | CMD_REQ_STATS = 0x0103, |
| | | CMD_RSP_STATS = 0xF103, |
| | | |
| | | // æºå°å表 |
| | | CMD_REQ_MACHINES = 0x0104, |
| | | CMD_RSP_MACHINES = 0xF104, |
| | | |
| | | // æ´æºå¤ééå¢éæå |
| | | CMD_REQ_SINCE_ALL = 0x0105, |
| | | CMD_RSP_SINCE_ALL = 0xF105, |
| | | |
| | | // æ¹æ¬¡ä¿¡æ¯ |
| | | CMD_REQ_BATCH_INFO = 0x0120, |
| | | CMD_RSP_BATCH_INFO = 0xF120, |
| | | |
| | | // é误 |
| | | CMD_RSP_ERROR = 0xE100, |
| | | }; |
| | | |
| | | // === since* 请æ±ééå batchId çæ å¿ä½ === |
| | | inline constexpr uint16_t SINCE_FLAG_HAS_BATCH = 0x0001; |
| | | |
| | | // ===== æ°æ®ç»æï¼ä¸¤ç«¯å
±ç¨ï¼ ===== |
| | | |
| | | // 0x0001 / 0xF001 |
| | | struct ReqVersion { |
| | | uint32_t dataId = 0; |
| | | }; |
| | | struct RspVersion { |
| | | uint32_t dataId = 0; |
| | | std::string version; // UTF-8ï¼ä¾å¦ "1.0.1" |
| | | }; |
| | | |
| | | // 0x0104 / 0xF104 |
| | | struct MachineInfo { |
| | | uint32_t id = 0; |
| | | std::string name; |
| | | }; |
| | | struct ReqMachines { |
| | | uint32_t dataId = 0; |
| | | }; |
| | | struct RspMachines { |
| | | uint32_t dataId = 0; |
| | | std::vector<MachineInfo> machines; |
| | | }; |
| | | |
| | | // 0x0103 / 0xF103 |
| | | struct ReqStats { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | uint16_t flags = 0; |
| | | }; |
| | | struct ChannelStatInfo { |
| | | uint32_t channelId = 0; |
| | | uint64_t earliestTs = 0; |
| | | uint64_t latestTs = 0; |
| | | uint32_t size = 0; |
| | | std::string name; // UTF-8 |
| | | }; |
| | | struct RspStats { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | std::vector<ChannelStatInfo> channels; |
| | | }; |
| | | |
| | | // 0x0101 / 0xF101ï¼åééå¢éï¼ |
| | | struct ReqSince { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | uint32_t channelId = 0; |
| | | uint64_t sinceTsExclusive = 0; // ms |
| | | uint16_t maxCount = 1024; |
| | | uint16_t flags = 0; // æä½ï¼è§ SINCE_FLAG_HAS_BATCH |
| | | std::string batchId; // flags & SINCE_FLAG_HAS_BATCH æ¶ææ |
| | | }; |
| | | struct SamplePair { |
| | | uint64_t ts_ms = 0; |
| | | double value = 0.0; |
| | | }; |
| | | struct RspSince { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | uint32_t channelId = 0; |
| | | uint64_t lastTsSent = 0; |
| | | uint8_t more = 0; // 该é鿝å¦è¿ææªå |
| | | std::vector<SamplePair> samples; |
| | | }; |
| | | |
| | | // 0x0105 / 0xF105ï¼æ´æºå¤ééå¢éï¼ |
| | | struct ChannelBlock { |
| | | uint32_t channelId = 0; |
| | | uint64_t lastTsSent = 0; // 该ééæ¬æ¬¡æåæ ·æ¬æ¶é´æ³ |
| | | uint8_t more = 0; // 该é鿝å¦è¿ææªå |
| | | std::vector<SamplePair> samples; |
| | | }; |
| | | struct ReqSinceAll { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | uint64_t sinceTsExclusive = 0; // 对ææééç»ä¸ since |
| | | uint16_t maxPerChannel = 1024; // æ¯æ¡æ²çº¿ä¸é |
| | | uint16_t flags = 0; // æä½ï¼è§ SINCE_FLAG_HAS_BATCH |
| | | std::string batchId; // flags & SINCE_FLAG_HAS_BATCH æ¶ææ |
| | | }; |
| | | struct RspSinceAll { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | uint8_t moreAny = 0; // æ¯å¦è¿æä»»æééæå©ä½ |
| | | std::vector<ChannelBlock> blocks; // å¤ä¸ªééçå¢é |
| | | }; |
| | | |
| | | // === æ¹æ¬¡ç¶æ === |
| | | enum class BatchState : uint8_t { |
| | | Idle = 0, // æ æ´»å¨æ¹æ¬¡ï¼activeBatchId="", activeStartTs=0, expectedEndTs=0 |
| | | Active = 1, |
| | | }; |
| | | |
| | | // === é误ç === |
| | | enum class ErrCode : uint16_t { |
| | | NoActiveBatch = 0x0001, // å½åæ æ´»å¨æ¹æ¬¡ |
| | | BatchMismatch = 0x0002, // è¯·æ±æºå¸¦ç batchId ä¸å½åæ´»å¨æ¹æ¬¡ä¸ä¸è´ |
| | | }; |
| | | |
| | | // 0x0120 / 0xF120ï¼æ¹æ¬¡ä¿¡æ¯ï¼ |
| | | struct ReqBatchInfo { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | }; |
| | | struct RspBatchInfo { |
| | | uint32_t dataId = 0; |
| | | uint32_t machineId = 0; |
| | | BatchState state = BatchState::Idle; |
| | | std::string activeBatchId; // state=Idle æ¶åºä¸ºç©º |
| | | uint64_t activeStartTs = 0; |
| | | uint64_t expectedEndTs = 0; // =0 表示æªç¥/Idle |
| | | }; |
| | | |
| | | // 0xE100 é误帧 |
| | | struct RspError { |
| | | uint32_t dataId = 0; |
| | | uint16_t refCmd = 0; // åºé请æ±çæä»¤ï¼å¦ 0x0101/0x0105/0x0120... |
| | | uint32_t machineId = 0; |
| | | ErrCode code = ErrCode::NoActiveBatch; |
| | | std::string message; // ç®çææ¬ |
| | | }; |
| | | |
| | | } // namespace Proto |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "ProtocolCodec.h" |
| | | #include <cstring> // std::memcpy |
| | | #include <cstdio> // std::snprintf (å¦éæ¥å¿) |
| | | #include <vector> |
| | | |
| | | namespace Proto { |
| | | |
| | | // --------------------------- |
| | | // Big-endian åºç¡ç¼è§£ç å·¥å
· |
| | | // --------------------------- |
| | | void put_u16(std::vector<uint8_t>& v, uint16_t x) { |
| | | v.push_back(static_cast<uint8_t>((x >> 8) & 0xFF)); |
| | | v.push_back(static_cast<uint8_t>(x & 0xFF)); |
| | | } |
| | | void put_u32(std::vector<uint8_t>& v, uint32_t x) { |
| | | v.push_back(static_cast<uint8_t>((x >> 24) & 0xFF)); |
| | | v.push_back(static_cast<uint8_t>((x >> 16) & 0xFF)); |
| | | v.push_back(static_cast<uint8_t>((x >> 8) & 0xFF)); |
| | | v.push_back(static_cast<uint8_t>(x & 0xFF)); |
| | | } |
| | | void put_u64(std::vector<uint8_t>& v, uint64_t x) { |
| | | for (int i = 7; i >= 0; --i) v.push_back(static_cast<uint8_t>((x >> (i * 8)) & 0xFF)); |
| | | } |
| | | uint16_t get_u16(const uint8_t* p) { |
| | | return static_cast<uint16_t>((uint16_t(p[0]) << 8) | uint16_t(p[1])); |
| | | } |
| | | uint32_t get_u32(const uint8_t* p) { |
| | | return (uint32_t(p[0]) << 24) | (uint32_t(p[1]) << 16) | (uint32_t(p[2]) << 8) | uint32_t(p[3]); |
| | | } |
| | | uint64_t get_u64(const uint8_t* p) { |
| | | uint64_t x = 0; |
| | | for (int i = 0; i < 8; ++i) { x = (x << 8) | p[i]; } |
| | | return x; |
| | | } |
| | | void put_f64_be(std::vector<uint8_t>& v, double d) { |
| | | static_assert(sizeof(double) == 8, "double must be 8 bytes"); |
| | | uint64_t u; |
| | | std::memcpy(&u, &d, 8); |
| | | for (int i = 7; i >= 0; --i) v.push_back(static_cast<uint8_t>((u >> (i * 8)) & 0xFF)); |
| | | } |
| | | double get_f64_be(const uint8_t* p) { |
| | | uint64_t u = 0; |
| | | for (int i = 0; i < 8; ++i) { u = (u << 8) | p[i]; } |
| | | double d; |
| | | std::memcpy(&d, &u, 8); |
| | | return d; |
| | | } |
| | | |
| | | // å¿«éçª¥æ¢æ£æ cmdï¼ä¸å宿´é¿åº¦æ ¸å¯¹ï¼ä¿çä½ åæ¬é£æ ¼ï¼ |
| | | uint16_t peek_cmd(const std::vector<uint8_t>& f) { |
| | | if (f.size() < 12) return 0; |
| | | if (!(f[0] == kHead[0] && f[1] == kHead[1] && f[2] == kHead[2] && f[3] == kHead[3])) return 0; |
| | | return (uint16_t(f[10]) << 8) | f[11]; |
| | | } |
| | | |
| | | // å
è£
帧ï¼4B头 + 4B dataId + 2B bodyLen + body + 1Bå°¾ |
| | | static inline void frame_wrap(uint32_t dataId, const std::vector<uint8_t>& body, std::vector<uint8_t>& out) { |
| | | out.clear(); |
| | | out.reserve(4 + 4 + 2 + body.size() + 1); |
| | | out.push_back(kHead[0]); out.push_back(kHead[1]); out.push_back(kHead[2]); out.push_back(kHead[3]); |
| | | put_u32(out, dataId); |
| | | put_u16(out, static_cast<uint16_t>(body.size())); |
| | | out.insert(out.end(), body.begin(), body.end()); |
| | | out.push_back(kTail); |
| | | } |
| | | |
| | | // --------------------------- |
| | | // 0x0104 / 0xF104 Machines |
| | | // --------------------------- |
| | | std::vector<uint8_t> encodeRequestMachines(const ReqMachines& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_MACHINES); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseMachines(const RspMachines& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_MACHINES); |
| | | put_u16(body, static_cast<uint16_t>(rsp.machines.size())); |
| | | for (auto& m : rsp.machines) { |
| | | put_u32(body, m.id); |
| | | const uint16_t n = static_cast<uint16_t>(m.name.size()); |
| | | put_u16(body, n); |
| | | body.insert(body.end(), m.name.begin(), m.name.end()); |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestMachines(const std::vector<uint8_t>& f, ReqMachines& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | return (get_u16(b) == CMD_REQ_MACHINES); |
| | | } |
| | | |
| | | bool decodeResponseMachines(const std::vector<uint8_t>& f, RspMachines& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_MACHINES) return false; |
| | | b += 2; |
| | | const uint16_t cnt = get_u16(b); b += 2; |
| | | |
| | | out.machines.clear(); |
| | | out.machines.reserve(cnt); |
| | | for (uint16_t i = 0; i < cnt; ++i) { |
| | | if (b + 4 + 2 > e) return false; |
| | | const uint32_t id = get_u32(b); b += 4; |
| | | const uint16_t n = get_u16(b); b += 2; |
| | | if (b + n > e) return false; |
| | | out.machines.push_back({ id, std::string(reinterpret_cast<const char*>(b), n) }); |
| | | b += n; |
| | | } |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------- |
| | | // 0x0001 / 0xF001 Version |
| | | // --------------------------- |
| | | std::vector<uint8_t> encodeRequestVersion(const ReqVersion& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_VERSION); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseVersion(const RspVersion& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_VERSION); |
| | | const uint16_t n = static_cast<uint16_t>(rsp.version.size()); |
| | | put_u16(body, n); |
| | | body.insert(body.end(), rsp.version.begin(), rsp.version.end()); // UTF-8 |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestVersion(const std::vector<uint8_t>& f, ReqVersion& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | const uint8_t* b = p + 10; |
| | | return (get_u16(b) == CMD_REQ_VERSION); |
| | | } |
| | | |
| | | bool decodeResponseVersion(const std::vector<uint8_t>& f, RspVersion& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_VERSION) return false; |
| | | b += 2; |
| | | |
| | | const uint16_t n = get_u16(b); b += 2; |
| | | if (b + n > e) return false; |
| | | out.version.assign(reinterpret_cast<const char*>(b), n); |
| | | b += n; |
| | | |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------- |
| | | // 0x0103 / 0xF103 Stats |
| | | // --------------------------- |
| | | std::vector<uint8_t> encodeRequestStats(const ReqStats& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_STATS); |
| | | put_u32(body, req.machineId); |
| | | put_u16(body, req.flags); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseStats(const RspStats& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_STATS); |
| | | put_u32(body, rsp.machineId); |
| | | put_u16(body, static_cast<uint16_t>(rsp.channels.size())); |
| | | |
| | | for (auto& c : rsp.channels) { |
| | | put_u32(body, c.channelId); |
| | | put_u64(body, c.earliestTs); |
| | | put_u64(body, c.latestTs); |
| | | put_u32(body, c.size); |
| | | const uint16_t n = static_cast<uint16_t>(c.name.size()); |
| | | put_u16(body, n); |
| | | body.insert(body.end(), c.name.begin(), c.name.end()); |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestStats(const std::vector<uint8_t>& f, ReqStats& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | if (b + 2 + 4 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_REQ_STATS) return false; |
| | | b += 2; |
| | | |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.flags = get_u16(b); b += 2; |
| | | |
| | | return (b == e); |
| | | } |
| | | |
| | | bool decodeResponseStats(const std::vector<uint8_t>& f, RspStats& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 4 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_STATS) return false; |
| | | b += 2; |
| | | |
| | | out.machineId = get_u32(b); b += 4; |
| | | const uint16_t cnt = get_u16(b); b += 2; |
| | | |
| | | out.channels.clear(); |
| | | out.channels.reserve(cnt); |
| | | for (uint16_t i = 0; i < cnt; ++i) { |
| | | if (b + 4 + 8 + 8 + 4 + 2 > e) return false; |
| | | ChannelStatInfo ci{}; |
| | | ci.channelId = get_u32(b); b += 4; |
| | | ci.earliestTs = get_u64(b); b += 8; |
| | | ci.latestTs = get_u64(b); b += 8; |
| | | ci.size = get_u32(b); b += 4; |
| | | |
| | | const uint16_t n = get_u16(b); b += 2; |
| | | if (b + n > e) return false; |
| | | ci.name.assign(reinterpret_cast<const char*>(b), n); |
| | | b += n; |
| | | |
| | | out.channels.push_back(std::move(ci)); |
| | | } |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------------------- |
| | | // 0x0101 / 0xF101 Sinceï¼æ¯æå¯é batchIdï¼ |
| | | // --------------------------------------- |
| | | std::vector<uint8_t> encodeRequestSince(const ReqSince& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_SINCE); |
| | | put_u32(body, req.machineId); |
| | | put_u32(body, req.channelId); |
| | | put_u64(body, req.sinceTsExclusive); |
| | | put_u16(body, req.maxCount); |
| | | put_u16(body, req.flags); |
| | | if (req.flags & SINCE_FLAG_HAS_BATCH) { |
| | | const uint16_t L = static_cast<uint16_t>(req.batchId.size()); |
| | | put_u16(body, L); |
| | | body.insert(body.end(), req.batchId.begin(), req.batchId.end()); |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseSince(const RspSince& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_SINCE); |
| | | put_u32(body, rsp.machineId); |
| | | put_u32(body, rsp.channelId); |
| | | put_u64(body, rsp.lastTsSent); |
| | | body.push_back(rsp.more ? 1u : 0u); |
| | | put_u16(body, static_cast<uint16_t>(rsp.samples.size())); |
| | | for (auto& s : rsp.samples) { |
| | | put_u64(body, s.ts_ms); |
| | | put_f64_be(body, s.value); |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestSince(const std::vector<uint8_t>& f, ReqSince& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 > e) return false; |
| | | if (get_u16(b) != CMD_REQ_SINCE) return false; |
| | | b += 2; |
| | | |
| | | if (b + 4 + 4 + 8 + 2 + 2 > e) return false; |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.channelId = get_u32(b); b += 4; |
| | | out.sinceTsExclusive = get_u64(b); b += 8; |
| | | out.maxCount = get_u16(b); b += 2; |
| | | out.flags = get_u16(b); b += 2; |
| | | |
| | | out.batchId.clear(); |
| | | if (out.flags & SINCE_FLAG_HAS_BATCH) { |
| | | if (b + 2 > e) return false; |
| | | const uint16_t L = get_u16(b); b += 2; |
| | | if (b + L > e) return false; |
| | | out.batchId.assign(reinterpret_cast<const char*>(b), L); |
| | | b += L; |
| | | } |
| | | |
| | | return (b == e); |
| | | } |
| | | |
| | | bool decodeResponseSince(const std::vector<uint8_t>& f, RspSince& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_SINCE) return false; |
| | | b += 2; |
| | | |
| | | if (b + 4 + 4 + 8 + 1 + 2 > e) return false; |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.channelId = get_u32(b); b += 4; |
| | | out.lastTsSent = get_u64(b); b += 8; |
| | | out.more = *b++; // u8 |
| | | const uint16_t cnt = get_u16(b); b += 2; |
| | | |
| | | out.samples.clear(); |
| | | out.samples.reserve(cnt); |
| | | for (uint16_t i = 0; i < cnt; ++i) { |
| | | if (b + 8 + 8 > e) return false; |
| | | const uint64_t ts = get_u64(b); b += 8; |
| | | const double v = get_f64_be(b); b += 8; |
| | | out.samples.push_back({ ts, v }); |
| | | } |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------------------- |
| | | // 0x0105 / 0xF105 SinceAllï¼æ´æºå¤ééå¢éï¼ |
| | | // --------------------------------------- |
| | | std::vector<uint8_t> encodeRequestSinceAll(const ReqSinceAll& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_SINCE_ALL); |
| | | put_u32(body, req.machineId); |
| | | put_u64(body, req.sinceTsExclusive); |
| | | put_u16(body, req.maxPerChannel); |
| | | put_u16(body, req.flags); |
| | | if (req.flags & SINCE_FLAG_HAS_BATCH) { |
| | | const uint16_t L = static_cast<uint16_t>(req.batchId.size()); |
| | | put_u16(body, L); |
| | | body.insert(body.end(), req.batchId.begin(), req.batchId.end()); |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseSinceAll(const RspSinceAll& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_SINCE_ALL); |
| | | put_u32(body, rsp.machineId); |
| | | body.push_back(rsp.moreAny ? 1u : 0u); |
| | | put_u16(body, static_cast<uint16_t>(rsp.blocks.size())); |
| | | |
| | | for (const auto& b : rsp.blocks) { |
| | | put_u32(body, b.channelId); |
| | | put_u64(body, b.lastTsSent); |
| | | body.push_back(b.more ? 1u : 0u); |
| | | put_u16(body, static_cast<uint16_t>(b.samples.size())); |
| | | for (const auto& sp : b.samples) { |
| | | put_u64(body, sp.ts_ms); |
| | | put_f64_be(body, sp.value); |
| | | } |
| | | } |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestSinceAll(const std::vector<uint8_t>& f, ReqSinceAll& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 > e) return false; |
| | | if (get_u16(b) != CMD_REQ_SINCE_ALL) return false; |
| | | b += 2; |
| | | |
| | | if (b + 4 + 8 + 2 + 2 > e) return false; |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.sinceTsExclusive = get_u64(b); b += 8; |
| | | out.maxPerChannel = get_u16(b); b += 2; |
| | | out.flags = get_u16(b); b += 2; |
| | | |
| | | out.batchId.clear(); |
| | | if (out.flags & SINCE_FLAG_HAS_BATCH) { |
| | | if (b + 2 > e) return false; |
| | | const uint16_t L = get_u16(b); b += 2; |
| | | if (b + L > e) return false; |
| | | out.batchId.assign(reinterpret_cast<const char*>(b), L); |
| | | b += L; |
| | | } |
| | | return (b == e); |
| | | } |
| | | |
| | | bool decodeResponseSinceAll(const std::vector<uint8_t>& f, RspSinceAll& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_SINCE_ALL) return false; |
| | | b += 2; |
| | | |
| | | if (b + 4 + 1 + 2 > e) return false; |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.moreAny = *b++; // u8 |
| | | const uint16_t N = get_u16(b); b += 2; |
| | | |
| | | out.blocks.clear(); |
| | | out.blocks.reserve(N); |
| | | for (uint16_t i = 0; i < N; ++i) { |
| | | if (b + 4 + 8 + 1 + 2 > e) return false; |
| | | ChannelBlock blk; |
| | | blk.channelId = get_u32(b); b += 4; |
| | | blk.lastTsSent = get_u64(b); b += 8; |
| | | blk.more = *b++; // u8 |
| | | const uint16_t M = get_u16(b); b += 2; |
| | | |
| | | blk.samples.clear(); |
| | | blk.samples.reserve(M); |
| | | for (uint16_t j = 0; j < M; ++j) { |
| | | if (b + 8 + 8 > e) return false; |
| | | SamplePair sp; |
| | | sp.ts_ms = get_u64(b); b += 8; |
| | | sp.value = get_f64_be(b); b += 8; |
| | | blk.samples.push_back(sp); |
| | | } |
| | | out.blocks.push_back(std::move(blk)); |
| | | } |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------- |
| | | // 0x0120 / 0xF120 BatchInfo |
| | | // --------------------------- |
| | | std::vector<uint8_t> encodeRequestBatchInfo(const ReqBatchInfo& req) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_REQ_BATCH_INFO); |
| | | put_u32(body, req.machineId); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(req.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeRequestBatchInfo(const std::vector<uint8_t>& f, ReqBatchInfo& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 4 > e) return false; |
| | | if (get_u16(b) != CMD_REQ_BATCH_INFO) return false; |
| | | b += 2; |
| | | |
| | | out.machineId = get_u32(b); b += 4; |
| | | return (b == e); |
| | | } |
| | | |
| | | std::vector<uint8_t> encodeResponseBatchInfo(const RspBatchInfo& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_BATCH_INFO); |
| | | put_u32(body, rsp.machineId); |
| | | body.push_back(static_cast<uint8_t>(rsp.state)); |
| | | |
| | | const uint16_t L = static_cast<uint16_t>(rsp.activeBatchId.size()); |
| | | put_u16(body, L); |
| | | body.insert(body.end(), rsp.activeBatchId.begin(), rsp.activeBatchId.end()); |
| | | |
| | | put_u64(body, rsp.activeStartTs); |
| | | put_u64(body, rsp.expectedEndTs); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeResponseBatchInfo(const std::vector<uint8_t>& f, RspBatchInfo& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 4 + 1 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_BATCH_INFO) return false; |
| | | b += 2; |
| | | |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.state = static_cast<BatchState>(*b++); |
| | | |
| | | const uint16_t L = get_u16(b); b += 2; |
| | | if (b + L > e) return false; |
| | | out.activeBatchId.assign(reinterpret_cast<const char*>(b), L); b += L; |
| | | |
| | | if (b + 8 + 8 > e) return false; |
| | | out.activeStartTs = get_u64(b); b += 8; |
| | | out.expectedEndTs = get_u64(b); b += 8; |
| | | |
| | | return (b == e); |
| | | } |
| | | |
| | | // --------------------------- |
| | | // 0xE100 Error |
| | | // --------------------------- |
| | | std::vector<uint8_t> encodeResponseError(const RspError& rsp) { |
| | | std::vector<uint8_t> body; |
| | | put_u16(body, CMD_RSP_ERROR); |
| | | put_u16(body, rsp.refCmd); |
| | | put_u32(body, rsp.machineId); |
| | | put_u16(body, static_cast<uint16_t>(rsp.code)); |
| | | const uint16_t L = static_cast<uint16_t>(rsp.message.size()); |
| | | put_u16(body, L); |
| | | body.insert(body.end(), rsp.message.begin(), rsp.message.end()); |
| | | |
| | | std::vector<uint8_t> out; |
| | | frame_wrap(rsp.dataId, body, out); |
| | | return out; |
| | | } |
| | | |
| | | bool decodeResponseError(const std::vector<uint8_t>& f, RspError& out) { |
| | | if (f.size() < 11) return false; |
| | | const uint8_t* p = f.data(); |
| | | if (p[0] != kHead[0] || p[1] != kHead[1] || p[2] != kHead[2] || p[3] != kHead[3]) return false; |
| | | if (f.back() != kTail) return false; |
| | | |
| | | out.dataId = get_u32(p + 4); |
| | | const uint16_t bodyLen = get_u16(p + 8); |
| | | if (10u + bodyLen + 1u != f.size()) return false; |
| | | |
| | | const uint8_t* b = p + 10; |
| | | const uint8_t* e = b + bodyLen; |
| | | |
| | | if (b + 2 + 2 + 4 + 2 + 2 > e) return false; |
| | | if (get_u16(b) != CMD_RSP_ERROR) return false; |
| | | b += 2; |
| | | |
| | | out.refCmd = get_u16(b); b += 2; |
| | | out.machineId = get_u32(b); b += 4; |
| | | out.code = static_cast<ErrCode>(get_u16(b)); b += 2; |
| | | |
| | | const uint16_t L = get_u16(b); b += 2; |
| | | if (b + L > e) return false; |
| | | out.message.assign(reinterpret_cast<const char*>(b), L); b += L; |
| | | |
| | | return (b == e); |
| | | } |
| | | |
| | | } // namespace Proto |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "Protocol.h" |
| | | |
| | | namespace Proto { |
| | | |
| | | // 大端工å
· |
| | | void put_u16(std::vector<uint8_t>& v, uint16_t x); |
| | | void put_u32(std::vector<uint8_t>& v, uint32_t x); |
| | | void put_u64(std::vector<uint8_t>& v, uint64_t x); |
| | | uint16_t get_u16(const uint8_t* p); |
| | | uint32_t get_u32(const uint8_t* p); |
| | | uint64_t get_u64(const uint8_t* p); |
| | | void put_f64_be(std::vector<uint8_t>& v, double d); |
| | | double get_f64_be(const uint8_t* p); |
| | | |
| | | // 帮å©ï¼peek cmd |
| | | uint16_t peek_cmd(const std::vector<uint8_t>& frame); |
| | | |
| | | // ç¼ç ï¼æå¸§ï¼å¤´ + dataId + len + body + å°¾ï¼ |
| | | std::vector<uint8_t> encodeRequestVersion(const ReqVersion& req); |
| | | std::vector<uint8_t> encodeResponseVersion(const RspVersion& rsp); |
| | | std::vector<uint8_t> encodeRequestMachines(const ReqMachines& req); |
| | | std::vector<uint8_t> encodeResponseMachines(const RspMachines& rsp); |
| | | std::vector<uint8_t> encodeRequestStats(const ReqStats& req); |
| | | std::vector<uint8_t> encodeResponseStats(const RspStats& rsp); |
| | | std::vector<uint8_t> encodeRequestSince(const ReqSince& req); |
| | | std::vector<uint8_t> encodeResponseSince(const RspSince& rsp); |
| | | std::vector<uint8_t> encodeRequestSinceAll(const ReqSinceAll& req); |
| | | std::vector<uint8_t> encodeResponseSinceAll(const RspSinceAll& rsp); |
| | | std::vector<uint8_t> encodeRequestBatchInfo(const ReqBatchInfo& req); |
| | | std::vector<uint8_t> encodeResponseBatchInfo(const RspBatchInfo& rsp); |
| | | |
| | | // è§£ç |
| | | bool decodeRequestVersion(const std::vector<uint8_t>& frame, ReqVersion& out); |
| | | bool decodeResponseVersion(const std::vector<uint8_t>& frame, RspVersion& out); |
| | | bool decodeRequestMachines(const std::vector<uint8_t>& frame, ReqMachines& out); |
| | | bool decodeResponseMachines(const std::vector<uint8_t>& frame, RspMachines& out); |
| | | bool decodeRequestStats(const std::vector<uint8_t>& frame, ReqStats& out); |
| | | bool decodeResponseStats(const std::vector<uint8_t>& frame, RspStats& out); |
| | | bool decodeRequestSince(const std::vector<uint8_t>& frame, ReqSince& out); |
| | | bool decodeResponseSince(const std::vector<uint8_t>& frame, RspSince& out); |
| | | bool decodeRequestSinceAll(const std::vector<uint8_t>& frame, ReqSinceAll& out); |
| | | bool decodeResponseSinceAll(const std::vector<uint8_t>& frame, RspSinceAll& out); |
| | | bool decodeRequestBatchInfo(const std::vector<uint8_t>& frame, ReqBatchInfo& out); |
| | | bool decodeResponseBatchInfo(const std::vector<uint8_t>& frame, RspBatchInfo& out); |
| | | std::vector<uint8_t> encodeResponseError(const RspError& rsp); |
| | | bool decodeResponseError(const std::vector<uint8_t>& frame, RspError& out); |
| | | |
| | | } // namespace Proto |
| | |
| | | return 0; |
| | | } |
| | | |
| | | int CBonder::onProcessStateChanged(PROCESS_STATE state) |
| | | int CBonder::onProcessStateChanged(int slotNo, PROCESS_STATE state) |
| | | { |
| | | CEquipment::onProcessStateChanged(state); |
| | | CEquipment::onProcessStateChanged(slotNo, state); |
| | | |
| | | if (state == PROCESS_STATE::Complete) { |
| | | // æ£æ¥æ°æ®ï¼å½å两çç»çï¼ä¸ç为G1, ä¸ç为G2, ä¸pProcessDataä¸çidè½å¹é
G1æG2 |
| | |
| | | virtual void getAttributeVector(CAttributeVector& attrubutes); |
| | | virtual int recvIntent(CPin* pPin, CIntent* pIntent); |
| | | virtual int onProcessData(CProcessData* pProcessData); |
| | | virtual int onProcessStateChanged(PROCESS_STATE state); |
| | | virtual int onProcessStateChanged(int slotNo, PROCESS_STATE state); |
| | | virtual int getIndexerOperationModeBaseValue(); |
| | | virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms); |
| | | virtual int parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& parsms); |
| | |
| | | #include "RecipeManager.h" |
| | | |
| | | |
| | | UINT btnID[] = { IDC_BUTTON_PORT1_PROCESS_START, |
| | | IDC_BUTTON_PORT2_PROCESS_START, |
| | | IDC_BUTTON_PORT3_PROCESS_START, |
| | | IDC_BUTTON_PORT4_PROCESS_START }; |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CCjPage2, CCjPageBase) |
| | |
| | | ON_BN_CLICKED(IDC_RADIO4, &CCjPage2::OnBnClickedRadio4) |
| | | ON_NOTIFY(CSGN_SEL_CHANGED, IDC_GRID1, &CCjPage2::OnGridSelChanged) |
| | | ON_NOTIFY(CSGN_MAT_CHANGED, IDC_GRID1, &CCjPage2::OnGridMatChanged) |
| | | ON_BN_CLICKED(IDC_BUTTON_PORT1_PROCESS_START, &CCjPage2::OnBnClickedButtonPort1ProcessStart) |
| | | ON_BN_CLICKED(IDC_BUTTON_PORT2_PROCESS_START, &CCjPage2::OnBnClickedButtonPort2ProcessStart) |
| | | ON_BN_CLICKED(IDC_BUTTON_PORT3_PROCESS_START, &CCjPage2::OnBnClickedButtonPort3ProcessStart) |
| | | ON_BN_CLICKED(IDC_BUTTON_PORT4_PROCESS_START, &CCjPage2::OnBnClickedButtonPort4ProcessStart) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | |
| | | m_grid.SetPortInfo(3, _T("Port 4"), _T("")); |
| | | |
| | | |
| | | // æµè¯æ°æ® |
| | | char szBuffer[256]; |
| | | for (int port = 0; port < 4; port++) { |
| | | for (int slot = 0; slot < 8; slot++) { |
| | | sprintf_s(szBuffer, 256, "Gls%04d%04d", port + 1, slot + 1); |
| | | m_grid.SetSlotGlass(port, slot, TRUE, szBuffer, CCarrierSlotGrid::MAT_G1); |
| | | } |
| | | } |
| | | |
| | | UpdatePjData(); |
| | | |
| | | |
| | |
| | | pItem->GetWindowRect(&rcItem); |
| | | ScreenToClient(rcItem); |
| | | |
| | | |
| | | int x = rcItem.left + 100 + 18; |
| | | int y = 100; |
| | | |
| | | |
| | | // 让æ§ä»¶çªå£å°ºå¯¸èªå¨å¹é
å½åå宽/è¡æ°ï¼ä¸åºç°æ»å¨æ¡ï¼ |
| | | if (::IsWindow(m_grid.m_hWnd)) { |
| | | CSize best = m_grid.CalcBestWindowSize(TRUE, -1, 2, 2); |
| | | pItem->MoveWindow(rcItem.left, rcItem.top, best.cx, best.cy); |
| | | pItem->Invalidate(); |
| | | pItem->GetWindowRect(&rcItem); |
| | | ScreenToClient(rcItem); |
| | | y = rcItem.bottom; |
| | | y += 18; |
| | | } |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_PORT1_PROCESS_START); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height()); |
| | | x += 220; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_PORT2_PROCESS_START); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height()); |
| | | x += 220; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_PORT3_PROCESS_START); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height()); |
| | | x += 220; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_PORT4_PROCESS_START); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height()); |
| | | x += 220; |
| | | } |
| | | |
| | | int CCjPage2::OnApply() |
| | |
| | | pButton->EnableWindow(enable[i]); |
| | | |
| | | m_grid.SetPortAllocated(i, !checked[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(checked[i]); |
| | | } |
| | | |
| | | |
| | | // 读ååºç宿°æ® |
| | | auto& master = theApp.m_model.getMaster(); |
| | | int EQID[] = {EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4}; |
| | | for (int p = 0; p < 4; p++) { |
| | | SERVO::CLoadPort* pPort = (SERVO::CLoadPort*)master.getEquipment(EQID[p]); |
| | | m_grid.SetPortInfo(p, |
| | | (std::string("Port ") + std::to_string(p+1)).c_str(), |
| | | pPort->getCassetteId().c_str() |
| | | ); |
| | | for (int i = 0; i < SLOT_MAX; ++i) { |
| | | SERVO::CSlot* pSlot = pPort->getSlot(i); |
| | | if (!pSlot) { |
| | | continue; |
| | | } |
| | | |
| | | // 设置 Panel ID |
| | | SERVO::CGlass* pGlass = dynamic_cast<SERVO::CGlass*>(pSlot->getContext()); |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | if (pGlass != nullptr && pJobDataS != nullptr) { |
| | | m_grid.SetSlotGlass(p, i, TRUE, |
| | | pGlass->getID().c_str(), |
| | | m_pjWarps[p].material[i]); |
| | | } |
| | | else { |
| | | m_grid.SetSlotGlass(p, i, FALSE, nullptr, CCarrierSlotGrid::MAT_G1); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | if (portIndex != -1) { |
| | | for (int i = 0; i < 8; i++) { |
| | | m_grid.SetSlotChecked(portIndex, i, ((PJWarp*)m_pContext)->checkSlot[i]); |
| | | m_grid.SetSlotMaterialType(portIndex, i, ((PJWarp*)m_pContext)->material[i]); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | |
| | | |
| | | *pResult = 0; |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedButtonPort1ProcessStart() |
| | | { |
| | | auto& master = theApp.m_model.getMaster(); |
| | | auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT1); |
| | | port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr); |
| | | |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedButtonPort2ProcessStart() |
| | | { |
| | | auto& master = theApp.m_model.getMaster(); |
| | | auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT2); |
| | | port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedButtonPort3ProcessStart() |
| | | { |
| | | auto& master = theApp.m_model.getMaster(); |
| | | auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT3); |
| | | port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedButtonPort4ProcessStart() |
| | | { |
| | | auto& master = theApp.m_model.getMaster(); |
| | | auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT4); |
| | | port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | struct PJWarp { |
| | | BOOL addToCj; |
| | | void* pj; |
| | | int port; |
| | | BOOL checkSlot[8]; |
| | | int material[8]; |
| | | }; |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | class CCjPage2 : public CCjPageBase |
| | |
| | | afx_msg void OnBnClickedRadio4(); |
| | | afx_msg void OnGridSelChanged(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnGridMatChanged(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnBnClickedButtonPort1ProcessStart(); |
| | | afx_msg void OnBnClickedButtonPort2ProcessStart(); |
| | | afx_msg void OnBnClickedButtonPort3ProcessStart(); |
| | | afx_msg void OnBnClickedButtonPort4ProcessStart(); |
| | | }; |
| | |
| | | |
| | | BEGIN_MESSAGE_MAP(CCjPage3, CCjPageBase) |
| | | ON_WM_DESTROY() |
| | | ON_EN_CHANGE(IDC_EDIT_CJ_ID, &CCjPage3::OnEnChangeEditCjId) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | |
| | | |
| | | int CCjPage3::OnApply() |
| | | { |
| | | // SERVO::CControlJob* |
| | | if (m_pContext == nullptr) return -1; |
| | | SERVO::CControlJob* pControlJob = (SERVO::CControlJob*)m_pContext; |
| | | |
| | | // æ´æ°åç§° |
| | | BOOL bOkName = TRUE; |
| | | char szBuffer[256]; |
| | | GetDlgItemText(IDC_EDIT_CJ_ID, szBuffer, 256); |
| | | pControlJob->setId(std::string(szBuffer)); |
| | | |
| | | |
| | | ContentChanged(1); |
| | | return 0; |
| | | } |
| | | |
| | | void CCjPage3::OnSetContext(void* pContext) |
| | | { |
| | | UpdateCjData(); |
| | | } |
| | | |
| | | void CCjPage3::UpdateCjData() |
| | | { |
| | | if (m_pContext == nullptr) return; |
| | | |
| | | m_bContentChangedLock = TRUE; |
| | | |
| | | SERVO::CControlJob* pControlJob = (SERVO::CControlJob*)m_pContext; |
| | | SetDlgItemText(IDC_EDIT_CJ_ID, pControlJob->id().c_str()); |
| | | |
| | | |
| | | m_bContentChangedLock = FALSE; |
| | | } |
| | | |
| | | void CCjPage3::OnEnChangeEditCjId() |
| | | { |
| | | ContentChanged(0); |
| | | } |
| | |
| | | #pragma once |
| | | #include "CCjPageBase.h" |
| | | #include "CControlJob.h" |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | |
| | | protected: |
| | | void Resize(); |
| | | virtual int OnApply(); |
| | | virtual void OnSetContext(void* pContext); |
| | | void UpdateCjData(); |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnDestroy(); |
| | | afx_msg void OnEnChangeEditCjId(); |
| | | }; |
| | |
| | | m_tEnd = src.m_tEnd; |
| | | } |
| | | |
| | | void CControlJob::setId(std::string& id) |
| | | { |
| | | m_cjId = trimCopy(id); |
| | | clampString(m_cjId, MAX_ID_LEN); |
| | | } |
| | | |
| | | bool CControlJob::addPJ(const std::string& pjId) { |
| | | if (pjId.empty()) return false; |
| | | auto id = pjId; |
| | |
| | | const std::vector<CControlJob::ValidationIssue>& CControlJob::issues() |
| | | { |
| | | return m_issues; |
| | | } |
| | | |
| | | void CControlJob::clearIssues() |
| | | { |
| | | m_issues.clear(); |
| | | } |
| | | |
| | | bool CControlJob::validateForCreate( |
| | |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::abort() { |
| | | bool CControlJob::abort(std::string reason) { |
| | | if (m_state == CJState::Completed || m_state == CJState::Aborted || m_state == CJState::Failed) |
| | | return false; |
| | | m_failReason = trimCopy(reason); |
| | | clampString(m_failReason, 128); |
| | | m_state = CJState::Aborted; |
| | | markEnd(); |
| | | return true; |
| | |
| | | |
| | | // ââ åºæ¬å±æ§ ââ // |
| | | const std::string& id() const noexcept { return m_cjId; } |
| | | void setId(std::string& id); |
| | | CJState state() const noexcept { return m_state; } |
| | | uint8_t priority() const noexcept { return m_priority; } |
| | | void setPriority(uint8_t p) noexcept { m_priority = p; } |
| | |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ); |
| | | const std::vector<ValidationIssue>& CControlJob::issues(); |
| | | void clearIssues(); |
| | | |
| | | // ââ S14F9 â S14F10 çâåºç¨ç»æâ模å ââ // |
| | | struct CreateRequest { |
| | |
| | | bool pause(); // Executing -> Paused |
| | | bool resume(); // Paused -> Executing |
| | | bool complete(); // Executing/Paused -> Completed |
| | | bool abort(); // éç»æ -> Aborted |
| | | bool abort(std::string reason); // éç»æ -> Aborted |
| | | bool fail(std::string reason); // ä»»æ -> Failed |
| | | |
| | | const std::string& failReason() const noexcept { return m_failReason; } |
| | |
| | | #include "CControlJobDlg.h" |
| | | #include "afxdialogex.h" |
| | | |
| | | // ===== æ°å¢ï¼æ ååºå¤´ ===== |
| | | #include <array> |
| | | #include <string> |
| | | #include <unordered_set> |
| | | #include <algorithm> |
| | | |
| | | // ===== æ°å¢ï¼CString ç Hash/Equalï¼è·¨ ANSI/Unicode éåï¼===== |
| | | struct CStringHash { |
| | | size_t operator()(const CString& s) const noexcept { |
| | | #ifdef _UNICODE |
| | | return std::hash<std::wstring>{}(std::wstring(s.GetString())); |
| | | #else |
| | | return std::hash<std::string>{}(std::string(s.GetString())); |
| | | #endif |
| | | } |
| | | }; |
| | | struct CStringEqual { |
| | | bool operator()(const CString& a, const CString& b) const noexcept { |
| | | return a == b; |
| | | } |
| | | }; |
| | | |
| | | |
| | | // CControlJobDlg å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CControlJobDlg, CDialogEx) |
| | | |
| | | CControlJobDlg::CControlJobDlg(CWnd* pParent /*=nullptr*/) |
| | | : CDialogEx(IDD_DIALOG_CONTROL_JOB, pParent) |
| | | : CDialogEx(IDD_DIALOG_CONTROL_JOB, pParent) |
| | | { |
| | | m_pControlJob = nullptr; |
| | | } |
| | |
| | | |
| | | void CControlJobDlg::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CDialogEx::DoDataExchange(pDX); |
| | | DDX_Control(pDX, IDC_LIST1, m_listCtrl); |
| | | CDialogEx::DoDataExchange(pDX); |
| | | DDX_Control(pDX, IDC_LIST1, m_listCtrl); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CControlJobDlg, CDialogEx) |
| | | ON_WM_SIZE() |
| | | ON_BN_CLICKED(IDC_BUTTON_COMPLETION_BATH, &CControlJobDlg::OnBnClickedButtonCompletionBath) |
| | | ON_BN_CLICKED(IDC_BUTTON_RELOAD, &CControlJobDlg::OnBnClickedButtonReload) |
| | | ON_WM_TIMER() |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | |
| | | // CControlJobDlg æ¶æ¯å¤çç¨åº |
| | | BOOL CControlJobDlg::OnInitDialog() |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | CDialogEx::OnInitDialog(); |
| | | |
| | | |
| | | // labelåä½ |
| | |
| | | |
| | | // æ§ä»¶ç¶æ |
| | | Resize(); |
| | | ShowGroup1(m_pControlJob == nullptr); |
| | | ShowGroup2(m_pControlJob != nullptr); |
| | | LoadData(); |
| | | OnBnClickedButtonReload(); |
| | | SetTimer(1, 2000, nullptr); |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | void CControlJobDlg::OnSize(UINT nType, int cx, int cy) |
| | |
| | | |
| | | |
| | | // å
³éæé® |
| | | int x2 = rcClient.right - 12; |
| | | int y = rcClient.bottom - 12; |
| | | pItem = GetDlgItem(IDCANCEL); |
| | | pItem->GetClientRect(&rcItem); |
| | | pItem->MoveWindow(rcClient.right - 12 - rcItem.Width(), |
| | | pItem->MoveWindow(x2 - rcItem.Width(), |
| | | y - rcItem.Height(), |
| | | rcItem.Width(), rcItem.Height()); |
| | | x2 -= rcItem.Width(); |
| | | x2 -= 8; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_RELOAD); |
| | | pItem->GetClientRect(&rcItem); |
| | | pItem->MoveWindow(x2 - rcItem.Width(), |
| | | y - rcItem.Height(), |
| | | rcItem.Width(), rcItem.Height()); |
| | | |
| | | |
| | | // ç»æ¹æé® |
| | | pItem = GetDlgItem(IDC_BUTTON_COMPLETION_BATH); |
| | | pItem->GetClientRect(&rcItem); |
| | | pItem->MoveWindow(12, y - rcItem.Height(), |
| | | rcItem.Width(), rcItem.Height()); |
| | | y -= rcItem.Height(); |
| | | y -= 12; |
| | | |
| | | |
| | | // 线 |
| | | pItem = GetDlgItem(IDC_LINE1); |
| | |
| | | GetDlgItem(IDC_LIST1)->ShowWindow(bShow ? SW_SHOW : SW_HIDE); |
| | | } |
| | | |
| | | void CControlJobDlg::LoadData() |
| | | void CControlJobDlg::LoadData(SERVO::CControlJob* pControlJob) |
| | | { |
| | | m_listCtrl.DeleteAllItems(); |
| | | // ââ å·¥å
·ï¼æâ第ä¸åé®âå¨ parent 䏿¥æ¾åèç¹ |
| | | auto FindChildByKey = [&](CExpandableListCtrl::Node* parent, LPCTSTR key)->CExpandableListCtrl::Node* { |
| | | if (!parent) return nullptr; |
| | | for (auto& up : parent->children) { |
| | | auto* n = up.get(); |
| | | if (n && n->cols.size() > 0 && n->cols[0].CompareNoCase(key) == 0) |
| | | return n; |
| | | } |
| | | return nullptr; |
| | | }; |
| | | |
| | | if (m_pControlJob != nullptr) { |
| | | auto* root1 = m_listCtrl.InsertRoot({ m_pControlJob->id().c_str(), _T("ControlJob"), |
| | | m_pControlJob->getStateText().c_str(), _T("") }); |
| | | auto pjs = m_pControlJob->getPjs(); |
| | | // ââ å·¥å
·ï¼æåæ´æ°ãæ åå建ï¼6åï¼ |
| | | auto EnsureChild = [&](CExpandableListCtrl::Node* parent, const std::array<CString, 6>& cols)->CExpandableListCtrl::Node* { |
| | | CExpandableListCtrl::Node* n = FindChildByKey(parent, cols[0]); |
| | | if (!n) { |
| | | n = m_listCtrl.InsertChild(parent, { cols[0], cols[1], cols[2], cols[3], cols[4], cols[5] }); |
| | | } |
| | | else { |
| | | if ((int)n->cols.size() < 6) n->cols.resize(6); |
| | | for (int i = 0; i < 6; i++) if (n->cols[i] != cols[i]) n->cols[i] = cols[i]; |
| | | } |
| | | return n; |
| | | }; |
| | | |
| | | // ââ å·¥å
·ï¼å é¤ parent ä¸âæ¬æ¬¡æªåºç°âçåèç¹ï¼åºäºç¬¬ä¸åé®ï¼ |
| | | auto RemoveStaleChildren = [&](CExpandableListCtrl::Node* parent, const std::unordered_set<CString, CStringHash, CStringEqual>& keep) { |
| | | if (!parent) return; |
| | | auto& vec = parent->children; |
| | | vec.erase(std::remove_if(vec.begin(), vec.end(), [&](const std::unique_ptr<CExpandableListCtrl::Node>& up) { |
| | | auto* n = up.get(); |
| | | if (!n || n->cols.empty()) return true; // é²å¾¡ï¼æ æè¡ç´æ¥å |
| | | return keep.find(n->cols[0]) == keep.end(); |
| | | }), vec.end()); |
| | | }; |
| | | |
| | | // ââââââââââââ 1) æ æ°æ®ï¼æ¸
空并å¤ä½ç¼å ââââââââââââ |
| | | if (!pControlJob) { |
| | | m_listCtrl.ClearTree(); |
| | | m_rootNode = nullptr; |
| | | m_lastCjPtr = nullptr; |
| | | m_lastCjId.Empty(); |
| | | m_listCtrl.RebuildVisible(); |
| | | return; |
| | | } |
| | | |
| | | const CString curId = pControlJob->id().c_str(); |
| | | const bool cjChanged = (pControlJob != m_lastCjPtr) || (curId != m_lastCjId); |
| | | |
| | | // ââââââââââââ 2) CJ åäºï¼æ´æ£µé建ï¼ä¿çå±å¼æ è®°ä¸å¿
管ï¼é建å³å¯ï¼ ââââââââââââ |
| | | if (cjChanged || !m_rootNode) { |
| | | m_listCtrl.ClearTree(); |
| | | |
| | | m_rootNode = m_listCtrl.InsertRoot({ |
| | | pControlJob->id().c_str(), _T("ControlJob"), |
| | | pControlJob->getStateText().c_str(), _T(""), _T(""), |
| | | pControlJob->failReason().c_str() |
| | | }); |
| | | |
| | | auto pjs = pControlJob->getPjs(); |
| | | for (auto pj : pjs) { |
| | | auto* root2 = m_listCtrl.InsertChild(root1, {pj->id().c_str(), _T("ProcessJob"), |
| | | pj->getStateText().c_str(), pj->recipeSpec().c_str(), _T(""), _T(""), _T("") }); |
| | | auto* pjNode = m_listCtrl.InsertChild(m_rootNode, { |
| | | pj->id().c_str(), _T("ProcessJob"), |
| | | pj->getStateText().c_str(), pj->recipeSpec().c_str(), _T(""), |
| | | pj->failReason().c_str() |
| | | }); |
| | | |
| | | auto cs = pj->carriers(); |
| | | for (auto c : cs) { |
| | | for (auto g : c.contexts) { |
| | | SERVO::CGlass* pGlass = (SERVO::CGlass*)g; |
| | | if (pGlass != nullptr) { |
| | | int port, slot; |
| | | auto* pGlass = static_cast<SERVO::CGlass*>(g); |
| | | if (pGlass) { |
| | | int port = 0, slot = 0; |
| | | pGlass->getOrginPort(port, slot); |
| | | std::string carrier = c.carrierId + " / Port" + std::to_string(port + 1) + " / Slot" + std::to_string(slot + 1); |
| | | m_listCtrl.InsertChild(root2, { pGlass->getID().c_str(), _T("Glass"), |
| | | pGlass->getStateText().c_str(), _T(""), carrier.c_str(), _T("") }); |
| | | CString carrier; carrier.Format(_T("%s / Port%d / Slot%d"), |
| | | CString(c.carrierId.c_str()), port + 1, slot + 1); |
| | | |
| | | m_listCtrl.InsertChild(pjNode, { |
| | | pGlass->getID().c_str(), _T("Glass"), |
| | | pGlass->getStateText().c_str(), _T(""), |
| | | carrier, _T("") |
| | | }); |
| | | } |
| | | else { |
| | | m_listCtrl.InsertChild(root2, { "Null", _T("Glass"), _T(""), _T(""), c.carrierId.c_str(), _T("") }); |
| | | m_listCtrl.InsertChild(pjNode, { |
| | | _T("Null@") + CString(c.carrierId.c_str()), _T("Glass"), |
| | | _T(""), _T(""), CString(c.carrierId.c_str()), _T("") |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | root2->expanded = true; |
| | | pjNode->expanded = true; |
| | | } |
| | | root1->expanded = true; |
| | | m_rootNode->expanded = true; |
| | | |
| | | m_lastCjPtr = pControlJob; |
| | | m_lastCjId = curId; |
| | | |
| | | m_listCtrl.RebuildVisible(); |
| | | return; |
| | | } |
| | | |
| | | // ââââââââââââ 3) CJ æªåï¼å¢éæ´æ° ââââââââââââ |
| | | |
| | | // 3.1 æ´æ° CJ è¡ææ¬ï¼ç¶æå¯è½ååï¼ |
| | | if ((int)m_rootNode->cols.size() < 6) m_rootNode->cols.resize(6); |
| | | m_rootNode->cols[0] = pControlJob->id().c_str(); |
| | | m_rootNode->cols[1] = _T("ControlJob"); |
| | | m_rootNode->cols[2] = pControlJob->getStateText().c_str(); |
| | | // cols[3] ä¿ç为空 |
| | | // cols[4] ä¿ç为空 |
| | | m_rootNode->cols[5] = pControlJob->failReason().c_str(); |
| | | |
| | | // 3.2 忥 PJ å± |
| | | std::unordered_set<CString, CStringHash, CStringEqual> pjKeysWanted; |
| | | |
| | | auto pjs = pControlJob->getPjs(); |
| | | for (auto pj : pjs) { |
| | | CString pjId = pj->id().c_str(); |
| | | pjKeysWanted.insert(pjId); |
| | | |
| | | auto* pjNode = FindChildByKey(m_rootNode, pjId); |
| | | if (!pjNode) { |
| | | pjNode = m_listCtrl.InsertChild(m_rootNode, { |
| | | pjId, _T("ProcessJob"), |
| | | pj->getStateText().c_str(), pj->recipeSpec().c_str(), _T(""), |
| | | pj->failReason().c_str() |
| | | }); |
| | | pjNode->expanded = true; // 忬¡åºç°é»è®¤å±å¼ |
| | | } |
| | | else { |
| | | if ((int)pjNode->cols.size() < 6) pjNode->cols.resize(6); |
| | | pjNode->cols[1] = _T("ProcessJob"); |
| | | pjNode->cols[2] = pj->getStateText().c_str(); |
| | | pjNode->cols[3] = pj->recipeSpec().c_str(); |
| | | pjNode->cols[5] = pj->failReason().c_str(); |
| | | } |
| | | |
| | | // 3.3 忥 Glass å±ï¼ç¬¬ä¸åé®ï¼GlassIDï¼ç©ºå¯¹è±¡ç¨ "Null@CarrierId" é²å²çªï¼ |
| | | std::unordered_set<CString, CStringHash, CStringEqual> gKeysWanted; |
| | | |
| | | auto cs = pj->carriers(); |
| | | for (auto c : cs) { |
| | | for (auto g : c.contexts) { |
| | | auto* pGlass = static_cast<SERVO::CGlass*>(g); |
| | | if (pGlass) { |
| | | int port = 0, slot = 0; |
| | | pGlass->getOrginPort(port, slot); |
| | | CString carrier; carrier.Format(_T("%s / Port%d / Slot%d"), |
| | | CString(c.carrierId.c_str()), port + 1, slot + 1); |
| | | |
| | | CString gid = pGlass->getID().c_str(); |
| | | gKeysWanted.insert(gid); |
| | | |
| | | auto* rowG = FindChildByKey(pjNode, gid); |
| | | if (!rowG) { |
| | | m_listCtrl.InsertChild(pjNode, { |
| | | gid, _T("Glass"), |
| | | pGlass->getStateText().c_str(), _T(""), |
| | | carrier, _T("") |
| | | }); |
| | | } |
| | | else { |
| | | if ((int)rowG->cols.size() < 6) rowG->cols.resize(6); |
| | | rowG->cols[1] = _T("Glass"); |
| | | rowG->cols[2] = pGlass->getStateText().c_str(); |
| | | rowG->cols[3] = _T(""); |
| | | rowG->cols[4] = carrier; |
| | | rowG->cols[5] = _T(""); |
| | | } |
| | | } |
| | | else { |
| | | CString key = _T("Null@") + CString(c.carrierId.c_str()); |
| | | gKeysWanted.insert(key); |
| | | |
| | | auto* rowG = FindChildByKey(pjNode, key); |
| | | if (!rowG) { |
| | | m_listCtrl.InsertChild(pjNode, { |
| | | key, _T("Glass"), _T(""), _T(""), |
| | | CString(c.carrierId.c_str()), _T("") |
| | | }); |
| | | } |
| | | else { |
| | | if ((int)rowG->cols.size() < 6) rowG->cols.resize(6); |
| | | rowG->cols[1] = _T("Glass"); |
| | | rowG->cols[2] = _T(""); |
| | | rowG->cols[3] = _T(""); |
| | | rowG->cols[4] = CString(c.carrierId.c_str()); |
| | | rowG->cols[5] = _T(""); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // å 餿¬æ¬¡ä¸åå¨ç Glass åèç¹ |
| | | RemoveStaleChildren(pjNode, gKeysWanted); |
| | | } |
| | | |
| | | // å 餿¬æ¬¡ä¸åå¨ç PJ åèç¹ |
| | | RemoveStaleChildren(m_rootNode, pjKeysWanted); |
| | | |
| | | // 3.4 é建å¯è§è¡ï¼ä¸æ¹å expanded æ å¿ï¼é¿å
éªç/æå ç¶æä¸¢å¤±ï¼ |
| | | m_listCtrl.RebuildVisible(); |
| | | } |
| | | |
| | | void CControlJobDlg::OnBnClickedButtonCompletionBath() |
| | | { |
| | | if (theApp.m_model.getMaster().forceCompleteControlJob("æµè¯æå¨ç»æ¹")) { |
| | | AfxMessageBox("ç»æ¹å®æ"); |
| | | } |
| | | |
| | | OnBnClickedButtonReload(); |
| | | } |
| | | |
| | | void CControlJobDlg::OnBnClickedButtonReload() |
| | | { |
| | | auto* cj = m_pControlJob; |
| | | if (cj == nullptr) { |
| | | cj = theApp.m_model.getMaster().getControlJob(); |
| | | } |
| | | |
| | | ShowGroup1(cj == nullptr); |
| | | ShowGroup2(cj != nullptr); |
| | | GetDlgItem(IDC_BUTTON_COMPLETION_BATH)->EnableWindow(cj != nullptr); |
| | | LoadData(cj); |
| | | } |
| | | |
| | | void CControlJobDlg::OnTimer(UINT_PTR nIDEvent) |
| | | { |
| | | if (1 == nIDEvent) { |
| | | OnBnClickedButtonReload(); |
| | | } |
| | | |
| | | CDialogEx::OnTimer(nIDEvent); |
| | | } |
| | |
| | | void Resize(); |
| | | void ShowGroup1(BOOL bShow); |
| | | void ShowGroup2(BOOL bShow); |
| | | void LoadData(); |
| | | void LoadData(SERVO::CControlJob* pControlJob); |
| | | |
| | | private: |
| | | SERVO::CControlJob* m_pControlJob; |
| | | CFont m_fontNoJob; |
| | | |
| | | // è®°å½ä¸ä¸æ¬¡ç CJ èº«ä»½ï¼æé/IDï¼ |
| | | SERVO::CControlJob* m_lastCjPtr = nullptr; |
| | | CString m_lastCjId; |
| | | CExpandableListCtrl::Node* m_rootNode = nullptr; |
| | | |
| | | protected: |
| | | CExpandableListCtrl m_listCtrl; |
| | |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnSize(UINT nType, int cx, int cy); |
| | | afx_msg void OnBnClickedButtonCompletionBath(); |
| | | afx_msg void OnBnClickedButtonReload(); |
| | | afx_msg void OnTimer(UINT_PTR nIDEvent); |
| | | }; |
| | |
| | | #include "CControlJobManagerDlg.h" |
| | | #include "afxdialogex.h" |
| | | #include "ToolUnits.h" |
| | | #include "RecipeManager.h" |
| | | |
| | | |
| | | bool CControlJobManagerDlg::m_bHasState = false; |
| | |
| | | else if (1 == code) { |
| | | if (contextType == 1) { |
| | | UpProcessJobId((PJWarp*)pContext); |
| | | } |
| | | else if (contextType == 2) { |
| | | UpControlJobId((SERVO::CControlJob*)pContext); |
| | | } |
| | | } |
| | | }; |
| | |
| | | SERVO::CControlJob* cj = (SERVO::CControlJob*)m_tree.GetItemData(hSel); |
| | | ASSERT(m_pages.size() == 3); |
| | | if (0 == ShowPage(2)) { |
| | | |
| | | SERVO::CControlJob* pControlJob = (SERVO::CControlJob*)m_tree.GetItemData(hSel); |
| | | m_pages[2]->SetContext(pControlJob, 2); |
| | | } |
| | | } |
| | | else if (m_tree.GetParentItem(hParent) == nullptr) { |
| | |
| | | } |
| | | } |
| | | |
| | | void CControlJobManagerDlg::UpControlJobId(SERVO::CControlJob* pControlJob) |
| | | { |
| | | // æ´æ°æ æ§ä»¶ |
| | | // éåæ ¹èç¹ |
| | | HTREEITEM hRoot = m_tree.GetRootItem(); |
| | | if (hRoot != nullptr) { |
| | | DWORD_PTR data = m_tree.GetItemData(hRoot); |
| | | if ((void*)data == pControlJob) { |
| | | m_tree.SetItemText(hRoot, pControlJob->id().c_str()); |
| | | return; // æ¾å°å°±è¿å |
| | | } |
| | | } |
| | | } |
| | | |
| | | void CControlJobManagerDlg::LoadState() |
| | | { |
| | | if (!m_bHasState) return; |
| | |
| | | |
| | | void CControlJobManagerDlg::OnBnClickedButtonBathCompletion() |
| | | { |
| | | // å
æ£æ¥å½åmaster |
| | | auto& master = theApp.m_model.getMaster(); |
| | | if (!master.canCreateControlJob()) { |
| | | AfxMessageBox("å½åMasterææªç»æ¹çJob, 请å
ç»æ¹å¤ç"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // å
åºç¨ |
| | | for (int i = 0; i < 3; i++) { |
| | | if (m_pages[i]->IsWindowVisible()) { |
| | |
| | | } |
| | | |
| | | |
| | | SERVO::CLoadPort* pPorts[4]; |
| | | pPorts[0] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT1); |
| | | pPorts[1] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT2); |
| | | pPorts[2] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT3); |
| | | pPorts[3] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT4); |
| | | |
| | | auto& master = theApp.m_model.getMaster(); |
| | | |
| | | bool bProcessStart[] = {false, false, false, false}; |
| | | std::vector<SERVO::CProcessJob*> pjs; |
| | | for (auto item : m_pjWarps) { |
| | | if (!item.addToCj) continue; |
| | |
| | | } |
| | | if (!bCheck) continue; |
| | | |
| | | |
| | | SERVO::CProcessJob* pScr = (SERVO::CProcessJob*)item.pj; |
| | | pScr->setPjWarp(item); |
| | | pScr->setLotId("LotID1"); |
| | | pScr->setProductId("ProductId1"); |
| | | pScr->setOperationId("OperationId"); |
| | | pScr->setRecipe(SERVO::RecipeMethod::NoTuning, pScr->recipeSpec()); |
| | | |
| | | SERVO::CProcessJob * pj = new SERVO::CProcessJob(pScr->id()); |
| | | pj->setPjWarp(item); |
| | | pj->setLotId("LotID1"); |
| | | pj->setProductId("ProductId1"); |
| | | pj->setOperationId("OperationId"); |
| | | pj->setRecipe(SERVO::RecipeMethod::NoTuning, pScr->recipeSpec()); |
| | | |
| | | std::vector<SERVO::CarrierSlotInfo> carriers; |
| | | SERVO::CarrierSlotInfo csi; |
| | | csi.carrierId = "Port" + std::to_string(item.port + 1); |
| | | csi.carrierId = pPorts[item.port]->getCassetteId(); |
| | | for (int i = 0; i < 8; i++) { |
| | | if (item.checkSlot[i]) { |
| | | csi.slots.push_back(i); |
| | | SERVO::CGlass* pGlass = pPorts[item.port]->getGlassFromSlot(i+1); |
| | | if (pGlass != nullptr) { |
| | | csi.slots.push_back(i + 1); |
| | | } |
| | | } |
| | | } |
| | | carriers.push_back(csi); |
| | | pj->setCarriers(carriers); |
| | | pjs.push_back(pj); |
| | | bProcessStart[item.port] = true; |
| | | |
| | | m_pControlJob->addPJ(pScr->id()); |
| | | } |
| | |
| | | return; |
| | | } |
| | | |
| | | |
| | | m_pControlJob->setPJs(pjs); |
| | | m_pControlJob->clearIssues(); |
| | | int nRet = master.setProcessJobs(pjs); |
| | | master.setControlJob(*m_pControlJob); |
| | | |
| | | // 没æé®é¢çpjè¦éæ¾ |
| | | for (auto pj : pjs) { |
| | | if (!pj->issues().empty()) { |
| | | delete pj; |
| | | } |
| | | } |
| | | pjs.clear(); |
| | | |
| | | if (nRet <= 0) { |
| | | std::string msg("忥Process Job失败!"); |
| | | for (auto pj : pjs) { |
| | | auto& issues = pj->issues(); |
| | | if (!issues.empty()) { |
| | | msg.append("\n"); |
| | | msg.append(pj->id()); |
| | | msg.append(":\n"); |
| | | for (auto i : issues) { |
| | | msg.append("["); |
| | | msg.append(std::to_string(i.code)); |
| | | msg.append("]"); |
| | | msg.append(i.text); |
| | | msg.append("\n"); |
| | | } |
| | | } |
| | | } |
| | | AfxMessageBox(msg.c_str()); |
| | | |
| | | return; |
| | | } |
| | | |
| | | nRet = master.setControlJob(*m_pControlJob); |
| | | if (nRet != 0) { |
| | | std::string msg("忥ControlJob失败!"); |
| | | auto& issues = m_pControlJob->issues(); |
| | | if (!issues.empty()) { |
| | | msg.append("\n"); |
| | | for (auto i : issues) { |
| | | msg.append("["); |
| | | msg.append(std::to_string(i.code)); |
| | | msg.append("]"); |
| | | msg.append(i.text); |
| | | msg.append("\n"); |
| | | } |
| | | } |
| | | AfxMessageBox(msg.c_str()); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // æåï¼è¦å¤æï¼åæ¥å°slotçglassä¸ï¼ç±»åç |
| | | for (int p = 0; p < 4; p++) { |
| | | if (m_pjWarps[p].port == -1) continue; |
| | | ASSERT(0 <= m_pjWarps[p].port && m_pjWarps[p].port <= 3); |
| | | |
| | | SERVO::CLoadPort* pLoadPort = pPorts[m_pjWarps[p].port]; |
| | | for (int i = 0; i < SLOT_MAX; ++i) { |
| | | SERVO::CSlot* pSlot = pLoadPort->getSlot(i); |
| | | if (!pSlot) { |
| | | continue; |
| | | } |
| | | |
| | | // 设置 Panel ID åå¾éæ¡ |
| | | SERVO::CProcessJob* pj = (SERVO::CProcessJob*)m_pjWarps[p].pj; |
| | | int nRecipeID = RecipeManager::getInstance().getIdByPPID(pj->recipeSpec()); |
| | | RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(pj->recipeSpec()); |
| | | std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList; |
| | | SERVO::CGlass* pGlass = dynamic_cast<SERVO::CGlass*>(pSlot->getContext()); |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | if (pGlass != nullptr && pJobDataS != nullptr) { |
| | | pGlass->setScheduledForProcessing(m_pjWarps[p].checkSlot[i]); |
| | | pGlass->setType(static_cast<SERVO::MaterialsType>(m_pjWarps[p].material[i])); |
| | | |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | pJobDataS->setLotId(pj->getLotId().c_str()); |
| | | pJobDataS->setProductId(pj->getProductId().c_str()); |
| | | pJobDataS->setOperationId(pj->getOperationId().c_str()); |
| | | pJobDataS->setMaterialsType(m_pjWarps[p].material[i]); |
| | | pJobDataS->setMasterRecipe(nRecipeID); |
| | | |
| | | for (const auto& info : vecRecipeInfo) { |
| | | const std::string& name = info.strDeviceName; |
| | | short nRecipeID = (short)info.nRecipeID; |
| | | |
| | | if (name == EQ_NAME_EFEM) { |
| | | pJobDataS->setDeviceRecipeId(0, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BONDER1) { |
| | | pJobDataS->setDeviceRecipeId(1, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BONDER2) { |
| | | pJobDataS->setDeviceRecipeId(2, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BAKE_COOLING) { |
| | | pJobDataS->setDeviceRecipeId(3, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_VACUUMBAKE) { |
| | | pJobDataS->setDeviceRecipeId(4, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_MEASUREMENT) { |
| | | pJobDataS->setDeviceRecipeId(5, nRecipeID); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // process start |
| | | for (int p = 0; p < 4; p++) { |
| | | if (bProcessStart[p]) { |
| | | pPorts[p]->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr); |
| | | Sleep(100); |
| | | } |
| | | } |
| | | } |
| | |
| | | bool AddPorcessJob(SERVO::CProcessJob* pj); |
| | | bool RemovePorcessJob(SERVO::CProcessJob* pj); |
| | | void UpProcessJobId(PJWarp* pjWarp); |
| | | void UpControlJobId(SERVO::CControlJob* pControlJob); |
| | | void InitData(); |
| | | void LoadState(); |
| | | void SaveState(); |
| | |
| | | m_pCclink = nullptr; |
| | | m_nBaseAlarmId = 0; |
| | | m_pArm = nullptr; |
| | | m_processState = PROCESS_STATE::Ready; |
| | | m_blockReadBit = { 0 }; |
| | | m_nTestFlag = 0; |
| | | InitializeCriticalSection(&m_criticalSection); |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void CEquipment::setProcessState(PROCESS_STATE state) |
| | | void CEquipment::setProcessState(int nSlotNo, PROCESS_STATE state) |
| | | { |
| | | m_processState = state; |
| | | onProcessStateChanged(m_processState); |
| | | if (nSlotNo <= 0 || nSlotNo > 8) return; |
| | | |
| | | m_processState[nSlotNo - 1] = state; |
| | | onProcessStateChanged(nSlotNo, m_processState[nSlotNo - 1]); |
| | | |
| | | if (m_listener.onProcessStateChanged != nullptr) { |
| | | m_listener.onProcessStateChanged(this, m_processState); |
| | | m_listener.onProcessStateChanged(this, nSlotNo, m_processState[nSlotNo - 1]); |
| | | } |
| | | } |
| | | |
| | |
| | | Unlock(); |
| | | |
| | | |
| | | if (m_processState != PROCESS_STATE::Ready) { |
| | | setProcessState(PROCESS_STATE::Ready); |
| | | if (m_processState[port] != PROCESS_STATE::Ready) { |
| | | setProcessState(port, PROCESS_STATE::Ready); |
| | | } |
| | | |
| | | if (m_listener.onDataChanged != nullptr) { |
| | |
| | | pGlass->release(); // tempFetchOutéè¦è°ç¨ä¸æ¬¡release |
| | | Unlock(); |
| | | |
| | | /* |
| | | if (m_processState != PROCESS_STATE::Processing) { |
| | | setProcessState(PROCESS_STATE::Processing); |
| | | } |
| | | */ |
| | | |
| | | if (m_listener.onDataChanged != nullptr) { |
| | | m_listener.onDataChanged(this, EDCC_STORED_JOB); |
| | |
| | | year, month, day, hour, minute, second |
| | | ); |
| | | |
| | | CGlass* pGlass = getGlassFromSlot(slotNo); |
| | | if (pGlass == nullptr) { |
| | | LOGE("<CEquipment-%s>decodeJobProcessStartReport, æ¾ä¸å°å¯¹åºglass", getName().c_str()); |
| | | } |
| | | if (slotNo <= 0 || slotNo > 8) return -1; |
| | | |
| | | if (m_processState != PROCESS_STATE::Processing) { |
| | | if (m_processState[slotNo -1] != PROCESS_STATE::Processing) { |
| | | Lock(); |
| | | m_svDatas.clear(); |
| | | Unlock(); |
| | | setProcessState(PROCESS_STATE::Processing); |
| | | setProcessState(slotNo, PROCESS_STATE::Processing); |
| | | } |
| | | |
| | | |
| | |
| | | ); |
| | | |
| | | |
| | | if (m_processState != PROCESS_STATE::Complete) { |
| | | setProcessState(PROCESS_STATE::Complete); |
| | | } |
| | | |
| | | CGlass* pGlass = getGlassFromSlot(slotNo); |
| | | if (m_processState[slotNo - 1] != PROCESS_STATE::Complete) { |
| | | setProcessState(slotNo, PROCESS_STATE::Complete); |
| | | } |
| | | |
| | | if (pGlass == nullptr) { |
| | | LOGE("<CEquipment-%s>decodeJobProcessEndReport, æ¾ä¸å°å¯¹åºglass", getName().c_str()); |
| | | } |
| | |
| | | if (pJs->getCassetteSequenceNo() == cassetteNo |
| | | && pJs->getJobSequenceNo() == jobSequenceNo) { |
| | | pGlass->processEnd(m_nID, getSlotUnit(slotNo)); |
| | | if (m_processState != PROCESS_STATE::Complete) { |
| | | setProcessState(PROCESS_STATE::Complete); |
| | | } |
| | | } |
| | | else { |
| | | LOGE("<CEquipment-%s>decodeJobProcessEndReport, jobSequenceNoæjobSequenceNoä¸å¹é
", |
| | |
| | | return 0; |
| | | } |
| | | |
| | | int CEquipment::onProcessStateChanged(PROCESS_STATE state) |
| | | int CEquipment::onProcessStateChanged(int nSlotNo, PROCESS_STATE state) |
| | | { |
| | | return 0; |
| | | } |
| | |
| | | typedef std::function<void(void* pEiuipment, void* pReport)> ONVCREVENTREPORT; |
| | | typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB)> ONPREFETCHEDOUTJOB; |
| | | typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB, short& putSlot)> ONPRESTOREDJOB; |
| | | typedef std::function<void(void* pEiuipment, PROCESS_STATE state)> ONPROCESSSTATE; |
| | | typedef std::function<void(void* pEiuipment, int nSlotNo, PROCESS_STATE state)> ONPROCESSSTATE; |
| | | typedef std::function<void(void* pEiuipment, short scanMap, short downMap)> ONMAPMISMATCH; |
| | | typedef std::function<void(void* pEiuipment, short status, __int64 data)> ONPORTSTATUSCHANGED; |
| | | |
| | |
| | | virtual int onProcessData(CProcessData* pProcessData); |
| | | virtual int onSendAble(int port); |
| | | virtual int onReceiveAble(int port); |
| | | virtual int onProcessStateChanged(PROCESS_STATE state); |
| | | virtual int onProcessStateChanged(int nSlotNo, PROCESS_STATE state); |
| | | virtual int getIndexerOperationModeBaseValue(); |
| | | virtual bool isSlotProcessed(int slot) { return true; }; |
| | | bool isAlarmStep(SERVO::CStep* pStep); |
| | |
| | | int decodeJobProcessStartReport(CStep* pStep, const char* pszData, size_t size); |
| | | int decodeJobProcessEndReport(CStep* pStep, const char* pszData, size_t size); |
| | | BOOL compareJobData(CJobDataB* pJobDataB, CJobDataS* pJobDataS); |
| | | void setProcessState(PROCESS_STATE state); |
| | | void setProcessState(int nSlotNo, PROCESS_STATE state); |
| | | float toFloat(const char* pszAddr); |
| | | |
| | | protected: |
| | |
| | | int m_nBaseAlarmId; |
| | | CRecipesManager m_recipesManager; |
| | | CSlot m_slot[SLOT_MAX]; |
| | | PROCESS_STATE m_processState; |
| | | PROCESS_STATE m_processState[SLOT_MAX] = { PROCESS_STATE::Ready }; |
| | | std::vector<SERVO::CSVData> m_svDatas; |
| | | |
| | | private: |
| | |
| | | m_rowColors.resize(GetItemCount()); |
| | | |
| | | SetRedraw(TRUE); |
| | | Invalidate(); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | // ââ ä¼ååçå±å¼/æ¶èµ·ï¼å±é¨æå
¥/å é¤ï¼ä¸å
¨é RebuildVisible ââ // |
| | | void CExpandableListCtrl::Expand(Node* n) |
| | | { |
| | | if (!n || n->children.empty()) return; |
| | | if (!n->expanded) { n->expanded = true; RebuildVisible(); } |
| | | if (n->expanded) return; |
| | | |
| | | // æ¬å°å·¥å
·ï¼æ¾èç¹å¨ m_visible ä¸çè¡å· |
| | | auto VisibleIndexOf = [&](Node* x)->int { |
| | | for (int i = 0; i < (int)m_visible.size(); ++i) |
| | | if (m_visible[i] == x) return i; |
| | | return -1; |
| | | }; |
| | | // é彿¶éâåºå½å¯è§âçåæ ï¼å expanded å½±åï¼ |
| | | std::vector<Node*> toInsert; |
| | | std::function<void(Node*)> CollectExpandedSubtree = [&](Node* x) { |
| | | if (!x) return; |
| | | for (auto& up : x->children) { |
| | | Node* ch = up.get(); |
| | | toInsert.push_back(ch); |
| | | if (ch->expanded && !ch->children.empty()) |
| | | CollectExpandedSubtree(ch); |
| | | } |
| | | }; |
| | | // ä» pos èµ·æå
¥ nodesï¼å¯¹é½ m_visible / ListCtrl / m_rowColors |
| | | auto InsertRowsAt = [&](int pos, const std::vector<Node*>& nodes) { |
| | | if (nodes.empty()) return; |
| | | const int colCount = GetHeaderCtrl() ? GetHeaderCtrl()->GetItemCount() : 1; |
| | | |
| | | SetRedraw(FALSE); |
| | | |
| | | // 1) å
æ m_visible |
| | | m_visible.insert(m_visible.begin() + pos, nodes.begin(), nodes.end()); |
| | | |
| | | // 2) åæ ListCtrl |
| | | for (int i = 0; i < (int)nodes.size(); ++i) { |
| | | Node* cur = nodes[i]; |
| | | LVITEM lvi{}; lvi.mask = LVIF_TEXT; |
| | | lvi.iItem = pos + i; |
| | | lvi.iSubItem = 0; |
| | | lvi.pszText = const_cast<LPTSTR>((LPCTSTR)(cur->cols.empty() ? _T("") : cur->cols[0])); |
| | | InsertItem(&lvi); |
| | | |
| | | for (int col = 1; col < colCount; ++col) { |
| | | CString txt = (col < (int)cur->cols.size()) ? cur->cols[col] : _T(""); |
| | | SetItemText(pos + i, col, txt); |
| | | } |
| | | } |
| | | |
| | | // 3) è¡å·é¢è²æ°ç»åæ¥æå
¥é»è®¤è² |
| | | m_rowColors.insert(m_rowColors.begin() + pos, nodes.size(), RowColor{}); |
| | | |
| | | SetRedraw(TRUE); |
| | | Invalidate(FALSE); |
| | | }; |
| | | |
| | | // ââ æ è®°å±å¼ |
| | | n->expanded = true; |
| | | |
| | | // ââ å¨ UI éæå
¥å
¶âåºå½å¯è§âçåæ |
| | | const int pos = VisibleIndexOf(n); |
| | | if (pos < 0) { RebuildVisible(); return; } |
| | | |
| | | CollectExpandedSubtree(n); |
| | | InsertRowsAt(pos + 1, toInsert); |
| | | } |
| | | |
| | | void CExpandableListCtrl::Collapse(Node* n) |
| | | { |
| | | if (!n || n->children.empty()) return; |
| | | if (n->expanded) { n->expanded = false; RebuildVisible(); } |
| | | if (!n->expanded) return; |
| | | |
| | | // æ¬å°å·¥å
·ï¼æ¾èç¹è¡å· |
| | | auto VisibleIndexOf = [&](Node* x)->int { |
| | | for (int i = 0; i < (int)m_visible.size(); ++i) |
| | | if (m_visible[i] == x) return i; |
| | | return -1; |
| | | }; |
| | | // 计ç®âå½åå¯è§çææå代æ°éâï¼åºäº level éåå¤æï¼ |
| | | auto CountDescendantsInVisible = [&](Node* x)->int { |
| | | if (!x) return 0; |
| | | const int start = VisibleIndexOf(x); |
| | | if (start < 0) return 0; |
| | | const int baseLevel = x->level; |
| | | int cnt = 0; |
| | | for (int i = start + 1; i < (int)m_visible.size(); ++i) { |
| | | if (!m_visible[i]) break; |
| | | if (m_visible[i]->level <= baseLevel) break; |
| | | ++cnt; |
| | | } |
| | | return cnt; |
| | | }; |
| | | // ä» UI å é¤ pos å¼å§ç count è¡ï¼å¹¶åæ¥ m_visible/m_rowColors |
| | | auto DeleteRowsAt = [&](int pos, int count) { |
| | | if (count <= 0) return; |
| | | |
| | | SetRedraw(FALSE); |
| | | |
| | | // å ListCtrlï¼ä¸ç´å posï¼å 为å ä¸è¡ååç»ä¸ç§» |
| | | for (int i = 0; i < count; ++i) { |
| | | DeleteItem(pos); |
| | | } |
| | | // å m_visible |
| | | m_visible.erase(m_visible.begin() + pos, m_visible.begin() + pos + count); |
| | | // å é¢è² |
| | | if (pos >= 0 && pos <= (int)m_rowColors.size()) { |
| | | int end = min((int)m_rowColors.size(), pos + count); |
| | | m_rowColors.erase(m_rowColors.begin() + pos, m_rowColors.begin() + end); |
| | | } |
| | | |
| | | SetRedraw(TRUE); |
| | | Invalidate(FALSE); |
| | | }; |
| | | |
| | | // ââ æ è®°æ¶èµ· |
| | | n->expanded = false; |
| | | |
| | | // ââ åªå é¤å
¶âå½åå¯è§âçææå代 |
| | | const int pos = VisibleIndexOf(n); |
| | | if (pos < 0) { RebuildVisible(); return; } |
| | | |
| | | const int cnt = CountDescendantsInVisible(n); |
| | | if (cnt > 0) { |
| | | DeleteRowsAt(pos + 1, cnt); |
| | | } |
| | | } |
| | | |
| | | void CExpandableListCtrl::Toggle(Node* n) |
| | | { |
| | | if (!n || n->children.empty()) return; |
| | | n->expanded = !n->expanded; |
| | | RebuildVisible(); |
| | | if (n->expanded) Collapse(n); |
| | | else Expand(n); |
| | | } |
| | | |
| | | CExpandableListCtrl::Node* CExpandableListCtrl::GetNodeByVisibleIndex(int i) const |
| | |
| | | for (int i = 0; i < (int)m_visible.size(); ++i) { |
| | | if (m_visible[i] == n) { |
| | | RedrawItems(i, i); |
| | | UpdateWindow(); |
| | | return; |
| | | } |
| | | } |
| | |
| | | for (int i = 0; i < (int)m_visible.size(); ++i) { |
| | | if (m_visible[i] == n) { |
| | | RedrawItems(i, i); |
| | | UpdateWindow(); |
| | | return; |
| | | } |
| | | } |
| | |
| | | m_rowColors[row] = rc; |
| | | |
| | | RedrawItems(row, row); |
| | | UpdateWindow(); |
| | | } |
| | | |
| | | CRect CExpandableListCtrl::expanderRectForRow(int row) const |
| | |
| | | |
| | | // ââ è¥ç¹å»å°éè¦âå
¨ææ¾ç¤ºâçåï¼ååç¶çªå£åéèªå®ä¹éç¥ ââ // |
| | | if (!m_popupCols.empty()) { |
| | | LPNMITEMACTIVATE pia = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); |
| | | LPNMITEMACTIVATE pia2 = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); |
| | | |
| | | // ç¨ SubItemHitTest æ´ç²¾åæ¿å°å |
| | | LVHITTESTINFO ht{}; |
| | | ht.pt = pia->ptAction; |
| | | ht.pt = pia2->ptAction; |
| | | int hit = SubItemHitTest(&ht); |
| | | if (hit >= 0 && ht.iItem >= 0 && ht.iSubItem >= 0) { |
| | | const int row = ht.iItem; |
| | |
| | | DeleteAllItems(); |
| | | SetRedraw(TRUE); |
| | | |
| | | Invalidate(); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CExpandableListCtrl::SetPopupFullTextColumns(const std::vector<int>& cols) |
| | |
| | | const int kPadding = 8; // é¢çä¸ç¹è¾¹è·/çç¥å·ä½é |
| | | return sz.cx > (rcCell.Width() - kPadding); |
| | | } |
| | | |
| | | |
| | |
| | | #include "stdafx.h" |
| | | #include "CGlass.h" |
| | | #include "Log.h" |
| | | |
| | | |
| | | namespace SERVO { |
| | |
| | | return "Queued"; |
| | | break; |
| | | case SERVO::GlsState::Completed: |
| | | return "Queued"; |
| | | return "Completed"; |
| | | break; |
| | | case SERVO::GlsState::Aborted: |
| | | return "Aborted"; |
| | |
| | | |
| | | |
| | | namespace SERVO { |
| | | static inline int64_t now_ms_epoch() { |
| | | using namespace std::chrono; |
| | | return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); |
| | | } |
| | | |
| | | CMaster* g_pMaster = NULL; |
| | | |
| | | unsigned __stdcall DispatchThreadFunction(LPVOID lpParam) |
| | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // 读ç¼åæ°æ® |
| | | readCache(); |
| | | loadState(); |
| | | |
| | | |
| | | // 宿¶å¨ |
| | |
| | | } |
| | | m_listEquipment.clear(); |
| | | |
| | | |
| | | if (m_pCollector != nullptr) { |
| | | m_pCollector->stopLoop(); |
| | | delete m_pCollector; |
| | | m_pCollector = nullptr; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | |
| | | |
| | | // æ¹å¤ç模å¼ï¼æç»ä»¥æ¤ä¸ºåï¼ä½å
ä¿çä¹åçåçæ¨¡å¼ |
| | | else if (m_state == MASTERSTATE::RUNNING_BATCH) { |
| | | // é¦éæ£æ¥ææ²¡æCControlJob, ç¶æç |
| | | if (m_pControlJob == nullptr) { |
| | | // 1) æ§å¶ä½ä¸çå½å¨æä¿é |
| | | if (m_pControlJob == nullptr) { unlock(); continue; } |
| | | CJState cjst = m_pControlJob->state(); |
| | | if (cjst == CJState::Completed || cjst == CJState::Aborted || cjst == CJState::Failed) { |
| | | unlock(); |
| | | continue; |
| | | } |
| | | CJState state = m_pControlJob->state(); |
| | | if (state == CJState::Completed || state == CJState::Aborted || state == CJState::Failed) { |
| | | // ConrolJpb已宿 |
| | | LOGE("<Master>ControlJobå·²ç»å®ææå¤±è´¥ä¸æ"); |
| | | unlock(); |
| | | continue; |
| | | } |
| | | |
| | | |
| | | if (m_pControlJob->state() == CJState::NoState) { |
| | | if (cjst == CJState::NoState) { |
| | | LOGI("<Master>ControlJobå·²ç»è¿å
¥åé"); |
| | | m_pControlJob->queue(); |
| | | } |
| | | if (m_pControlJob->state() == CJState::Queued) { |
| | | LOGI("<Master>ControlJobå·²ç»å¯å¨"); |
| | | m_pControlJob->start(); |
| | | |
| | | if (m_listener.onCjStart != nullptr) { |
| | | m_listener.onCjStart(this, m_pControlJob); |
| | | } |
| | | if (m_listener.onCjStart) m_listener.onCjStart(this, m_pControlJob); |
| | | } |
| | | if (m_pControlJob->state() == CJState::Paused) { |
| | | LOGI("<Master>ControlJobå·²ç»æ¢å¤è¿è¡"); |
| | | m_pControlJob->resume(); |
| | | } |
| | | |
| | | |
| | | // 妿å½åæªéæ©CProcessJob, éæ©ä¸ä¸ª |
| | | // 2) è¥å½åæ PJï¼åéæ©ä¸ä¸ªå¹¶ä¸æ¥ |
| | | if (m_inProcesJobs.empty()) { |
| | | auto pj = acquireNextProcessJob(); |
| | | if (pj != nullptr) { |
| | | if (auto pj = acquireNextProcessJob()) { |
| | | m_inProcesJobs.push_back(pj); |
| | | |
| | | // è¿é䏿¥PJ Startäºä»¶ |
| | | if (m_listener.onPjStart != nullptr) { |
| | | m_listener.onPjStart(this, pj); |
| | | } |
| | | if (m_listener.onPjStart) m_listener.onPjStart(this, pj); |
| | | } |
| | | } |
| | | if (m_inProcesJobs.empty()) { |
| | |
| | | continue; |
| | | } |
| | | |
| | | // 妿å½å没æGlass, éæ© |
| | | // 3) è¥éåæ Glassï¼æåå°çå¾
éå |
| | | if (m_queueGlasses.empty()) { |
| | | int nCount = acquireGlassToQueue(); |
| | | LOGI("<Master>å·²å å
¥ %d åGlasså°å·¥èºåéï¼", nCount); |
| | | if (nCount > 0) { |
| | | LOGI("<Master>å·²å å
¥ %d åGlasså°å·¥èºåéï¼", nCount); |
| | | } |
| | | } |
| | | |
| | | |
| | | // æ£æµå¤ærobotç¶æ |
| | | // 4) æºå¨äººç¶æ |
| | | RMDATA& rmd = pEFEM->getRobotMonitoringData(); |
| | | if (rmd.status != ROBOT_STATUS::Idle && rmd.status != ROBOT_STATUS::Run) { |
| | | unlock(); |
| | | continue; |
| | | unlock(); continue; |
| | | } |
| | | |
| | | // 5) æ£å¨æ§è¡ç RobotTask å
让å®è·å®ä¸æ |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | if (m_pActiveRobotTask->isPicked()) { |
| | | m_pActiveRobotTask->place(); |
| | | } |
| | | unlock(); |
| | | // æ£æµå°å½åææ£å¨ä¸åçä»»å¡ï¼ç¡®ä¿å½åä»»å¡å®ææä¸æ¢åç»§ç» |
| | | // LOGI("æ£æµå°å½åææ£å¨ä¸åçä»»å¡ï¼ç¡®ä¿å½åä»»å¡å®ææä¸æ¢åç»§ç»..."); |
| | | unlock(); // çå½åä»»å¡å®ææä¸æ¢åç»§ç» |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // æ¤å¤æ£æµä¼å
ç±»å忬¡è¦ç±»åï¼G1æG2ï¼ |
| | | // 妿å
¶ä¸ä¸Bonderæå个ç»çï¼ä¼å
åå®çé
对类åï¼å¦åæ æè°äº |
| | | primaryType = MaterialsType::G1; |
| | | secondaryType = MaterialsType::G2; |
| | | if ((!pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1)) |
| | | && (!pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) { |
| | | // 妿G1åG2齿»¡äºï¼é£å°±çAligner, 妿Aligneræç»ç为G1, ååG2 |
| | | CGlass* pGlass = pAligner->getGlassFromSlot(1); |
| | | if (pGlass != nullptr && pGlass->getType() == MaterialsType::G1) { |
| | | primaryType = MaterialsType::G2; |
| | | secondaryType = MaterialsType::G1; |
| | | // 6) ââå
³é®ï¼å
¨å±ç»è®¡ G1/G2 ä¸ç»æ°é¨éï¼ä¸åç忝坹é½ï¼ââ |
| | | auto countG1G2 = [&]() { |
| | | int g1 = 0, g2 = 0; |
| | | if (pBonder1->slotHasGlass(0)) g2++; |
| | | if (pBonder1->slotHasGlass(1)) g1++; |
| | | if (pBonder2->slotHasGlass(0)) g2++; |
| | | if (pBonder2->slotHasGlass(1)) g1++; |
| | | if (pFliper->slotHasGlass(0)) g2++; |
| | | if (pVacuumBake->slotHasGlass(0)) g1++; |
| | | if (pVacuumBake->slotHasGlass(1)) g1++; |
| | | if (auto g = pAligner->getGlassFromSlot(0)) { |
| | | auto t = g->getType(); |
| | | if (t == MaterialsType::G1) g1++; else if (t == MaterialsType::G2) g2++; |
| | | } |
| | | } |
| | | else if ((pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1)) |
| | | || (pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) { |
| | | primaryType = MaterialsType::G2; |
| | | secondaryType = MaterialsType::G1; |
| | | } |
| | | return std::pair<int, int>(g1, g2); |
| | | }; |
| | | |
| | | int g1Count = 0, g2Count = 0; |
| | | std::tie(g1Count, g2Count) = countG1G2(); |
| | | int nGlassGroup = min(g1Count, g2Count); |
| | | int nExtraType = (g1Count == g2Count ? 0 : (g1Count > g2Count ? 1 : 2)); |
| | | |
| | | // Measurement -> LoadPort |
| | | // primary/secondary ç»ä¸å®ä¹ï¼secondary é»è®¤ G0ï¼ |
| | | MaterialsType primaryType = MaterialsType::G1; |
| | | MaterialsType secondaryType = MaterialsType::G0; |
| | | if (nExtraType == 0) primaryType = MaterialsType::G2; // ä¸åç忝ä¸è´ |
| | | else primaryType = MaterialsType::G1; |
| | | |
| | | // ç»æ°é¨éï¼â¥2 ç»æ¶ä¸åä» LP ä¸çï¼é¿å
å 积ï¼ä¸åçä¸è´ï¼ |
| | | bool blockLoadFromLP = (nGlassGroup >= 2); |
| | | |
| | | // 7) Measurement -> LoadPortï¼åºå®ï¼G1 ä¼å
å LPï¼ |
| | | if (rmd.armState[0] || rmd.armState[1]) { |
| | | LOGD("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("ä¸å¯ç¨") : _T("å¯ç¨"), |
| | | LOGD("Arm1 %s, Arm2 %s.", |
| | | rmd.armState[0] ? _T("ä¸å¯ç¨") : _T("å¯ç¨"), |
| | | rmd.armState[1] ? _T("ä¸å¯ç¨") : _T("å¯ç¨")); |
| | | } |
| | | for (int s = 0; s < 4; s++) { |
| | |
| | | if (!rmd.armState[0] && pLoadPorts[s]->isEnable() |
| | | && (pt == PortType::Unloading || pt == PortType::Both) |
| | | && pLoadPorts[s]->getPortStatus() == PORT_INUSE) { |
| | | m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType); |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | goto BATCH_PORT_PUT; |
| | | } |
| | | m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], MaterialsType::G1, secondaryType); |
| | | if (m_pActiveRobotTask != nullptr) { goto BATCH_PORT_PUT; } |
| | | } |
| | | } |
| | | |
| | | BATCH_PORT_PUT: |
| | | BATCH_PORT_PUT: |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | |
| | | |
| | | // Measurement NG -> LoadPort |
| | | // NGååä½ |
| | | // 8) Measurement NG -> LoadPortï¼åä½åéï¼ |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // BakeCooling ->Measurement |
| | | // 9) BakeCooling -> Measurement |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bakecooling_to_measurement(pBakeCooling, pMeasurement); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // BakeCoolingå
é¨ |
| | | // Bake -> Cooling |
| | | // 10) BakeCooling å
é¨ï¼Bake -> Coolingï¼ |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bake_to_cooling(pBakeCooling); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Bonder -> BakeCooling |
| | | // 11) Bonder -> BakeCooling |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder1, pBakeCooling); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder2, pBakeCooling); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | // 12) Fliper(G2) -> Bonderï¼åç½®ï¼VacuumBake æ processed G1ï¼è¾åº G2 å° Bonder slot0ï¼ |
| | | if (auto pSrcSlot = pVacuumBake->getProcessedSlot(MaterialsType::G1)) { |
| | | if (!rmd.armState[1] && pBonder1->canPlaceGlassInSlot(0)) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, MaterialsType::G2, MaterialsType::G0, 2); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | if (!rmd.armState[1] && pBonder2->canPlaceGlassInSlot(0)) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, MaterialsType::G2, MaterialsType::G0, 2); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | } |
| | | |
| | | // Fliper(G2) -> Bonder |
| | | auto pSrcSlot = pVacuumBake->getProcessedSlot(primaryType); |
| | | if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, primaryType, secondaryType, 2); |
| | | // 13) VacuumBake(G1) -> Bonderï¼æ§½çº§å¤å®ï¼slot0(G2) å·²æä¸ slot1(G1) ä¸ºç©ºï¼ |
| | | if (!rmd.armState[0] && pBonder1->slotHasGlass(0) && !pBonder1->slotHasGlass(1)) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, primaryType, secondaryType, 2); |
| | | if (!rmd.armState[0] && pBonder2->slotHasGlass(0) && !pBonder2->slotHasGlass(1)) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // VacuumBake(G1) -> Bonder |
| | | if (!rmd.armState[0] && !pBonder1->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, primaryType, secondaryType); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | if (!rmd.armState[0] && !pBonder2->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, primaryType, secondaryType); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Aligner -> Fliper(G2) |
| | | // Aligner -> VacuumBake(G1) |
| | | // 14) Aligner -> Fliper(G2) 以å -> VacuumBake(G1)ï¼åºå®æ å°ï¼ |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pFliper, primaryType, secondaryType); |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pFliper, MaterialsType::G2, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, primaryType, secondaryType); |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Aligner -> LoadPort |
| | | // 15) Aligner -> LoadPortï¼restoreï¼ |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | // 16) LoadPort -> Alignerï¼åç»æ°é¨éæ§å¶ï¼ç»ä¸ buddy/ç¶ææ¶åºï¼ |
| | | if (blockLoadFromLP) { unlock(); continue; } |
| | | |
| | | // LoadPort -> Aligner |
| | | for (int s = 0; s < 4; s++) { |
| | | PortType pt = pLoadPorts[s]->getPortType(); |
| | | if (!rmd.armState[0] && pLoadPorts[s]->isEnable() |
| | | && (pt == PortType::Loading || pt == PortType::Both) |
| | | && pLoadPorts[s]->getPortStatus() == PORT_INUSE) { |
| | | m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, m_bJobMode); |
| | | |
| | | m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode); |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext(); |
| | | auto* pGlass = static_cast<CGlass*>(m_pActiveRobotTask->getContext()); |
| | | if (pGlass->getBuddy() != nullptr) { |
| | | delete m_pActiveRobotTask; |
| | | m_pActiveRobotTask = nullptr; |
| | | delete m_pActiveRobotTask; m_pActiveRobotTask = nullptr; |
| | | continue; |
| | | } |
| | | |
| | | pEFEM->setContext(pGlass); |
| | | // ç»ä¸ï¼queue -> start -> setContext -> move queueâinProcess -> onPanelStart |
| | | pGlass->queue(); |
| | | pGlass->start(); |
| | | pEFEM->setContext(pGlass); |
| | | |
| | | bool bMoved = glassFromQueueToInPorcess(pGlass); |
| | | if (bMoved) { |
| | | LOGI("<Master>Glass(%s)ä»çå¾
åéå°å·¥èºåé转移æå.", |
| | | pGlass->getID().c_str()); |
| | | LOGI("<Master>Glass(%s)ä»çå¾
åéå°å·¥èºåé转移æå.", pGlass->getID().c_str()); |
| | | } |
| | | else { |
| | | LOGE("<Master>Glass(%s)ä»çå¾
åéå°å·¥èºåé转移失败.", |
| | | pGlass->getID().c_str()); |
| | | LOGE("<Master>Glass(%s)ä»çå¾
åéå°å·¥èºåé转移失败.", pGlass->getID().c_str()); |
| | | } |
| | | |
| | | // è¿é䏿¥Panel Startäºä»¶ |
| | | if (m_listener.onPanelStart != nullptr) { |
| | | m_listener.onPanelStart(this, pGlass); |
| | | } |
| | | |
| | | if (m_listener.onPanelStart) m_listener.onPanelStart(this, pGlass); |
| | | goto BATCH_PORT_GET; |
| | | } |
| | | } |
| | | } |
| | | |
| | | BATCH_PORT_GET: |
| | | BATCH_PORT_GET: |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | |
| | | |
| | | unlock(); |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // åä¼ æ¨¡å¼è°åº¦é»è¾ |
| | | else if (m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) { |
| | |
| | | if (m_listener.onCjEnd != nullptr) { |
| | | m_listener.onCjEnd(this, pJob); |
| | | } |
| | | |
| | | completeControlJob(); |
| | | } |
| | | } |
| | | } |
| | |
| | | unlock(); |
| | | } |
| | | }; |
| | | listener.onProcessStateChanged = [&](void* pEquipment, PROCESS_STATE state) -> void { |
| | | listener.onProcessStateChanged = [&](void* pEquipment, int slotNo, PROCESS_STATE state) -> void { |
| | | ASSERT(1 <= slotNo && slotNo <= 8); |
| | | int eqid = ((CEquipment*)pEquipment)->getID(); |
| | | CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(slotNo); |
| | | LOGI("<Master>onProcessStateChanged<%d>", (int)state); |
| | | if (state == PROCESS_STATE::Processing) { |
| | | if (pGlass != nullptr) { |
| | | m_pCollector->batchStart(eqid, |
| | | pGlass->getID().c_str(), 10 * 60 * 1000ULL); |
| | | } |
| | | } |
| | | else if (state == PROCESS_STATE::Complete) { |
| | | m_pCollector->batchStop(eqid); |
| | | } |
| | | }; |
| | | listener.onMapMismatch = [&](void* pEquipment, short scanMap, short downMap) { |
| | | LOGE("<Master-%s>Port InUse, map(%d!=%d)ä¸ä¸è´ï¼è¯·æ£æ¥ã", |
| | |
| | | for (auto pj : pjs) { |
| | | auto carrier = pj->getCarrier(pPort->getCassetteId()); |
| | | if (carrier != nullptr) { |
| | | carrier->contexts.clear(); |
| | | for (auto slot : carrier->slots) { |
| | | CGlass* pGlass = pPort->getGlassFromSlot(slot); |
| | | carrier->contexts.push_back((void*)pGlass); |
| | | if (pGlass != nullptr) { |
| | | pGlass->setProcessJob(pj); |
| | | |
| | | PJWarp& jpWarp = pj->getPjWarp(); |
| | | int nRecipeID = RecipeManager::getInstance().getIdByPPID(pj->recipeSpec()); |
| | | RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(pj->recipeSpec()); |
| | | std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList; |
| | | |
| | | pGlass->setScheduledForProcessing(jpWarp.checkSlot[slot-1]); |
| | | pGlass->setType(static_cast<SERVO::MaterialsType>(jpWarp.material[slot-1])); |
| | | |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | if (pJobDataS != nullptr) { |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | pJobDataS->setLotId(pj->getLotId().c_str()); |
| | | pJobDataS->setProductId(pj->getProductId().c_str()); |
| | | pJobDataS->setOperationId(pj->getOperationId().c_str()); |
| | | pJobDataS->setMaterialsType(jpWarp.material[slot - 1]); |
| | | pJobDataS->setMasterRecipe(nRecipeID); |
| | | for (const auto& info : vecRecipeInfo) { |
| | | const std::string& name = info.strDeviceName; |
| | | short nRecipeID = (short)info.nRecipeID; |
| | | |
| | | if (name == EQ_NAME_EFEM) { |
| | | pJobDataS->setDeviceRecipeId(0, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BONDER1) { |
| | | pJobDataS->setDeviceRecipeId(1, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BONDER2) { |
| | | pJobDataS->setDeviceRecipeId(2, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_BAKE_COOLING) { |
| | | pJobDataS->setDeviceRecipeId(3, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_VACUUMBAKE) { |
| | | pJobDataS->setDeviceRecipeId(4, nRecipeID); |
| | | } |
| | | else if (name == EQ_NAME_MEASUREMENT) { |
| | | pJobDataS->setDeviceRecipeId(5, nRecipeID); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | if (m_listener.onLoadPortStatusChanged != nullptr) { |
| | |
| | | std::vector<CParam> params; |
| | | ((CEquipment*)pEquipment)->parsingSVData((const char*)rawData.data(), rawData.size(), params); |
| | | |
| | | |
| | | // 以ä¸å å
¥å°æ²çº¿æ°æ®ä¸ |
| | | const int64_t ts = now_ms_epoch(); |
| | | int eqid = ((CEquipment*)pEquipment)->getID(); |
| | | if (eqid == EQ_ID_Bonder1 || eqid == EQ_ID_Bonder2) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(7).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(8).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(9).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(10).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 13, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 14, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 15, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 16, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | else if (eqid == EQ_ID_VACUUMBAKE) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(7).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(10).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 13, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 14, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | else if (eqid == EQ_ID_BAKE_COOLING) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | |
| | | |
| | | // 以䏿¯è¾åºæµè¯ |
| | | std::string strOut; |
| | | char szBuffer[256]; |
| | | for (auto p : params) { |
| | |
| | | |
| | | |
| | | // æ¨¡ææµè¯ |
| | | /* |
| | | static int aaa = 0; |
| | | aaa++; |
| | | if (aaa % 30 == 0) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | */ |
| | | } |
| | | |
| | | void CMaster::connectEquipments() |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void CMaster::setPortType(unsigned int index, BOOL enable, int type, int mode, |
| | | int cassetteType, int transferMode, BOOL autoChangeEnable) |
| | | void CMaster::setPortType(unsigned int index, int type) |
| | | { |
| | | ASSERT(index < 4); |
| | | int eqid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4}; |
| | | CLoadPort* pPort = (CLoadPort*)getEquipment(eqid[index]); |
| | | pPort->localSetPortType((SERVO::PortType)type); |
| | | } |
| | | |
| | | void CMaster::setPortTypeEx(unsigned int index, BOOL enable, int type, int mode, |
| | | int cassetteType, int transferMode, BOOL autoChangeEnable) |
| | | { |
| | | ASSERT(index < 4); |
| | | int eqid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4 }; |
| | | CLoadPort* pPort = (CLoadPort*)getEquipment(eqid[index]); |
| | | pPort->localEanblePort(enable); |
| | | pPort->localSetPortType((SERVO::PortType)type); |
| | |
| | | temp.push_back(p); |
| | | } |
| | | } |
| | | |
| | | m_processJobs = temp; |
| | | |
| | | |
| | | // æ´æ°context |
| | | std::vector<uint8_t> newSlots; |
| | | std::vector<void*> newContexts; |
| | | for (auto pj : m_processJobs) { |
| | | for (auto& c : pj->carriers()) { |
| | | auto pPort = getPortWithCarrierId(c.carrierId); |
| | | if (pPort == nullptr) continue; |
| | | |
| | | for (auto s : c.slots) { |
| | | auto pGlass = pPort->getGlassFromSlot(s); |
| | | if (pGlass == nullptr) continue; |
| | | |
| | | newSlots.push_back(s); |
| | | newContexts.push_back(pGlass); |
| | | } |
| | | |
| | | pj->setCarrierSlotsAndContexts(c.carrierId, newSlots, newContexts); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | this->saveState(); |
| | | |
| | | return (int)m_processJobs.size(); |
| | |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::loadState(const std::string& path) |
| | | bool CMaster::loadState() |
| | | { |
| | | // ä¿åæä»¶è·¯å¾ |
| | | m_strStatePath = path; |
| | | |
| | | |
| | | std::ifstream ifs(path, std::ios::binary); |
| | | std::ifstream ifs(m_strStatePath, std::ios::binary); |
| | | if (!ifs) return false; |
| | | |
| | | // æä»¶å¤´ |
| | |
| | | m_pControlJob->setPJs(tempPjs); |
| | | |
| | | |
| | | // æ´æ°contexts |
| | | auto pjs = m_pControlJob->getPjs(); |
| | | for (auto pj : pjs) { |
| | | for (auto& c : pj->carriers()) { |
| | | auto p = getPortWithCarrierId(c.carrierId); |
| | | if (p == nullptr) continue; |
| | | |
| | | std::vector<void*> contexts; |
| | | for (auto s : c.slots) { |
| | | auto g = getGlass(p->getIndex(), s - 1); |
| | | if (g == nullptr) continue; |
| | | contexts.push_back(g); |
| | | } |
| | | pj->setCarrierContexts(c.carrierId, contexts); |
| | | } |
| | | } |
| | | |
| | | |
| | | // å¦æçæ¬å级ï¼å¯å¨è¿é夿 version æ¥å è½½æ°å段 |
| | | |
| | | |
| | | return true; |
| | | } |
| | | |
| | | void CMaster::setStateFile(const std::string& path) |
| | | { |
| | | m_strStatePath = path; |
| | | } |
| | | |
| | | CProcessJob* CMaster::acquireNextProcessJob() |
| | |
| | | int nCount = 0; |
| | | for (auto* pj : m_inProcesJobs) { |
| | | // éå PJ ç carriers å slots |
| | | if (pj->carriers().empty()) continue; |
| | | for (auto& cs : pj->carriers()) { |
| | | for (auto ctx : cs.contexts) { |
| | | CGlass* pGlass = (CGlass*)ctx; |
| | |
| | | return nullptr; |
| | | } |
| | | |
| | | |
| | | bool CMaster::completeControlJob() |
| | | { |
| | | if (m_pControlJob == nullptr) { |
| | | return false; |
| | | } |
| | | for (auto item : m_processJobs) { |
| | | if (item->state() != PJState::Completed) return false; |
| | | } |
| | | if (m_pControlJob->state() != CJState::Completed) |
| | | return false; |
| | | |
| | | |
| | | |
| | | // éæ¾Jobç¸å
³ |
| | | for (auto item : m_processJobs) { |
| | | delete item; |
| | | } |
| | | m_processJobs.clear(); |
| | | if (m_pControlJob != nullptr) { |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | // 注æè¦éæ¾å¼ç¨ |
| | | m_inProcesJobs.clear(); |
| | | m_completeProcessJobs.clear(); |
| | | m_queueGlasses.clear(); |
| | | m_inProcesGlasses.clear(); |
| | | m_completeGlasses.clear(); |
| | | |
| | | |
| | | saveState(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::forceCompleteControlJob(std::string description) |
| | | { |
| | | if (m_pControlJob == nullptr || m_state != SERVO::MASTERSTATE::READY) { |
| | | return false; |
| | | } |
| | | for (auto item : m_processJobs) { |
| | | item->abort(description); |
| | | } |
| | | m_pControlJob->abort(description); |
| | | |
| | | |
| | | // éæ¾Jobç¸å
³ |
| | | for (auto item : m_processJobs) { |
| | | delete item; |
| | | } |
| | | m_processJobs.clear(); |
| | | if (m_pControlJob != nullptr) { |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | // 注æè¦éæ¾å¼ç¨ |
| | | m_inProcesJobs.clear(); |
| | | m_completeProcessJobs.clear(); |
| | | m_queueGlasses.clear(); |
| | | m_inProcesGlasses.clear(); |
| | | m_completeGlasses.clear(); |
| | | |
| | | |
| | | saveState(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::canCreateControlJob() |
| | | { |
| | | return m_pControlJob == nullptr; |
| | |
| | | |
| | | return true; |
| | | } |
| | | |
| | | CGlass* CMaster::getGlass(int scrPort, int scrSlot) |
| | | { |
| | | for (auto eq : m_listEquipment) { |
| | | std::vector<CGlass*> glasses; |
| | | eq->getAllGlass(glasses); |
| | | for (auto g : glasses) { |
| | | int p, s; |
| | | g->getOrginPort(p, s); |
| | | if (p == scrPort && s == scrSlot) { |
| | | return g; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return nullptr; |
| | | } |
| | | |
| | | void CMaster::CreateDAQBridgeServer() |
| | | { |
| | | auto connectionStatusCallback = [&](int code, const std::string& status) { |
| | | LOGI("<DAQBridge>status:", status.c_str()); |
| | | }; |
| | | auto rawDataCallback = [](const std::vector<uint8_t>& bytes) { |
| | | |
| | | }; |
| | | |
| | | // äºä»¶ï¼æäººè¿å
¥/æå¼å°±ä¸æ¥å¿ |
| | | auto clieintEventCallback = [](const std::string& ip, uint16_t port, bool connected) { |
| | | LOGI("<DAQBridge>[Client %s] %s:%u", connected ? _T("JOIN") : _T("LEAVE"), ip.c_str(), port); |
| | | }; |
| | | |
| | | if (m_pCollector == nullptr) { |
| | | m_pCollector = new Collector(); |
| | | m_pCollector->setConnectionStatusCallback(connectionStatusCallback); |
| | | m_pCollector->setRawDataCallback(rawDataCallback); |
| | | m_pCollector->setClientEventCallback(clieintEventCallback); |
| | | m_pCollector->createServer(8081); |
| | | m_pCollector->startLoop(10); |
| | | |
| | | // 1) æ³¨åæºå°ï¼æ¨èï¼å
注å id + æºå¨åç§°ï¼ |
| | | RetentionPolicy defP; defP.mode = RetainMode::ByCount; defP.maxSamples = 200; |
| | | m_pCollector->registryAddMachine(EQ_ID_Bonder1, "Bonder1", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_Bonder2, "Bonder2", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_VACUUMBAKE, "åçç¤", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_BAKE_COOLING, "çç¤å·å´", defP); |
| | | |
| | | |
| | | // 2) 为ééè®¾ç½®âæ²çº¿åç§°â |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 1, "æ°ååå"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 2, "ä¸è
åå"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 3, "管éç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 4, "è
ä½ç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 5, "ä¸è
温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 6, "ä¸è
温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 7, "ä¸è
温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 8, "ä¸è
温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 9, "ä¸è
温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 10, "ä¸è
温度6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 11, "ä¸è
温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 12, "ä¸è
温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 13, "ä¸è
温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 14, "ä¸è
温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 15, "ä¸è
温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 16, "ä¸è
温度6"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 1, "æ°ååå"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 2, "ä¸è
åå"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 3, "管éç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 4, "è
ä½ç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 5, "ä¸è
温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 6, "ä¸è
温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 7, "ä¸è
温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 8, "ä¸è
温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 9, "ä¸è
温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 10, "ä¸è
温度6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 11, "ä¸è
温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 12, "ä¸è
温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 13, "ä¸è
温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 14, "ä¸è
温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 15, "ä¸è
温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 16, "ä¸è
温度6"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 1, "Aè
ç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 2, "Aè
温æ§1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 3, "Aè
温æ§2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 4, "Aè
温æ§4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 5, "Aè
温æ§5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 6, "Aè
温æ§6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 7, "Aè
温æ§7"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 8, "Bè
ç空è§å¼"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 9, "Bè
温æ§1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 10, "Bè
温æ§2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 11, "Bè
温æ§4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 12, "Bè
温æ§5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 13, "Bè
温æ§6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 14, "Bè
温æ§7"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 1, "Açç¤æ¸©æ§1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 2, "Açç¤æ¸©æ§2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 3, "Açç¤æ¸©æ§4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 4, "Açç¤æ¸©æ§5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 5, "Açç¤æ¸©æ§6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 6, "Açç¤æ¸©æ§7"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 7, "Bçç¤æ¸©æ§1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 8, "Bçç¤æ¸©æ§2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 9, "Bçç¤æ¸©æ§4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 10, "Bçç¤æ¸©æ§5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 11, "Bçç¤æ¸©æ§6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 12, "Bçç¤æ¸©æ§7"); |
| | | } |
| | | } |
| | | } |
| | |
| | | #include "CRobotTask.h" |
| | | #include "ProcessJob.h" |
| | | #include "CControlJob.h" |
| | | #include "../DAQBridge/core/Collector.h" |
| | | |
| | | |
| | | #define CTStep_Unknow 0 |
| | |
| | | int abortCurrentTask(); |
| | | int restoreCurrentTask(); |
| | | int resendCurrentTask(); |
| | | void setPortType(unsigned int index, BOOL enable, int type, int mode, |
| | | void setPortTypeEx(unsigned int index, BOOL enable, int type, int mode, |
| | | int cassetteType, int transferMode, BOOL autoChangeEnable); |
| | | void setPortType(unsigned int index, int type); |
| | | void setPortCassetteType(unsigned int index, SERVO::CassetteType type); |
| | | void setPortEnable(unsigned int index, BOOL bEnable); |
| | | void setCompareMapsBeforeProceeding(BOOL bCompare); |
| | |
| | | CControlJob* getControlJob(); |
| | | CLoadPort* getPortWithCarrierId(const std::string& carrierId) const; |
| | | bool saveState() const; |
| | | bool loadState(const std::string& path); |
| | | bool loadState(); |
| | | void setStateFile(const std::string& path); |
| | | int getWipGlasses(std::vector<CGlass*>& glasses); |
| | | void test(); |
| | | bool moveGlassToBuf(int eqid, int slotNo); |
| | | bool moveGlassToSlot(int eqid, int slotNo); |
| | | int getPortCassetteSnSeed(int port); |
| | | void setPortCassetteSnSeed(int port, int seed); |
| | | CGlass* getGlass(int scrPort, int scrSlot); |
| | | |
| | | private: |
| | | inline void lock() { EnterCriticalSection(&m_criticalSection); } |
| | |
| | | bool checkAndUpdatePjComplete(CProcessJob* pJob); |
| | | bool checkAndUpdateCjComplete(CControlJob* pJob); |
| | | CProcessJob* getGlassProcessJob(CGlass* pGlass); |
| | | bool completeControlJob(); |
| | | bool forceCompleteControlJob(std::string description); |
| | | bool canCreateControlJob(); |
| | | bool canCompleteControlJob(); |
| | | bool canDeleteControlJob(); |
| | |
| | | |
| | | int m_nTestFlag; |
| | | std::list<CGlass*> m_bufGlass; |
| | | |
| | | private: |
| | | Collector* m_pCollector = nullptr; |
| | | void CreateDAQBridgeServer(); |
| | | }; |
| | | } |
| | | |
| | |
| | | auto pageFull = db.queryPaged(m_filters, rawLimit, rawOffset); |
| | | #endif |
| | | |
| | | // 妿å¤åºä¸æ¡ï¼çç宿¯å¦æ¯âæ¬é¡µæå䏿¡âç buddy |
| | | std::optional<decltype(pageFull.items)::value_type> lookahead; // é¢è¯»è®°å½ï¼è¥ä¸æå䏿¡é
å¯¹ï¼ |
| | | #if !USE_FAKE_DB_DEMO |
| | | // ââ ä¸å
é®å·¥å
·ï¼<classId>|C<cassette>|J<job> ââ // |
| | | // ââ ä¸å
é®å·¥å
·ï¼<classId>|C<cassette>|J<job> ââ // |
| | | auto makeKey = [](const std::string& cls, int csn, int jsn) -> std::string { |
| | | std::string k; |
| | | k.reserve(cls.size() + 32); |
| | | k.append(cls); |
| | | k.push_back('|'); k.push_back('C'); |
| | | k.append(std::to_string(csn)); |
| | | k.push_back('|'); k.push_back('J'); |
| | | k.append(std::to_string(jsn)); |
| | | return k; |
| | | }; |
| | | |
| | | // â
â
â
è¿éæ¯å
³é®ä¿®å¤ï¼æ¥æ¶âconst Row&âï¼ä¸è¦é const å¼ç¨ |
| | | using RowT = std::decay<decltype(pageFull.items.front())>::type; |
| | | auto makeKeyR = [&](const RowT& r) -> std::string { |
| | | return makeKey(r.classId, r.cassetteSeqNo, r.jobSeqNo); |
| | | }; |
| | | |
| | | // ä¸åºå大å°å classId ç¸ç |
| | | auto iEquals = [](const std::string& a, const std::string& b) { |
| | | #ifdef _WIN32 |
| | | return _stricmp(a.c_str(), b.c_str()) == 0; |
| | | #else |
| | | return strcasecmp(a.c_str(), b.c_str()) == 0; |
| | | #endif |
| | | }; |
| | | }; |
| | | |
| | | |
| | | // ââ lookahead é¢è¯»ï¼è¥è¶
åº 1 æ¡ï¼å°è¯æâæå䏿¡âä¸âé¢è¯»âå¤ä¸ºä¸å¯¹ï¼ä¸¥æ ¼ä¼å
ï¼ââ |
| | | std::optional<decltype(pageFull.items)::value_type> lookahead; |
| | | if (pageFull.items.size() == rawLimit) { |
| | | const auto& last = pageFull.items[PAGE_SIZE - 1]; |
| | | const auto& extra = pageFull.items[PAGE_SIZE]; |
| | | |
| | | bool pair = |
| | | bool strictPair = |
| | | (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId) |
| | | && last.cassetteSeqNo == extra.cassetteSeqNo |
| | | && last.jobSeqNo == extra.jobSeqNo) |
| | | || (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId) |
| | | && extra.cassetteSeqNo == last.cassetteSeqNo |
| | | && extra.jobSeqNo == last.jobSeqNo); |
| | | |
| | | bool loosePair = |
| | | (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId)) || |
| | | (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId)); |
| | | |
| | | if (pair) { |
| | | lookahead = extra; // æé¢è¯»ä¿å䏿¥ï¼ç¨åè¡¥æåè¡ |
| | | if (strictPair || loosePair) { |
| | | lookahead = extra; |
| | | } |
| | | // æ 论æ¯å¦é
对ï¼å表é½ç¼©å PAGE_SIZE æ¡ï¼é¢è¯»ä¸ç®å
¥æ¬é¡µæ°æ®éï¼ |
| | | // é¢è¯»ä¸ç®å
¥æ¬é¡µ |
| | | pageFull.items.pop_back(); |
| | | } |
| | | |
| | | // ä¹åæ£å¸¸æ page æå»º |
| | | auto& page = pageFull; // 为äºå¤ç¨ä½ åæåéå |
| | | auto& pageRef = pageFull; |
| | | |
| | | // 建索å¼ï¼classId -> index |
| | | std::unordered_map<std::string, size_t> idxById; |
| | | idxById.reserve(page.items.size()); |
| | | for (size_t i = 0; i < page.items.size(); ++i) { |
| | | idxById[page.items[i].classId] = i; |
| | | // ââ å»ºä¸¤ä¸ªç´¢å¼ ââ // |
| | | // A) byTriple: ä¸å
é® -> indexï¼å¯ä¸/å·²æ¶è´¹ä¾æ®ï¼ |
| | | // B) byClass : classId -> indicesï¼buddy åéæ± ï¼å
许å¤ä¸ªï¼ |
| | | std::unordered_map<std::string, size_t> byTriple; |
| | | std::unordered_map<std::string, std::vector<size_t>> byClass; |
| | | byTriple.reserve(pageRef.items.size()); |
| | | byClass.reserve(pageRef.items.size()); |
| | | |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) { |
| | | const auto& r = pageRef.items[i]; |
| | | byTriple[makeKeyR(r)] = i; |
| | | byClass[r.classId].push_back(i); |
| | | } |
| | | |
| | | // å·²æ¶è´¹ï¼å·²æå
¥ä¸ºç¶æåï¼ |
| | | // ââ å·²æ¶è´¹éåï¼ç¨ä¸å
é®ï¼ââ |
| | | std::unordered_set<std::string> consumed; |
| | | consumed.reserve(pageRef.items.size()); |
| | | |
| | | int zebra = 0; |
| | | auto zebraBk = [&](int z) -> COLORREF { |
| | | return (z % 2 == 0) ? RGB(255, 255, 255) : RGB(235, 235, 235); |
| | | }; |
| | | |
| | | // -------- Phase 1: å
å¤çâæ buddyId çè®°å½âï¼è½é
å°±é
ï¼ååä¹é
ï¼ ---------- |
| | | for (size_t i = 0; i < page.items.size(); ++i) { |
| | | const auto& r = page.items[i]; |
| | | // CopyUtf8ToClipboard(r.pretty); |
| | | |
| | | if (consumed.count(r.classId)) continue; |
| | | // -------- Phase 1: å
å¤çâæ buddyId çè®°å½â ---------- |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) { |
| | | const auto& r = pageRef.items[i]; |
| | | if (consumed.count(makeKeyR(r))) continue; |
| | | if (r.buddyId.empty()) continue; |
| | | |
| | | COLORREF bk = zebraBk(zebra); |
| | | // å¨å页é为 r æ¾ buddy åé |
| | | size_t buddyIdx = (size_t)-1; |
| | | auto itVec = byClass.find(r.buddyId); |
| | | if (itVec != byClass.end()) { |
| | | const auto& vec = itVec->second; |
| | | |
| | | auto it = idxById.find(r.buddyId); |
| | | if (it != idxById.end()) { |
| | | const auto& br = page.items[it->second]; |
| | | if (!consumed.count(br.classId)) { |
| | | // ââ ä»¥âæ buddyId çè¿æ¡ râ为ç¶ï¼buddy ä½ä¸ºåï¼ååä¹è½é
ï¼ââ |
| | | std::vector<CString> pcols(colCount); |
| | | pcols[1] = std::to_string(r.id).c_str(); |
| | | pcols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | | pcols[3] = std::to_string(r.jobSeqNo).c_str(); |
| | | pcols[4] = r.classId.c_str(); |
| | | pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str(); |
| | | pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str(); |
| | | pcols[7] = r.tStart.c_str(); |
| | | pcols[8] = r.tEnd.c_str(); |
| | | pcols[9] = r.buddyId.c_str(); |
| | | pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str(); |
| | | pcols[11] = r.path.c_str(); |
| | | pcols[12] = r.params.c_str(); |
| | | |
| | | auto* nParent = m_listCtrl.InsertRoot(pcols); |
| | | MaybeRestoreExpandByKey(nParent, expandedKeys); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk); |
| | | |
| | | std::vector<CString> ccols(colCount); |
| | | ccols[1] = std::to_string(br.id).c_str(); |
| | | ccols[2] = std::to_string(br.cassetteSeqNo).c_str(); |
| | | ccols[3] = std::to_string(br.jobSeqNo).c_str(); |
| | | ccols[4] = br.classId.c_str(); |
| | | ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str(); |
| | | ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str(); |
| | | ccols[7] = br.tStart.c_str(); |
| | | ccols[8] = br.tEnd.c_str(); |
| | | ccols[9] = br.buddyId.c_str(); |
| | | ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str(); |
| | | ccols[11] = br.path.c_str(); |
| | | ccols[12] = br.params.c_str(); |
| | | |
| | | auto* nChild = m_listCtrl.InsertChild(nParent, ccols); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk); |
| | | |
| | | consumed.insert(r.classId); |
| | | consumed.insert(br.classId); |
| | | ++zebra; |
| | | continue; |
| | | // 1) ä¸¥æ ¼å¹é
ï¼Cassette/Job ä¸è´ |
| | | for (size_t j : vec) { |
| | | const auto& br = pageRef.items[j]; |
| | | if (br.cassetteSeqNo == r.cassetteSeqNo && br.jobSeqNo == r.jobSeqNo) { |
| | | if (!consumed.count(makeKeyR(br))) { buddyIdx = j; break; } |
| | | } |
| | | } |
| | | // 2) 宽æ¾å¹é
ï¼å classId æªæ¶è´¹çä»»æä¸æ¡ |
| | | if (buddyIdx == (size_t)-1) { |
| | | for (size_t j : vec) { |
| | | const auto& br = pageRef.items[j]; |
| | | if (!consumed.count(makeKeyR(br))) { buddyIdx = j; break; } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // å页没æ¾å° buddyï¼æå·²è¢«æ¶è´¹ï¼â æå ä½åè¡ |
| | | COLORREF bk = zebraBk(zebra); |
| | | |
| | | if (buddyIdx != (size_t)-1) { |
| | | const auto& br = pageRef.items[buddyIdx]; |
| | | |
| | | // ç¶ï¼rï¼æ buddyIdï¼ï¼åï¼br |
| | | std::vector<CString> pcols(colCount); |
| | | pcols[1] = std::to_string(r.id).c_str(); |
| | | pcols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | | pcols[3] = std::to_string(r.jobSeqNo).c_str(); |
| | | pcols[4] = r.classId.c_str(); |
| | | pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str(); |
| | | pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str(); |
| | | pcols[7] = r.tStart.c_str(); |
| | | pcols[8] = r.tEnd.c_str(); |
| | | pcols[9] = r.buddyId.c_str(); |
| | | pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str(); |
| | | pcols[11] = r.path.c_str(); |
| | | pcols[12] = r.params.c_str(); |
| | | |
| | | auto* nParent = m_listCtrl.InsertRoot(pcols); |
| | | MaybeRestoreExpandByKey(nParent, expandedKeys); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk); |
| | | |
| | | std::vector<CString> ccols(colCount); |
| | | ccols[1] = std::to_string(br.id).c_str(); |
| | | ccols[2] = std::to_string(br.cassetteSeqNo).c_str(); |
| | | ccols[3] = std::to_string(br.jobSeqNo).c_str(); |
| | | ccols[4] = br.classId.c_str(); |
| | | ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str(); |
| | | ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str(); |
| | | ccols[7] = br.tStart.c_str(); |
| | | ccols[8] = br.tEnd.c_str(); |
| | | ccols[9] = br.buddyId.c_str(); |
| | | ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str(); |
| | | ccols[11] = br.path.c_str(); |
| | | ccols[12] = br.params.c_str(); |
| | | |
| | | auto* nChild = m_listCtrl.InsertChild(nParent, ccols); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk); |
| | | |
| | | consumed.insert(makeKeyR(r)); |
| | | consumed.insert(makeKeyR(br)); |
| | | ++zebra; |
| | | continue; |
| | | } |
| | | |
| | | // 没æ¾å° buddy â æå ä½åè¡ï¼åªå ClassIDï¼ |
| | | std::vector<CString> pcols(colCount); |
| | | pcols[1] = std::to_string(r.id).c_str(); |
| | | pcols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | |
| | | |
| | | auto* nParent = m_listCtrl.InsertRoot(pcols); |
| | | MaybeRestoreExpandByKey(nParent, expandedKeys); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), zebraBk(zebra)); |
| | | |
| | | std::vector<CString> ccols(colCount); // å ä½åªå ClassID |
| | | ccols[4] = r.buddyId.c_str(); |
| | | std::vector<CString> ccols(colCount); |
| | | ccols[4] = r.buddyId.c_str(); // å ä½ |
| | | auto* nChild = m_listCtrl.InsertChild(nParent, ccols); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), zebraBk(zebra)); |
| | | |
| | | consumed.insert(r.classId); |
| | | consumed.insert(makeKeyR(r)); |
| | | ++zebra; |
| | | } |
| | | |
| | | // -------- Phase 2: å©ä½æªæ¶è´¹çï¼ä½ä¸ºâåæ¡æ ¹è¡â ---------- |
| | | for (size_t i = 0; i < page.items.size(); ++i) { |
| | | const auto& r = page.items[i]; |
| | | if (consumed.count(r.classId)) continue; |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) { |
| | | const auto& r = pageRef.items[i]; |
| | | if (consumed.count(makeKeyR(r))) continue; |
| | | |
| | | COLORREF bk = zebraBk(zebra); |
| | | |
| | | std::vector<CString> cols(colCount); |
| | | cols[1] = std::to_string(r.id).c_str(); |
| | | cols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | | cols[3] = std::to_string(r.jobSeqNo).c_str(); |
| | | cols[4] = r.classId.c_str(); |
| | | cols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str(); |
| | | cols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str(); |
| | | cols[7] = r.tStart.c_str(); |
| | | cols[8] = r.tEnd.c_str(); |
| | | cols[9] = r.buddyId.c_str(); |
| | | cols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str(); |
| | | cols[11] = r.path.c_str(); |
| | | cols[12] = r.params.c_str(); |
| | | |
| | | auto* n = m_listCtrl.InsertRoot(cols); |
| | | m_listCtrl.SetNodeColor(n, RGB(0, 0, 0), bk); |
| | | |
| | | consumed.insert(makeKeyR(r)); |
| | | ++zebra; |
| | | } |
| | | |
| | | // 䏿¬¡æ§éç» |
| | | m_listCtrl.RebuildVisible(); |
| | | |
| | | #else |
| | | // ===== DEMO 忝ï¼ä¿æåæ ·ï¼è¥è¦æ¼ç¤ºåæ ·é»è¾ï¼å¯ä»¿ç
§ä¸é¢æ¹é ï¼===== |
| | | // 妿å¤åºä¸æ¡ï¼çç宿¯å¦æ¯âæ¬é¡µæå䏿¡âç buddy |
| | | std::optional<decltype(page.items)::value_type> lookahead; |
| | | auto iEquals = [](const std::string& a, const std::string& b) { |
| | | #ifdef _WIN32 |
| | | return _stricmp(a.c_str(), b.c_str()) == 0; |
| | | #else |
| | | return strcasecmp(a.c_str(), b.c_str()) == 0; |
| | | #endif |
| | | }; |
| | | |
| | | if (page.items.size() == rawLimit) { |
| | | const auto& last = page.items[PAGE_SIZE - 1]; |
| | | const auto& extra = page.items[PAGE_SIZE]; |
| | | bool pair = |
| | | (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId)) || |
| | | (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId)); |
| | | if (pair) lookahead = extra; |
| | | page.items.pop_back(); |
| | | } |
| | | |
| | | // ä½ å¯ä»¥æ DEMO 忝ä¹åå°ä¸å
é®é»è¾ï¼è¿éä»ç¥ |
| | | auto& pageRef = page; |
| | | std::unordered_map<std::string, size_t> idxById; |
| | | idxById.reserve(pageRef.items.size()); |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) idxById[pageRef.items[i].classId] = i; |
| | | |
| | | std::unordered_set<std::string> consumed; |
| | | int zebra = 0; |
| | | auto zebraBk = [&](int z) -> COLORREF { |
| | | return (z % 2 == 0) ? RGB(255, 255, 255) : RGB(235, 235, 235); |
| | | }; |
| | | |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) { |
| | | const auto& r = pageRef.items[i]; |
| | | if (consumed.count(r.classId)) continue; |
| | | if (!r.buddyId.empty()) { |
| | | auto it = idxById.find(r.buddyId); |
| | | if (it != idxById.end()) { |
| | | const auto& br = pageRef.items[it->second]; |
| | | if (!consumed.count(br.classId)) { |
| | | COLORREF bk = zebraBk(zebra); |
| | | std::vector<CString> pcols(colCount), ccols(colCount); |
| | | pcols[1] = std::to_string(r.id).c_str(); |
| | | pcols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | | pcols[3] = std::to_string(r.jobSeqNo).c_str(); |
| | | pcols[4] = r.classId.c_str(); |
| | | pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str(); |
| | | pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str(); |
| | | pcols[7] = r.tStart.c_str(); |
| | | pcols[8] = r.tEnd.c_str(); |
| | | pcols[9] = r.buddyId.c_str(); |
| | | pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str(); |
| | | pcols[11] = r.path.c_str(); |
| | | pcols[12] = r.params.c_str(); |
| | | auto* nParent = m_listCtrl.InsertRoot(pcols); |
| | | MaybeRestoreExpandByKey(nParent, expandedKeys); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk); |
| | | |
| | | ccols[1] = std::to_string(br.id).c_str(); |
| | | ccols[2] = std::to_string(br.cassetteSeqNo).c_str(); |
| | | ccols[3] = std::to_string(br.jobSeqNo).c_str(); |
| | | ccols[4] = br.classId.c_str(); |
| | | ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str(); |
| | | ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str(); |
| | | ccols[7] = br.tStart.c_str(); |
| | | ccols[8] = br.tEnd.c_str(); |
| | | ccols[9] = br.buddyId.c_str(); |
| | | ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str(); |
| | | ccols[11] = br.path.c_str(); |
| | | ccols[12] = br.params.c_str(); |
| | | auto* nChild = m_listCtrl.InsertChild(nParent, ccols); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk); |
| | | |
| | | consumed.insert(r.classId); |
| | | consumed.insert(br.classId); |
| | | ++zebra; |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | // æå ä½å |
| | | COLORREF bk = zebraBk(zebra); |
| | | std::vector<CString> pcols(colCount), ccols(colCount); |
| | | pcols[1] = std::to_string(r.id).c_str(); |
| | | pcols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | | pcols[3] = std::to_string(r.jobSeqNo).c_str(); |
| | | pcols[4] = r.classId.c_str(); |
| | | pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str(); |
| | | pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str(); |
| | | pcols[7] = r.tStart.c_str(); |
| | | pcols[8] = r.tEnd.c_str(); |
| | | pcols[9] = r.buddyId.c_str(); |
| | | pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str(); |
| | | pcols[11] = r.path.c_str(); |
| | | pcols[12] = r.params.c_str(); |
| | | auto* nParent = m_listCtrl.InsertRoot(pcols); |
| | | MaybeRestoreExpandByKey(nParent, expandedKeys); |
| | | m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk); |
| | | |
| | | ccols[4] = r.buddyId.c_str(); |
| | | auto* nChild = m_listCtrl.InsertChild(nParent, ccols); |
| | | m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk); |
| | | |
| | | consumed.insert(r.classId); |
| | | ++zebra; |
| | | } |
| | | } |
| | | for (size_t i = 0; i < pageRef.items.size(); ++i) { |
| | | const auto& r = pageRef.items[i]; |
| | | if (consumed.count(r.classId)) continue; |
| | | |
| | | COLORREF bk = zebraBk(zebra); |
| | | std::vector<CString> cols(colCount); |
| | | cols[1] = std::to_string(r.id).c_str(); |
| | | cols[2] = std::to_string(r.cassetteSeqNo).c_str(); |
| | |
| | | ++zebra; |
| | | } |
| | | |
| | | // 䏿¬¡æ§éç» |
| | | m_listCtrl.RebuildVisible(); |
| | | #endif |
| | | |
| | | // ä¸ä¸é¡µ / ä¸ä¸é¡µ |
| | | UpdatePageControls(); |
| | |
| | | CExpandableListCtrl::Node* savedTop = nullptr; |
| | | |
| | | // 3) é个å¤ç WIPï¼å·²åå¨ -> 就尿´æ°ï¼å¿
è¦æ¶âåªå¯¹æ ¹è¡¥å项â |
| | | // ä¸åå¨ -> ä¼å
æå° buddy 容å¨ï¼å¦åè§¦åæ´é¡µéå»ºï¼æ°æ ¹ä¿æé¡¶é¨ï¼ |
| | | // ä¸åå¨ -> æå° buddy 容å¨ï¼è¥ buddy ä¸å¨å¯è§è¡¨ï¼è§¦åå
¨éé建ï¼ä¿è¯ WIP é¡¶é¨ï¼ |
| | | for (auto* g : wipGlasses) { |
| | | if (!GlassMatchesFilters(*g, m_filters)) continue; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // ââ åªå¯¹âæ ¹èç¹âè¡¥å项ï¼ä¸ä»
å½ buddy å°æªåºç°å¨å¯è§è¡¨ï¼ä¸æ ¹ä¸ä¹æ²¡æè¯¥ buddy ââ |
| | | // ââ åªå¯¹âæ ¹èç¹âè¡¥å项 ââ |
| | | SERVO::CGlass* b = g->getBuddy(); |
| | | if (b) { |
| | | auto itRoot = wipRootById.find(cid); |
| | |
| | | bool buddyExistsAnywhere = (wipRowById.find(newBid) != wipRowById.end()); |
| | | bool hasChildAlready = NodeHasChildWithClassId(container, newBuddyCid); |
| | | |
| | | // å
³ç³»æ¯å¦åçååï¼ï¼oldChildCid ä¸ newBuddyCid ä¸åï¼ææåä½ç°å¨æ²¡ buddyï¼ |
| | | // å
³ç³»æ¯å¦åçååï¼ |
| | | bool relationChanged = |
| | | (!oldChildCid.IsEmpty() && newBuddyCid.IsEmpty()) || |
| | | (oldChildCid.IsEmpty() && !newBuddyCid.IsEmpty()) || |
| | |
| | | } |
| | | } |
| | | } |
| | | // è¥å½åæ¯âåèç¹âï¼ä¸å¨è¿éè°æ´ç¶åå
³ç³»ï¼è®©âå
³ç³»ååâèµ°å
¨éé建 |
| | | } |
| | | else { |
| | | // 没æ buddyï¼å¦æå®¹å¨ä¸ç°å¨æåï¼ä¹ç®å
³ç³»ååï¼è§¦åé建 |
| | | // 没 buddy ä½å®¹å¨ä¸æå -> å
³ç³»ååï¼è§¦åå
¨éé建 |
| | | auto itRoot = wipRootById.find(cid); |
| | | if (itRoot != wipRootById.end()) { |
| | | CExpandableListCtrl::Node* container = itRoot->second; |
| | |
| | | } |
| | | else { |
| | | // (B) ä¸åå¨ï¼æ°å¢ |
| | | // å
å°è¯âæå° buddy ç容卿 ¹âä¸é¢ï¼ |
| | | // è¥ buddy ä¸å¨å½åå¯è§è¡¨ï¼å触åå
¨éé建ï¼ä¿è¯ WIP é¡¶é¨ï¼ã |
| | | SERVO::CGlass* b = g->getBuddy(); |
| | | CExpandableListCtrl::Node* container = nullptr; |
| | | |
| | |
| | | } |
| | | |
| | | if (container) { |
| | | // buddy 容å¨åå¨ï¼æ g ä½ä¸ºâåè¡âæä¸å»ï¼é¿å
éå¤ï¼ |
| | | CString cidCs = g->getID().c_str(); |
| | | if (!NodeHasChildWithClassId(container, cidCs)) { |
| | | if (!needRebuildChildren) { CaptureUiState(m_listCtrl, savedSel, savedTop); } |
| | |
| | | CMsgDlg msgDlg("请çå¾
", "æ£å¨æä½ï¼è¯·çå¾
..."); |
| | | msgDlg.SetData((DWORD_PTR)this); |
| | | |
| | | // ä¿®æ¹ä¸ºåªä¿å卿¬å°é
ç½® |
| | | ASSERT(m_pPort != nullptr); |
| | | int index = ((CComboBox*)GetDlgItem(IDC_COMBO_PORT_TYPE))->GetCurSel(); |
| | | theApp.m_model.setPortType(m_pPort->getIndex(), SERVO::PortType(index + 1)); |
| | | |
| | | /* |
| | | m_pPort->setPortType(SERVO::PortType(index + 1), [&](int code) -> int { |
| | | Sleep(100); |
| | | CString strMsg; |
| | |
| | | |
| | | msgDlg.DoModal(); |
| | | g_nMsgDlgShow = 1; |
| | | */ |
| | | } |
| | | |
| | | void CPagePortProperty::OnCbnSelchangeComboPortMode() |
| | |
| | | |
| | | double CParam::getDoubleValue() |
| | | { |
| | | return m_fValue; |
| | | if(m_nValueType == PVT_DOUBLE) |
| | | return m_fValue; |
| | | if (m_nValueType == PVT_INT) |
| | | return (double)m_nValue; |
| | | |
| | | return 0.0; |
| | | } |
| | | |
| | | void CParam::setDoubleValue(double value) |
| | |
| | | return TRUE; |
| | | } |
| | | |
| | | BOOL CConfiguration::setPortType(unsigned int index, int type) |
| | | { |
| | | if (index >= 4) return FALSE; |
| | | if (type < 1 || 7 < type) return FALSE; |
| | | |
| | | static char* pszSection[] = { "Port1", "Port2", "Port3", "Port4" }; |
| | | WritePrivateProfileString(pszSection[index], _T("Type"), std::to_string(type).c_str(), m_strFilepath); |
| | | return true; |
| | | } |
| | | |
| | | BOOL CConfiguration::setPortCassetteType(unsigned int index, int cassetteType) |
| | | { |
| | | if (index >= 4) return FALSE; |
| | |
| | | int getFilterMode(); |
| | | BOOL getPortParms(unsigned int index, BOOL& bEnable, int& type, int& mode, |
| | | int& cassetteType, int& transferMode, BOOL& bAutoChangeEnable); |
| | | BOOL setPortType(unsigned int index, int type); |
| | | BOOL setPortCassetteType(unsigned int index, int cassetteType); |
| | | BOOL setPortEnable(unsigned int index, BOOL bEnable); |
| | | BOOL isCompareMapsBeforeProceeding(); |
| | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_configuration.getPortParms(i, portEnable, portType, portMode, |
| | | cassetteType, transferMode, autoChangeEnable); |
| | | m_master.setPortType(i, portEnable, portType, portMode, cassetteType, |
| | | m_master.setPortTypeEx(i, portEnable, portType, portMode, cassetteType, |
| | | transferMode, autoChangeEnable); |
| | | |
| | | int seed = m_configuration.getPortCassetteSnSeed(i + 1); |
| | | m_master.setPortCassetteSnSeed(i + 1, seed); |
| | | } |
| | | } |
| | | |
| | | void CModel::setPortType(unsigned int index, SERVO::PortType type) |
| | | { |
| | | m_master.setPortType(index, (int)type); |
| | | m_configuration.setPortType(index, (int)type); |
| | | } |
| | | |
| | | void CModel::setPortCassetteType(unsigned int index, SERVO::CassetteType type) |
| | |
| | | // å æªJob |
| | | strMasterDataFile.Format(_T("%s\\MasterState.dat"), (LPTSTR)(LPCTSTR)m_strWorkDir); |
| | | std::string strPath = std::string((LPTSTR)(LPCTSTR)strMasterDataFile); |
| | | if (!m_master.loadState(strPath)) { |
| | | LOGE("<Master>å è½½MasterState.datæä»¶å¤±è´¥."); |
| | | } |
| | | m_master.setStateFile(strPath); |
| | | |
| | | |
| | | |
| | | // å è½½è¦åä¿¡æ¯ |
| | |
| | | SERVO::CMaster& getMaster(); |
| | | void setWorkDir(const char* pszWorkDir); |
| | | void loadPortParams(); |
| | | void setPortType(unsigned int index, SERVO::PortType type);; |
| | | void setPortCassetteType(unsigned int index, SERVO::CassetteType type); |
| | | void setPortEnable(unsigned int index, BOOL bEnable); |
| | | int init(); |
| | |
| | | return true; |
| | | } |
| | | |
| | | bool CProcessJob::abort() { |
| | | bool CProcessJob::abort(std::string reason) { |
| | | if (m_state == PJState::Completed || m_state == PJState::Aborted || m_state == PJState::Failed) |
| | | return false; |
| | | m_failReason = trimCopy(reason); |
| | | clampString(m_failReason, 128); |
| | | m_state = PJState::Aborted; |
| | | markEnd(); |
| | | return true; |
| | |
| | | cs.slots = std::move(slots); |
| | | m_carriers.emplace_back(std::move(cs)); |
| | | } |
| | | } |
| | | |
| | | bool CProcessJob::setCarrierSlotsAndContexts(std::string carrierId, std::vector<uint8_t> slots, std::vector<void*> contexts) |
| | | { |
| | | for (auto& c : m_carriers) { |
| | | if (c.carrierId.compare(carrierId) == 0) { |
| | | c.slots = std::move(slots); |
| | | c.contexts = std::move(contexts); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | bool CProcessJob::setCarrierContexts(std::string carrierId, std::vector<void*> contexts) |
| | | { |
| | | for (auto& c : m_carriers) { |
| | | if (c.carrierId.compare(carrierId) == 0) { |
| | | c.contexts = std::move(contexts); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | // --------- æ ¸å¿ï¼serialize/deserialize --------- |
| | |
| | | |
| | | return nullptr; |
| | | } |
| | | |
| | | void CProcessJob::setLotId(std::string strLotId) |
| | | { |
| | | m_strLotId = strLotId; |
| | | } |
| | | |
| | | std::string& CProcessJob::getLotId() |
| | | { |
| | | return m_strLotId; |
| | | } |
| | | |
| | | void CProcessJob::setProductId(std::string strProductId) |
| | | { |
| | | m_strProductId = strProductId; |
| | | } |
| | | |
| | | std::string& CProcessJob::getProductId() |
| | | { |
| | | return m_strProductId; |
| | | } |
| | | |
| | | void CProcessJob::setOperationId(std::string strOperationId) |
| | | { |
| | | m_strOperationId = strOperationId; |
| | | } |
| | | |
| | | std::string& CProcessJob::getOperationId() |
| | | { |
| | | return m_strOperationId; |
| | | } |
| | | |
| | | void CProcessJob::setPjWarp(PJWarp pjWarp) |
| | | { |
| | | m_pjWarp = pjWarp; |
| | | } |
| | | |
| | | PJWarp& CProcessJob::getPjWarp() |
| | | { |
| | | return m_pjWarp; |
| | | } |
| | | } |
| | |
| | | #include <chrono> |
| | | #include <optional> |
| | | |
| | | |
| | | |
| | | struct PJWarp { |
| | | BOOL addToCj; |
| | | void* pj; |
| | | int port; |
| | | BOOL checkSlot[8]; |
| | | int material[8]; |
| | | }; |
| | | |
| | | namespace SERVO { |
| | | /// PJ çå½å¨æï¼è´´è¿ E40 常è§ç¶æï¼ |
| | | enum class PJState : uint8_t { |
| | |
| | | bool pause(); // InProcess -> Paused |
| | | bool resume(); // Paused -> InProcess |
| | | bool complete(); // InProcess -> Completed |
| | | bool abort(); // Any (æªç»æ) -> Aborted |
| | | bool abort(std::string reason); // Any (æªç»æ) -> Aborted |
| | | bool fail(std::string reason); // ä»»ææ -> Failedï¼è®°å½å¤±è´¥åå ï¼ |
| | | |
| | | // ââ 访é®å¨ï¼ç¨äºä¸æ¥/æ¥è¯¢ï¼ââ |
| | |
| | | |
| | | // 追å ä¸ä¸ªè½½å
· |
| | | void addCarrier(std::string carrierId, std::vector<uint8_t> slots); |
| | | |
| | | // 设置载å
·slotsåcontexts |
| | | bool setCarrierSlotsAndContexts(std::string carrierId, std::vector<uint8_t> slots, std::vector<void*> contexts); |
| | | bool setCarrierContexts(std::string carrierId, std::vector<void*> contexts); |
| | | |
| | | // 访é®å¨ |
| | | const std::vector<CarrierSlotInfo>& carriers() const noexcept { return m_carriers; } |
| | |
| | | |
| | | // é误å表 |
| | | std::vector<ValidationIssue> m_issues; |
| | | |
| | | // æ°å¢ |
| | | std::string m_strLotId; |
| | | std::string m_strProductId; |
| | | std::string m_strOperationId; |
| | | PJWarp m_pjWarp; |
| | | |
| | | public: |
| | | void setLotId(std::string strLotId); |
| | | std::string& getLotId(); |
| | | void setProductId(std::string strProductId); |
| | | std::string& getProductId(); |
| | | void setOperationId(std::string strOperationId); |
| | | std::string& getOperationId(); |
| | | void setPjWarp(PJWarp pjWarp); |
| | | PJWarp& getPjWarp(); |
| | | }; |
| | | } |
| | | |
| | |
| | | <Text Include="ReadMe.txt" /> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClInclude Include="..\DAQBridge\buffer\BufferManager.h" /> |
| | | <ClInclude Include="..\DAQBridge\buffer\BufferRegistry.h" /> |
| | | <ClInclude Include="..\DAQBridge\buffer\SampleBuffer.h" /> |
| | | <ClInclude Include="..\DAQBridge\core\Collector.h" /> |
| | | <ClInclude Include="..\DAQBridge\core\CommBase.h" /> |
| | | <ClInclude Include="..\DAQBridge\core\ConnEvents.h" /> |
| | | <ClInclude Include="..\DAQBridge\core\DataTypes.h" /> |
| | | <ClInclude Include="..\DAQBridge\core\Display.h" /> |
| | | <ClInclude Include="..\DAQBridge\DAQConfig.h" /> |
| | | <ClInclude Include="..\DAQBridge\net\FrameAssembler.h" /> |
| | | <ClInclude Include="..\DAQBridge\net\SocketComm.h" /> |
| | | <ClInclude Include="..\DAQBridge\proto\Protocol.h" /> |
| | | <ClInclude Include="..\DAQBridge\proto\ProtocolCodec.h" /> |
| | | <ClInclude Include="..\jsoncpp\include\json\autolink.h" /> |
| | | <ClInclude Include="..\jsoncpp\include\json\config.h" /> |
| | | <ClInclude Include="..\jsoncpp\include\json\features.h" /> |
| | |
| | | <ClInclude Include="VerticalLine.h" /> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClCompile Include="..\DAQBridge\buffer\BufferManager.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\buffer\BufferRegistry.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\buffer\SampleBuffer.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\core\Collector.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\core\Display.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\net\SocketComm.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\proto\ProtocolCodec.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="..\jsoncpp\lib_json\json_reader.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | |
| | | <ClCompile Include="CCjPageBase.cpp" /> |
| | | <ClCompile Include="CCarrierSlotSelector.cpp" /> |
| | | <ClCompile Include="CCarrierSlotGrid.cpp" /> |
| | | <ClCompile Include="..\DAQBridge\buffer\BufferManager.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\buffer\BufferRegistry.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\buffer\SampleBuffer.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\core\Collector.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\core\Display.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\net\SocketComm.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="..\DAQBridge\proto\ProtocolCodec.cpp"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClCompile> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClInclude Include="AlarmManager.h" /> |
| | |
| | | <ClInclude Include="CCjPageBase.h" /> |
| | | <ClInclude Include="CCarrierSlotSelector.h" /> |
| | | <ClInclude Include="CCarrierSlotGrid.h" /> |
| | | <ClInclude Include="..\DAQBridge\buffer\BufferManager.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\buffer\BufferRegistry.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\buffer\SampleBuffer.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\core\Collector.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\core\CommBase.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\core\ConnEvents.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\core\DataTypes.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\core\Display.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\net\FrameAssembler.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\net\SocketComm.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\proto\Protocol.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\proto\ProtocolCodec.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="..\DAQBridge\DAQConfig.h"> |
| | | <Filter>DAQBridge</Filter> |
| | | </ClInclude> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ResourceCompile Include="Servo.rc" /> |
| | |
| | | <Filter Include="JsonCpp"> |
| | | <UniqueIdentifier>{a877af37-2f78-484f-b1bb-276edbbcd694}</UniqueIdentifier> |
| | | </Filter> |
| | | <Filter Include="DAQBridge"> |
| | | <UniqueIdentifier>{885738f6-3122-4bb9-8308-46b7f692fb13}</UniqueIdentifier> |
| | | </Filter> |
| | | </ItemGroup> |
| | | </Project> |
| | |
| | | } |
| | | } |
| | | else if (id == IDC_BUTTON_JOBS) { |
| | | static int i = 0; i++; |
| | | if (i % 2 == 0) { |
| | | CControlJobManagerDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | else { |
| | | CControlJobDlg dlg; |
| | | dlg.SetControlJob(theApp.m_model.m_master.getControlJob()); |
| | | dlg.DoModal(); |
| | | } |
| | | CControlJobDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | else if (id == IDC_BUTTON_PORT_CONFIG) { |
| | | CPortConfigurationDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | else if (id == IDC_BUTTON_CASSETTE) { |
| | | CControlJobManagerDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | else if (id == IDC_BUTTON_ROBOT) { |
| | | theApp.m_model.getMaster().clearError(); |
| | | SERVO::CEFEM* pEFEM = (SERVO::CEFEM*)theApp.m_model.getMaster().getEquipment(EQ_ID_EFEM); |
| | |
| | | DDX_Control(pDX, IDC_BUTTON_ALARM, m_btnAlarm); |
| | | DDX_Control(pDX, IDC_BUTTON_SETTINGS, m_btnSettings); |
| | | DDX_Control(pDX, IDC_BUTTON_PORT_CONFIG, m_btnPortConfig); |
| | | DDX_Control(pDX, IDC_BUTTON_CASSETTE, m_btnCassette); |
| | | DDX_Control(pDX, IDC_BUTTON_ROBOT, m_btnRobot); |
| | | DDX_Control(pDX, IDC_BUTTON_OPERATOR, m_btnOperator); |
| | | } |
| | |
| | | InitBtn(m_btnSettings, "Settings_High_32.ico", "Settings_Gray_32.ico"); |
| | | InitBtn(m_btnRobot, "Robot_High_32.ico", "Robot_Gray_32.ico"); |
| | | InitBtn(m_btnPortConfig, "PortConfig_High_32.ico", "PortConfig_Gray_32.ico"); |
| | | InitBtn(m_btnCassette, "Cassette_High_32.ico", "Cassette_Gray_32.ico"); |
| | | InitBtn(m_btnOperator, "Operator_High_32.ico", "Operator_Gray_32.ico"); |
| | | HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_OPEATOR)); |
| | | m_btnOperator.SetMenu(hMenu); |
| | |
| | | x += BTN_WIDTH; |
| | | x += 2; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_CASSETTE); |
| | | pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight); |
| | | x += BTN_WIDTH; |
| | | x += 2; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_ROBOT); |
| | | pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight); |
| | | x += BTN_WIDTH; |
| | |
| | | case IDC_BUTTON_ALARM: |
| | | case IDC_BUTTON_SETTINGS: |
| | | case IDC_BUTTON_PORT_CONFIG: |
| | | case IDC_BUTTON_CASSETTE: |
| | | case IDC_BUTTON_ROBOT: |
| | | GetParent()->SendMessage(ID_MSG_TOOLBAR_BTN_CLICKED, 0, LOWORD(wParam)); |
| | | break; |
| | |
| | | CBlButton m_btnAlarm; |
| | | CBlButton m_btnSettings; |
| | | CBlButton m_btnPortConfig; |
| | | CBlButton m_btnCassette; |
| | | CBlButton m_btnRobot; |
| | | CBlButton m_btnOperator; |
| | | |
| | |
| | | [LoadPort 1] |
| | | Left=23 |
| | | Top=88 |
| | | Top=87 |
| | | [LoadPort 2] |
| | | Left=23 |
| | | Top=437 |