Merge branch 'clh' into liuyang
| | |
| | | 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 |
| | |
| | | |
| | | int CBakeCooling::parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | | { |
| | | return parsingParams(pszData, size, params); |
| | | ASSERT(pszData); |
| | | if (size < 250) return 0; |
| | | int i = 0, v; |
| | | |
| | | |
| | | // 1.å·¥èºåæ°åºå· |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("å·¥èºåæ°åºå·", "", this->getName().c_str(), v)); |
| | | i += 2; |
| | | |
| | | if (v == 1) { |
| | | // 2.A_è
çç¤æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("A_è
çç¤æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | |
| | | // 3.A_çç¤æ¸©åº¦è®¾å® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("A_çç¤æ¸©åº¦è®¾å®", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 2; |
| | | } |
| | | else if (v == 2) { |
| | | // 2.A_è
å·å´æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("A_è
å·å´æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | } |
| | | else if (v == 3) { |
| | | // 2.A_è
çç¤æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("B_è
çç¤æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | |
| | | // 3.A_çç¤æ¸©åº¦è®¾å® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("B_çç¤æ¸©åº¦è®¾å®", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 2; |
| | | } |
| | | else if (v == 4) { |
| | | // 2.A_è
å·å´æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("B_è
å·å´æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | } |
| | | |
| | | |
| | | return (int)params.size(); |
| | | } |
| | | |
| | | int CBakeCooling::parsingSVData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | |
| | | 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 "stdafx.h" |
| | | #include "CCarrierSlotGrid.h" |
| | | #include <gdiplus.h> |
| | | #pragma comment(lib, "gdiplus.lib") |
| | | |
| | | using namespace Gdiplus; |
| | | |
| | | #define SAFE_PORT(p) ((p) >= 0 && (p) < (int)m_ports.size()) |
| | | #define SAFE_SLOT(s) ((s) >= 0 && (s) < m_nSlots) |
| | | |
| | | static bool s_gdiplusInited = false; |
| | | static ULONG_PTR s_gdiplusToken = 0; |
| | | static void EnsureGdiplus() |
| | | { |
| | | if (!s_gdiplusInited) |
| | | { |
| | | GdiplusStartupInput in; |
| | | if (GdiplusStartup(&s_gdiplusToken, &in, nullptr) == Ok) |
| | | s_gdiplusInited = true; |
| | | } |
| | | } |
| | | |
| | | BEGIN_MESSAGE_MAP(CCarrierSlotGrid, CWnd) |
| | | ON_WM_ERASEBKGND() |
| | | ON_WM_PAINT() |
| | | ON_WM_CREATE() |
| | | ON_WM_SIZE() |
| | | ON_WM_HSCROLL() |
| | | ON_WM_VSCROLL() // â
æ°å¢ |
| | | ON_WM_LBUTTONDOWN() |
| | | ON_WM_LBUTTONUP() |
| | | ON_WM_MOUSEWHEEL() |
| | | ON_WM_MOUSEMOVE() |
| | | ON_WM_SETCURSOR() |
| | | ON_WM_SHOWWINDOW() |
| | | ON_WM_WINDOWPOSCHANGED() |
| | | END_MESSAGE_MAP() |
| | | |
| | | CCarrierSlotGrid::CCarrierSlotGrid() {} |
| | | CCarrierSlotGrid::~CCarrierSlotGrid() |
| | | { |
| | | if ((HFONT)m_fntText) m_fntText.DeleteObject(); |
| | | if ((HFONT)m_fntBold) m_fntBold.DeleteObject(); |
| | | if ((HFONT)m_fntSmall) m_fntSmall.DeleteObject(); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::PreSubclassWindow() |
| | | { |
| | | CWnd::PreSubclassWindow(); |
| | | if (GetParent() && GetParent()->GetFont()) SetFont(GetParent()->GetFont()); |
| | | EnsureFonts(); |
| | | EnsureGdiplus(); |
| | | |
| | | SetWindowPos(nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| | | } |
| | | |
| | | int CCarrierSlotGrid::OnCreate(LPCREATESTRUCT cs) |
| | | { |
| | | if (CWnd::OnCreate(cs) == -1) return -1; |
| | | if (GetParent() && GetParent()->GetFont()) SetFont(GetParent()->GetFont()); |
| | | EnsureFonts(); |
| | | EnsureGdiplus(); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void CCarrierSlotGrid::EnsureFonts() |
| | | { |
| | | if ((HFONT)m_fntText) return; |
| | | |
| | | LOGFONT lf{}; bool ok = false; |
| | | if (GetParent() && GetParent()->GetFont()) { GetParent()->GetFont()->GetLogFont(&lf); ok = true; } |
| | | else if (GetFont()) { GetFont()->GetLogFont(&lf); ok = true; } |
| | | else { |
| | | NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(NONCLIENTMETRICS); |
| | | if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) { lf = ncm.lfMessageFont; ok = true; } |
| | | } |
| | | if (!ok) { CFont* pDef = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT)); pDef->GetLogFont(&lf); } |
| | | |
| | | m_fntText.CreateFontIndirect(&lf); |
| | | LOGFONT lfb = lf; lfb.lfWeight = FW_SEMIBOLD; m_fntBold.CreateFontIndirect(&lfb); |
| | | LOGFONT lfs = lf; lfs.lfHeight = (LONG)(lf.lfHeight * 0.9); if (lfs.lfHeight == 0) lfs.lfHeight = lf.lfHeight - 1; m_fntSmall.CreateFontIndirect(&lfs); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::InitGrid(int nPorts, int nSlots) |
| | | { |
| | | ASSERT(nPorts >= 1 && nSlots >= 1); |
| | | m_ports.assign(nPorts, PortColumn{}); |
| | | m_portColCXs.assign(nPorts, 180); |
| | | m_nSlots = nSlots; |
| | | for (auto& pc : m_ports) pc.slots.assign(m_nSlots, SlotCell{}); |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetColumnWidths(int slotColWidth, int portColWidth) |
| | | { |
| | | if (slotColWidth > 0) m_slotColCX = slotColWidth; |
| | | if (portColWidth > 0) |
| | | for (size_t i = 0; i < m_portColCXs.size(); ++i) m_portColCXs[i] = portColWidth; |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetRowHeight(int cy) { m_rowHeight = max(18, min(cy, 64)); UpdateScrollRange(); Invalidate(FALSE); } |
| | | void CCarrierSlotGrid::SetHeaderHeight(int cy) { m_headerCY = max(20, min(cy, 48)); UpdateScrollRange(); Invalidate(FALSE); } |
| | | void CCarrierSlotGrid::SetShowMaterialToggle(BOOL bShow) { m_bShowMatToggle = bShow; Invalidate(FALSE); } |
| | | |
| | | void CCarrierSlotGrid::SetPortInfo(int portIndex, LPCTSTR portName, LPCTSTR carrierName) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | if (portName) m_ports[portIndex].portName = portName; |
| | | if (carrierName) m_ports[portIndex].carrierName = carrierName; |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetPortAllocated(int portIndex, BOOL allocated, LPCTSTR byName) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | auto& pc = m_ports[portIndex]; |
| | | pc.allocated = !!allocated; |
| | | pc.allocatedBy = byName ? byName : _T(""); |
| | | if (pc.allocated) |
| | | for (auto& cell : pc.slots) cell.checked = false; |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | BOOL CCarrierSlotGrid::IsPortAllocated(int portIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return FALSE; return m_ports[portIndex].allocated; |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetSlotGlass(int portIndex, int slotIndex, BOOL hasGlass, LPCTSTR coreId, int material) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | cell.hasGlass = !!hasGlass; |
| | | cell.coreId = coreId ? coreId : _T(""); |
| | | cell.material = (material == MAT_G2) ? MAT_G2 : MAT_G1; |
| | | if (!cell.hasGlass) cell.checked = false; |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetSlotChecked(int portIndex, int slotIndex, BOOL checked, BOOL bNotify/* = FALSE*/) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | auto& pc = m_ports[portIndex]; |
| | | if (pc.allocated) return; |
| | | auto& cell = pc.slots[slotIndex]; |
| | | if (!cell.hasGlass) return; |
| | | cell.checked = !!checked; |
| | | if(bNotify) NotifySelectionChanged(portIndex, slotIndex, cell.checked); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | BOOL CCarrierSlotGrid::GetSlotChecked(int portIndex, int slotIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return FALSE; |
| | | return m_ports[portIndex].slots[slotIndex].checked ? TRUE : FALSE; |
| | | } |
| | | |
| | | int CCarrierSlotGrid::GetSlotMaterialType(int portIndex, int slotIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return MAT_G1; |
| | | return m_ports[portIndex].slots[slotIndex].material; |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetSlotMaterialType(int portIndex, int slotIndex, int material, BOOL bNotify) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | auto& pc = m_ports[portIndex]; |
| | | if (pc.allocated) return; |
| | | auto& cell = pc.slots[slotIndex]; |
| | | if (!cell.hasGlass) return; |
| | | int mt = (material == MAT_G2) ? MAT_G2 : MAT_G1; |
| | | if (cell.material != mt) { |
| | | cell.material = mt; |
| | | if (bNotify) NotifyMaterialChanged(portIndex, slotIndex, cell.material); |
| | | Invalidate(FALSE); |
| | | } |
| | | } |
| | | |
| | | CString CCarrierSlotGrid::GetDisplayId(int portIndex, int slotIndex) const |
| | | { |
| | | CString s(_T("â")); |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return s; |
| | | const auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | if (!cell.hasGlass) return s; |
| | | s.Format(_T("G%d-%s"), (cell.material == MAT_G2) ? 2 : 1, cell.coreId.GetString()); |
| | | return s; |
| | | } |
| | | |
| | | void CCarrierSlotGrid::CheckAllInPort(int portIndex, BOOL checked, BOOL bNotify) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | auto& pc = m_ports[portIndex]; |
| | | if (pc.allocated) return; |
| | | for (int r = 0; r < m_nSlots; ++r) { |
| | | auto& cell = pc.slots[r]; |
| | | if (!cell.hasGlass) continue; |
| | | if (cell.checked != !!checked) { |
| | | cell.checked = !!checked; |
| | | if (bNotify) NotifySelectionChanged(portIndex, r, cell.checked); |
| | | } |
| | | } |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::RebuildTexts() { Invalidate(FALSE); } |
| | | |
| | | CSize CCarrierSlotGrid::CalcBestClientSize(int nSlotsOverride) const |
| | | { |
| | | const int slots = (nSlotsOverride > 0) ? nSlotsOverride : m_nSlots; |
| | | int w = m_slotColCX; |
| | | for (int cx : m_portColCXs) w += cx; |
| | | int h = m_headerCY + slots * m_rowHeight; |
| | | return CSize(w, h); |
| | | } |
| | | |
| | | CSize CCarrierSlotGrid::CalcBestWindowSize(BOOL includeNonClient, |
| | | int nSlotsOverride, |
| | | int extraPadX, |
| | | int extraPadY) const |
| | | { |
| | | // 1) åºç¡å®¢æ·åºå°ºå¯¸ï¼å«æä»¬å¨å®¢æ·åºç»ç 1px è¾¹æ¡ï¼å·¦å³+2/ä¸ä¸+2ï¼ |
| | | const CSize content = CalcBestClientSize(nSlotsOverride); |
| | | |
| | | // 2) å DPIãæ»å¨æ¡å°ºå¯¸ï¼å°½éç¨ ForDpiï¼åéå°æ®éï¼ |
| | | UINT dpi = 96; |
| | | #if (_WIN32_WINNT >= 0x0603) |
| | | if (m_hWnd) { |
| | | HMODULE hUser32 = ::GetModuleHandleW(L"user32.dll"); |
| | | if (hUser32) { |
| | | typedef UINT(WINAPI* PFN_GETDPIFORWINDOW)(HWND); |
| | | auto pGetDpiForWindow = (PFN_GETDPIFORWINDOW)::GetProcAddress(hUser32, "GetDpiForWindow"); |
| | | if (pGetDpiForWindow) dpi = pGetDpiForWindow(m_hWnd); |
| | | } |
| | | } |
| | | #endif |
| | | int cxVScroll = ::GetSystemMetrics(SM_CXVSCROLL); |
| | | int cyHScroll = ::GetSystemMetrics(SM_CYHSCROLL); |
| | | #if (_WIN32_WINNT >= 0x0A00) // Win10: å¯ç¨ GetSystemMetricsForDpi |
| | | HMODULE hUser32_2 = ::GetModuleHandleW(L"user32.dll"); |
| | | if (hUser32_2) { |
| | | typedef int (WINAPI* PFN_GSMFD)(int, UINT); |
| | | auto pGsmForDpi = (PFN_GSMFD)::GetProcAddress(hUser32_2, "GetSystemMetricsForDpi"); |
| | | if (pGsmForDpi) { |
| | | cxVScroll = pGsmForDpi(SM_CXVSCROLL, dpi); |
| | | cyHScroll = pGsmForDpi(SM_CYHSCROLL, dpi); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | // 3) DPI èªéåºå®å
¨ä½éï¼é¿å
åæ´è¯¯å·®/主é¢å·®å¼ï¼ |
| | | const int autoPad = max(1, MulDiv(2, (int)dpi, 96)); // 约çäº 2px@96DPI |
| | | const int padX = (extraPadX >= 0) ? extraPadX : autoPad; |
| | | const int padY = (extraPadY >= 0) ? extraPadY : autoPad; |
| | | |
| | | // 4) è¿ä»£ï¼èèæ»å¨æ¡ç¸äºå½±åï¼ç´å°ç¨³å®ä¸éè¦æ»å¨æ¡ |
| | | int needCx = content.cx + padX; |
| | | int needCy = content.cy + padY; |
| | | |
| | | while (true) { |
| | | bool needV = (GetTotalContentWidth() > needCx); // 宽ä¸å¤âä¼åºç°æ¨ªåæ»å¨æ¡ï¼ï¼æ³¨æï¼æ¨ªæ¡å é«åº¦ï¼ |
| | | bool needH = (m_headerCY + (nSlotsOverride > 0 ? nSlotsOverride : m_nSlots) * m_rowHeight + 2 /*客æ·åºè¾¹æ¡*/ > needCy); // é«ä¸å¤âä¼åºç°çºµæ¡ï¼ï¼çºµæ¡å å®½åº¦ï¼ |
| | | |
| | | // 注æï¼åºç°âçºµåæ¡âä¼åå°å¯ç¨å®½åº¦ï¼åºç°âæ¨ªåæ¡âä¼åå°å¯ç¨é«åº¦ |
| | | // æä»¬ç®æ æ¯è®©âå³ä½¿æ£æè¿äºå ä½âåä¹ä»ç¶ >= å
容尺寸 |
| | | int adjCx = content.cx + padX + (needH ? cxVScroll : 0); |
| | | int adjCy = content.cy + padY + (needV ? cyHScroll : 0); |
| | | |
| | | if (adjCx <= needCx && adjCy <= needCy) break; // 稳å®ï¼å½å needCx/needCy è¶³å¤ |
| | | needCx = max(needCx, adjCx); |
| | | needCy = max(needCy, adjCy); |
| | | } |
| | | |
| | | if (!includeNonClient) return CSize(needCx, needCy); |
| | | |
| | | // 5) æâçæ³å®¢æ·åºå°ºå¯¸âæ¢ç®æçªå£å¤æ¡å°ºå¯¸ï¼å»æ WS_H/VSCROLL 忢ç®ï¼ |
| | | RECT rc = { 0, 0, needCx, needCy }; |
| | | DWORD style = GetStyle(); // â
ç¨ç宿 ·å¼ï¼è®©ç³»ç»ææ»å¨æ¡é客æ·åºä¸å¹¶ç®è¿å» |
| | | DWORD exStyle = GetExStyle(); |
| | | ::AdjustWindowRectEx(&rc, style, FALSE, exStyle); |
| | | return CSize(rc.right - rc.left, rc.bottom - rc.top); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::DisableSystemScrollbars() |
| | | { |
| | | // å»ææ ·å¼ |
| | | ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, 0); |
| | | // éèï¼å
¼å®¹æ§ï¼ |
| | | ShowScrollBar(SB_HORZ, FALSE); |
| | | ShowScrollBar(SB_VERT, FALSE); |
| | | // æ¸
空æ»å¨ä¿¡æ¯ |
| | | SCROLLINFO si{ sizeof(SCROLLINFO) }; si.fMask = SIF_ALL; si.nMin = 0; si.nMax = 0; si.nPage = 0; si.nPos = 0; |
| | | SetScrollInfo(SB_HORZ, &si, TRUE); |
| | | SetScrollInfo(SB_VERT, &si, TRUE); |
| | | // 让é客æ·åºéç® |
| | | SetWindowPos(nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| | | Invalidate(FALSE); |
| | | } |
| | | |
| | | // 注æï¼è¿éç¨âæ æ»å¨æ¡æ ·å¼âæ¥æ¢ç®çªå£å¤æ¡å°ºå¯¸ï¼ç¡®ä¿å®¢æ·åº=å
容尺寸 + æä»¬å®¢æ·åºè¾¹æ¡ |
| | | void CCarrierSlotGrid::ResizeWindowToFitAll(BOOL includeNonClient, int nSlotsOverride) |
| | | { |
| | | // 计ç®å
容æé客æ·åºï¼CalcBestClientSize å
å·²å
嫿们客æ·åº1pxè¾¹æ¡ç +2ï¼ |
| | | CSize need = CalcBestClientSize(nSlotsOverride); |
| | | |
| | | if (!includeNonClient) { |
| | | SetWindowPos(nullptr, 0, 0, need.cx, need.cy, |
| | | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
| | | return; |
| | | } |
| | | |
| | | RECT rc = { 0, 0, need.cx, need.cy }; |
| | | DWORD style = GetStyle() & ~(WS_HSCROLL | WS_VSCROLL); // â ç¨âæ æ»å¨æ¡âçæ ·å¼æ¥æ¢ç® |
| | | DWORD exStyle = GetExStyle(); |
| | | ::AdjustWindowRectEx(&rc, style, FALSE, exStyle); |
| | | |
| | | int w = rc.right - rc.left; |
| | | int h = rc.bottom - rc.top; |
| | | |
| | | SetWindowPos(nullptr, 0, 0, w, h, |
| | | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::SetNoScrollbarsMode(BOOL enable) |
| | | { |
| | | m_noScrollbars = !!enable; |
| | | |
| | | if (m_noScrollbars) { |
| | | // 1) åç§»æ¸
é¶ |
| | | m_scrollX = 0; |
| | | m_scrollY = 0; |
| | | |
| | | // 2) å»ææ ·å¼å¹¶éèæ¡ |
| | | ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, 0); |
| | | ShowScrollBar(SB_BOTH, FALSE); |
| | | |
| | | // 3) æ¸
空æ»å¨ä¿¡æ¯ï¼å³ä¾¿èµæºéåæ¬å¸¦äºæ ·å¼ï¼ä¹ä¸åå½±åï¼ |
| | | SCROLLINFO si{ sizeof(SCROLLINFO) }; si.fMask = SIF_ALL; |
| | | SetScrollInfo(SB_HORZ, &si, TRUE); |
| | | SetScrollInfo(SB_VERT, &si, TRUE); |
| | | |
| | | // 4) éç¥ç³»ç»é客æ·åºå·æ°ï¼ç¡®ä¿æ¡è¢«å½»åºç§»é¤ |
| | | SetWindowPos(nullptr, 0, 0, 0, 0, |
| | | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| | | |
| | | Invalidate(FALSE); |
| | | } |
| | | else { |
| | | // éåºæ æ»å¨æ¡æ¨¡å¼ï¼ä»
æ¢å¤æ ·å¼ï¼å®é
èå´ä¼å¨ UpdateScrollRange ä¸éæ°è®¾ç½® |
| | | ModifyStyle(0, WS_HSCROLL | WS_VSCROLL, 0); |
| | | SetWindowPos(nullptr, 0, 0, 0, 0, |
| | | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::FitWindowToContentNoScroll(BOOL includeNonClient, int nSlotsOverride) |
| | | { |
| | | // ç¡®ä¿å·²å¤äºâæ æ»å¨æ¡æ¨¡å¼âï¼é²æ¢ç³»ç»å¨ AdjustWindowRectEx æ¶é¢çæ»å¨æ¡é客æ·åº |
| | | SetNoScrollbarsMode(TRUE); |
| | | |
| | | // ä½ èªå·±ç CalcBestClientSize å·²å
å«å®¢æ·åº 1px è¾¹æ¡(+2)çä¿®æ£ |
| | | CSize needCli = CalcBestClientSize(nSlotsOverride); |
| | | |
| | | if (!includeNonClient) { |
| | | SetWindowPos(nullptr, 0, 0, needCli.cx, needCli.cy, |
| | | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
| | | return; |
| | | } |
| | | |
| | | RECT rc{ 0, 0, needCli.cx, needCli.cy }; |
| | | // 注æï¼æ¤æ¶çªå£æ ·å¼å·²ç»æ²¡æ WS_H/VSCROLL äºââç¨ç宿 ·å¼æ¢ç®å³å¯ |
| | | ::AdjustWindowRectEx(&rc, GetStyle(), FALSE, GetExStyle()); |
| | | const int w = rc.right - rc.left; |
| | | const int h = rc.bottom - rc.top; |
| | | |
| | | SetWindowPos(nullptr, 0, 0, w, h, |
| | | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
| | | } |
| | | |
| | | // ---------- å ä½ ---------- |
| | | CRect CCarrierSlotGrid::GetClientRectNoSB() const |
| | | { |
| | | CRect rc; GetClientRect(&rc); return rc; |
| | | } |
| | | CRect CCarrierSlotGrid::GetHeaderRect() const |
| | | { |
| | | CRect rc = GetClientRectNoSB(); rc.bottom = rc.top + m_headerCY; return rc; |
| | | } |
| | | int CCarrierSlotGrid::GetTotalContentWidth() const |
| | | { |
| | | int w = m_slotColCX; |
| | | for (int cx : m_portColCXs) w += cx; |
| | | return w; |
| | | } |
| | | CRect CCarrierSlotGrid::GetHeaderItemRect(int iItem) const |
| | | { |
| | | CRect rcHeader = GetHeaderRect(); |
| | | int x = rcHeader.left - m_scrollX; |
| | | if (iItem == 0) |
| | | return CRect(x, rcHeader.top, x + m_slotColCX, rcHeader.bottom); |
| | | |
| | | x += m_slotColCX; |
| | | for (int c = 1; c < iItem; ++c) x += m_portColCXs[c - 1]; |
| | | int w = m_portColCXs[iItem - 1]; |
| | | return CRect(x, rcHeader.top, x + w, rcHeader.bottom); |
| | | } |
| | | BOOL CCarrierSlotGrid::GetCellRect(int row, int sub, CRect& rc) const |
| | | { |
| | | CRect cli = GetClientRectNoSB(); |
| | | int y0 = cli.top + m_headerCY - m_scrollY; |
| | | int top = y0 + row * m_rowHeight; |
| | | int bottom = top + m_rowHeight; |
| | | if (bottom <= cli.top + m_headerCY || top >= cli.bottom) return FALSE; |
| | | |
| | | int x = cli.left - m_scrollX; |
| | | if (sub == 0) { rc = CRect(x, top, x + m_slotColCX, bottom); return TRUE; } |
| | | x += m_slotColCX; |
| | | for (int c = 1; c < sub; ++c) x += m_portColCXs[c - 1]; |
| | | int w = m_portColCXs[sub - 1]; |
| | | rc = CRect(x, top, x + w, bottom); |
| | | return TRUE; |
| | | } |
| | | CRect CCarrierSlotGrid::GetHeaderCheckboxRect(int iItem) const |
| | | { |
| | | CRect rItem = GetHeaderItemRect(iItem); |
| | | const int box = 16; |
| | | const int padR = 6; |
| | | int vpad = max(0, (rItem.Height() - box) / 2); |
| | | return CRect(rItem.right - padR - box, rItem.top + vpad, rItem.right - padR, rItem.bottom - vpad); |
| | | } |
| | | CRect CCarrierSlotGrid::GetCheckboxRect(const CRect& cell) const |
| | | { |
| | | int sz = max(14, min(int(m_rowHeight * 0.70), 20)); |
| | | int leftPad = 8; |
| | | int top = cell.top + (cell.Height() - sz) / 2; |
| | | return CRect(cell.left + leftPad, top, cell.left + leftPad + sz, top + sz); |
| | | } |
| | | CRect CCarrierSlotGrid::GetMaterialTagRect(const CRect& cell) const |
| | | { |
| | | int h = max(14, min(int(m_rowHeight * 0.65), m_rowHeight - 8)); |
| | | int w = 32; |
| | | int gap = 6; |
| | | int rightPadForDot = 16; |
| | | int top = cell.top + (cell.Height() - h) / 2; |
| | | int right = cell.right - rightPadForDot - gap; |
| | | return CRect(right - w, top, right, top + h); |
| | | } |
| | | CRect CCarrierSlotGrid::GetStatusDotRect(const CRect& cell) const |
| | | { |
| | | int d = max(8, min(int(m_rowHeight * 0.42), 12)); |
| | | int rightPad = 6; |
| | | int top = cell.top + (cell.Height() - d) / 2; |
| | | return CRect(cell.right - rightPad - d, top, cell.right - rightPad, top + d); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::UpdateScrollRange() |
| | | { |
| | | if (m_noScrollbars) { |
| | | // ç¡®ä¿åç§»ä¸ç´ä¸º 0ï¼ä¸è®¾ä»»ä½æ»å¨ä¿¡æ¯ |
| | | m_scrollX = 0; |
| | | m_scrollY = 0; |
| | | return; |
| | | } |
| | | |
| | | CRect rc; GetClientRect(&rc); |
| | | |
| | | // åç´ |
| | | const int contentH = m_headerCY + m_nSlots * m_rowHeight; |
| | | const int pageY = max(1, rc.Height()); |
| | | const int maxPosY = max(0, contentH - pageY); |
| | | m_scrollY = max(0, min(m_scrollY, maxPosY)); |
| | | SCROLLINFO siY = { sizeof(SCROLLINFO) }; |
| | | siY.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; |
| | | siY.nMin = 0; siY.nMax = contentH - 1; siY.nPage = pageY; siY.nPos = m_scrollY; |
| | | SetScrollInfo(SB_VERT, &siY, TRUE); |
| | | |
| | | // æ°´å¹³ |
| | | const int contentW = GetTotalContentWidth(); |
| | | const int pageX = max(1, rc.Width()); |
| | | const int maxPosX = max(0, contentW - pageX); |
| | | m_scrollX = max(0, min(m_scrollX, maxPosX)); |
| | | SCROLLINFO siX = { sizeof(SCROLLINFO) }; |
| | | siX.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; |
| | | siX.nMin = 0; siX.nMax = contentW - 1; siX.nPage = pageX; siX.nPos = m_scrollX; |
| | | SetScrollInfo(SB_HORZ, &siX, TRUE); |
| | | } |
| | | |
| | | // ---------- 表头åé线å½ä¸ ---------- |
| | | int CCarrierSlotGrid::HitHeaderEdge(CPoint pt) const |
| | | { |
| | | if (!m_bAllowResize) return -1; // â æ°å¢ |
| | | if (!GetHeaderRect().PtInRect(pt)) return -1; |
| | | const int tol = 4; |
| | | int x = GetHeaderRect().left - m_scrollX + m_slotColCX; |
| | | if (abs(pt.x - x) <= tol) return 0; |
| | | |
| | | int cum = GetHeaderRect().left - m_scrollX + m_slotColCX; |
| | | for (int i = 0; i <= GetPortCount() - 2; ++i) { |
| | | cum += m_portColCXs[i]; |
| | | if (abs(pt.x - cum) <= tol) return i + 1; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | // ---------- ç»å¶ ---------- |
| | | BOOL CCarrierSlotGrid::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } |
| | | |
| | | void CCarrierSlotGrid::DrawFlatCheckbox(CDC* pDC, const CRect& r, bool checked, bool disabled) |
| | | { |
| | | CBrush br(disabled ? RGB(245, 245, 245) : RGB(255, 255, 255)); |
| | | CPen pen(PS_SOLID, 1, disabled ? RGB(200, 200, 200) : RGB(130, 130, 135)); |
| | | CBrush* pOldB = pDC->SelectObject(&br); |
| | | CPen* pOldP = pDC->SelectObject(&pen); |
| | | pDC->RoundRect(r, CPoint(3, 3)); |
| | | pDC->SelectObject(pOldB); pDC->SelectObject(pOldP); |
| | | |
| | | if (!checked) return; |
| | | COLORREF c = disabled ? RGB(160, 160, 160) : RGB(40, 150, 90); |
| | | CPen penTick(PS_SOLID, max(2, r.Height() / 8), c); |
| | | CPen* pOld = pDC->SelectObject(&penTick); |
| | | POINT p1 = { r.left + r.Width() * 2 / 9, r.top + r.Height() * 5 / 9 }; |
| | | POINT p2 = { r.left + r.Width() * 4 / 9, r.top + r.Height() * 7 / 9 }; |
| | | POINT p3 = { r.left + r.Width() * 7 / 9, r.top + r.Height() * 3 / 9 }; |
| | | pDC->MoveTo(p1); pDC->LineTo(p2); pDC->LineTo(p3); |
| | | pDC->SelectObject(pOld); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::PaintTo(CDC* pDC) |
| | | { |
| | | EnsureGdiplus(); |
| | | |
| | | CRect cli = GetClientRectNoSB(); |
| | | pDC->FillSolidRect(cli, m_colBg); |
| | | |
| | | // Header |
| | | CRect rh = GetHeaderRect(); |
| | | pDC->FillSolidRect(rh, ::GetSysColor(COLOR_BTNFACE)); |
| | | CPen penSep(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); |
| | | CPen* pOldPen = pDC->SelectObject(&penSep); |
| | | pDC->MoveTo(rh.left, rh.bottom - 1); pDC->LineTo(rh.right, rh.bottom - 1); |
| | | pDC->SelectObject(pOldPen); |
| | | |
| | | for (int i = 0; i <= GetPortCount(); ++i) |
| | | { |
| | | CRect rItem = GetHeaderItemRect(i); |
| | | |
| | | // ä¿®æ¹ä¸ºï¼ |
| | | if (i < GetPortCount()) { // â
æåä¸åä¸ç»åé线 |
| | | CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); |
| | | pOldPen = pDC->SelectObject(&pen); |
| | | pDC->MoveTo(rItem.right - 1, rItem.top); |
| | | pDC->LineTo(rItem.right - 1, rItem.bottom); |
| | | pDC->SelectObject(pOldPen); |
| | | } |
| | | |
| | | CString text; |
| | | if (i == 0) { |
| | | text = _T("Slot"); |
| | | CRect rt = rItem; rt.DeflateRect(6, 0, 6, 0); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SelectObject(&m_fntBold); |
| | | pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); |
| | | pDC->DrawText(text, rt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); |
| | | } |
| | | else { |
| | | const auto& pc = m_ports[i - 1]; |
| | | int selected = 0; bool any = false, all = true; |
| | | for (const auto& cell : pc.slots) { |
| | | if (cell.hasGlass) { any = true; if (cell.checked) ++selected; else all = false; } |
| | | } |
| | | if (!any) all = false; |
| | | |
| | | CString leftTitle = pc.carrierName.IsEmpty() |
| | | ? pc.portName |
| | | : (pc.portName + _T(" (") + pc.carrierName + _T(")")); |
| | | |
| | | // å¾éæ¡é å³ |
| | | CRect rcCb = GetHeaderCheckboxRect(i); |
| | | DrawFlatCheckbox(pDC, rcCb, all, pc.allocated); |
| | | |
| | | // 计æ°è´´è¿å¾éæ¡å·¦ä¾§ |
| | | CString cnt; cnt.Format(_T("%d/%d"), selected, m_nSlots); |
| | | SIZE szCnt{ 0,0 }; |
| | | { CFont* o = pDC->SelectObject(&m_fntBold); |
| | | GetTextExtentPoint32(pDC->GetSafeHdc(), cnt, cnt.GetLength(), &szCnt); |
| | | pDC->SelectObject(o); } |
| | | const int gap = 6; |
| | | CRect rcCnt(rcCb.left - gap - szCnt.cx, rItem.top, rcCb.left - gap, rItem.bottom); |
| | | |
| | | // 左侧æ é¢ |
| | | CRect rt = rItem; rt.DeflateRect(6, 0, (rItem.right - rcCnt.left) + 6, 0); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SelectObject(&m_fntBold); |
| | | pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); |
| | | pDC->DrawText(leftTitle, rt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); |
| | | |
| | | // è®¡æ° |
| | | pDC->SelectObject(&m_fntBold); |
| | | pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); |
| | | pDC->DrawText(cnt, rcCnt, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); |
| | | } |
| | | } |
| | | |
| | | // Cells |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | for (int s = 0; s <= GetPortCount(); ++s) |
| | | { |
| | | CRect rc; |
| | | if (!GetCellRect(r, s, rc)) continue; |
| | | |
| | | COLORREF bk = m_colBg; |
| | | if (s >= 1) { |
| | | int port = s - 1; |
| | | if (port % 2 == 0) bk = m_colAlt; |
| | | if (SAFE_PORT(port) && m_ports[port].allocated) bk = m_colLock; |
| | | } |
| | | pDC->FillSolidRect(rc, bk); |
| | | |
| | | CPen penMajor(PS_SOLID, (s >= 1 && ((s - 1) % 2 == 0)) ? 2 : 1, m_gridMajor); |
| | | CPen* pOld = pDC->SelectObject(&penMajor); |
| | | pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.right, rc.top); |
| | | pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.left, rc.bottom); |
| | | pDC->SelectObject(pOld); |
| | | |
| | | CPen penMinor(PS_SOLID, 1, m_gridMinor); |
| | | pOld = pDC->SelectObject(&penMinor); |
| | | if (s == GetPortCount()) { pDC->MoveTo(rc.right - 1, rc.top); pDC->LineTo(rc.right - 1, rc.bottom); } |
| | | if (r == m_nSlots - 1) { pDC->MoveTo(rc.left, rc.bottom - 1); pDC->LineTo(rc.right, rc.bottom - 1); } |
| | | pDC->SelectObject(pOld); |
| | | |
| | | if (s == 0) { |
| | | CString sl; sl.Format(_T("Slot %d"), r + 1); |
| | | CRect rt = rc; rt.DeflateRect(8, 0, 8, 0); |
| | | pDC->SelectObject(&m_fntBold); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(RGB(60, 60, 64)); |
| | | pDC->DrawText(sl, rt, DT_LEFT | DT_VCENTER | DT_SINGLELINE); |
| | | } |
| | | else { |
| | | int port = s - 1; |
| | | const auto& pc = m_ports[port]; |
| | | const auto& cell = pc.slots[r]; |
| | | |
| | | CRect rChk = GetCheckboxRect(rc); |
| | | DrawFlatCheckbox(pDC, rChk, cell.checked, pc.allocated || !cell.hasGlass); |
| | | |
| | | CString t = GetDisplayId(port, r); |
| | | CRect rText = rc; |
| | | int leftPad = rChk.right + 6; |
| | | CRect rDot = GetStatusDotRect(rc); |
| | | CRect rTag = GetMaterialTagRect(rc); |
| | | int rightPad = rc.right - min(rTag.left - 6, rDot.left - 6); |
| | | rText.DeflateRect(leftPad - rc.left, 0, rightPad, 0); |
| | | |
| | | pDC->SelectObject(&m_fntText); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(cell.hasGlass ? m_text : m_textDim); |
| | | pDC->DrawText(t, rText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); |
| | | |
| | | if (m_bShowMatToggle) |
| | | { |
| | | CRect rT = GetMaterialTagRect(rc); |
| | | COLORREF crBorder = (cell.material == MAT_G2) ? RGB(180, 150, 220) : RGB(120, 160, 220); |
| | | COLORREF crFill = (cell.material == MAT_G2) ? RGB(243, 235, 250) : RGB(233, 240, 252); |
| | | COLORREF crText = (cell.material == MAT_G2) ? RGB(90, 60, 150) : RGB(50, 90, 160); |
| | | if (pc.allocated || !cell.hasGlass) { crBorder = RGB(210, 210, 210); crFill = RGB(245, 245, 245); crText = RGB(160, 160, 160); } |
| | | CBrush br(crFill); CPen tagPen(PS_SOLID, 1, crBorder); |
| | | CPen* pOldP = pDC->SelectObject(&tagPen); |
| | | CBrush* pOldB = pDC->SelectObject(&br); |
| | | pDC->RoundRect(rT, CPoint(6, 6)); |
| | | pDC->SelectObject(pOldB); pDC->SelectObject(pOldP); |
| | | CString tx; tx.Format(_T("G%d"), (cell.material == MAT_G2) ? 2 : 1); |
| | | pDC->SelectObject(&m_fntSmall); |
| | | pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(crText); |
| | | pDC->DrawText(tx, rT, DT_CENTER | DT_VCENTER | DT_SINGLELINE); |
| | | } |
| | | |
| | | // ç¶æç¹ï¼GDI+ æé¯é½¿ï¼ |
| | | { |
| | | Graphics g(pDC->GetSafeHdc()); |
| | | g.SetSmoothingMode(SmoothingModeAntiAlias); |
| | | COLORREF c = cell.hasGlass ? (pc.allocated ? RGB(215, 160, 60) : RGB(60, 170, 80)) : RGB(160, 160, 160); |
| | | SolidBrush brush(Color(255, GetRValue(c), GetGValue(c), GetBValue(c))); |
| | | Pen outline(Color(255, 120, 120, 120), 1.f); |
| | | g.FillEllipse(&brush, rDot.left, rDot.top, rDot.Width(), rDot.Height()); |
| | | g.DrawEllipse(&outline, (REAL)rDot.left, (REAL)rDot.top, (REAL)rDot.Width(), (REAL)rDot.Height()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | // ===== 卿¯ä¸ªå·²åé
(allocated)çåä¸å¤®ç»å¶åéæ LOCK æ°´å°ï¼ç¨ HDC+LOGFONT æé åä½ï¼===== |
| | | { |
| | | Gdiplus::Graphics g(pDC->GetSafeHdc()); |
| | | g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); |
| | | |
| | | CRect cli = GetClientRectNoSB(); |
| | | CRect rh = GetHeaderRect(); |
| | | |
| | | // åå½å UI åä½ï¼ä¼å
ç²ä½ï¼ |
| | | LOGFONT lf{}; |
| | | if ((HFONT)m_fntBold) m_fntBold.GetLogFont(&lf); |
| | | else if ((HFONT)m_fntText) m_fntText.GetLogFont(&lf); |
| | | |
| | | for (int i = 0; i < GetPortCount(); ++i) |
| | | { |
| | | if (!m_ports[i].allocated) continue; |
| | | |
| | | // åç©å½¢ï¼é¤å»è¡¨å¤´ï¼èèæ°´å¹³æ»å¨ï¼ |
| | | CRect rCol = GetHeaderItemRect(i + 1); |
| | | rCol.top = rh.bottom; |
| | | rCol.bottom = cli.bottom; |
| | | if (rCol.right <= cli.left || rCol.left >= cli.right || rCol.Height() <= 0) continue; |
| | | |
| | | // èªéåºä¸ä¸ªåéçåç´ é«åº¦ |
| | | int availW = rCol.Width() - 12; |
| | | int availH = rCol.Height() - 12; |
| | | int emPx = max(16, min(min(availW / 3, availH / 5), 72)); |
| | | if (emPx < 16) emPx = 16; |
| | | // åå·ååï¼å¹¶ç»ä¸ªæ´ä½çå
åºï¼é¿å
太å°ï¼ |
| | | emPx = max(12, emPx / 2); |
| | | |
| | | // ç¨ LOGFONTW + HDC æé GDI+ åä½ |
| | | LOGFONTW lfw{}; |
| | | #ifdef UNICODE |
| | | lfw = *reinterpret_cast<LOGFONTW*>(&lf); |
| | | #else |
| | | lfw.lfHeight = lf.lfHeight; |
| | | lfw.lfWidth = lf.lfWidth; |
| | | lfw.lfEscapement = lf.lfEscapement; |
| | | lfw.lfOrientation = lf.lfOrientation; |
| | | lfw.lfWeight = lf.lfWeight; |
| | | lfw.lfItalic = lf.lfItalic; |
| | | lfw.lfUnderline = lf.lfUnderline; |
| | | lfw.lfStrikeOut = lf.lfStrikeOut; |
| | | lfw.lfCharSet = lf.lfCharSet; |
| | | lfw.lfOutPrecision = lf.lfOutPrecision; |
| | | lfw.lfClipPrecision = lf.lfClipPrecision; |
| | | lfw.lfQuality = lf.lfQuality; |
| | | lfw.lfPitchAndFamily = lf.lfPitchAndFamily; |
| | | MultiByteToWideChar(CP_ACP, 0, lf.lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE); |
| | | #endif |
| | | lfw.lfHeight = -emPx; // è´å¼=æåç´ é«åº¦ |
| | | lfw.lfWeight = FW_BOLD; |
| | | |
| | | Gdiplus::Font gdifont(pDC->GetSafeHdc(), &lfw); // â
å ä¸ Gdiplus:: |
| | | Gdiplus::StringFormat fmt; |
| | | fmt.SetAlignment(Gdiplus::StringAlignmentCenter); |
| | | fmt.SetLineAlignment(Gdiplus::StringAlignmentCenter); |
| | | Gdiplus::Color col(140, 120, 100, 60); // åéæ |
| | | Gdiplus::SolidBrush brush(col); |
| | | Gdiplus::RectF box((Gdiplus::REAL)rCol.left, (Gdiplus::REAL)rCol.top, |
| | | (Gdiplus::REAL)rCol.Width(), (Gdiplus::REAL)rCol.Height()); |
| | | |
| | | if (gdifont.GetLastStatus() == Gdiplus::Ok) { |
| | | g.DrawString(L"LOCK", -1, &gdifont, box, &fmt, &brush); |
| | | } |
| | | else { |
| | | Gdiplus::Font fallback(L"Arial", (Gdiplus::REAL)emPx, Gdiplus::FontStyleBold, Gdiplus::UnitPixel); |
| | | g.DrawString(L"LOCK", -1, &fallback, box, &fmt, &brush); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // === 客æ·åºå
1px ç°è²è¾¹æ¡ï¼ä¸å
æ»å¨æ¡ï¼ä½ä¸ä¼ç¼ºè§/æ¢ç»å¶ï¼=== |
| | | { |
| | | CRect cli; GetClientRect(&cli); |
| | | |
| | | // ç¨ FrameRect æ´ç¨³ï¼é¿å
å³ä¸è§ä¸¢çº¿ï¼ |
| | | CBrush br; br.CreateSolidBrush(::GetSysColor(COLOR_3DSHADOW)); |
| | | CRect r = cli; |
| | | // 注æï¼å®¢æ·åºåæ æ¯ [0..width, 0..height]ï¼FrameRect ä¼å¨å
ä¾§ç» 1px |
| | | pDC->FrameRect(&r, &br); |
| | | br.DeleteObject(); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnPaint() |
| | | { |
| | | CPaintDC dc(this); |
| | | CRect rc; GetClientRect(&rc); |
| | | |
| | | CDC mem; mem.CreateCompatibleDC(&dc); |
| | | CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height()); |
| | | HGDIOBJ ob = mem.SelectObject(bmp); |
| | | |
| | | PaintTo(&mem); |
| | | dc.BitBlt(0, 0, rc.Width(), rc.Height(), &mem, 0, 0, SRCCOPY); |
| | | |
| | | mem.SelectObject(ob); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnSize(UINT nType, int cx, int cy) |
| | | { |
| | | CWnd::OnSize(nType, cx, cy); |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pBar) |
| | | { |
| | | if (m_noScrollbars) return; // â æ°å¢ |
| | | |
| | | UNREFERENCED_PARAMETER(pBar); |
| | | |
| | | SCROLLINFO si = { sizeof(SCROLLINFO) }; |
| | | si.fMask = SIF_ALL; |
| | | GetScrollInfo(SB_HORZ, &si); |
| | | |
| | | int pos = m_scrollX; |
| | | const int maxPos = max(0, (int)si.nMax - (int)si.nPage + 1); |
| | | |
| | | switch (nSBCode) |
| | | { |
| | | case SB_LINELEFT: pos -= 30; break; |
| | | case SB_LINERIGHT: pos += 30; break; |
| | | case SB_PAGELEFT: pos -= (int)si.nPage; break; |
| | | case SB_PAGERIGHT: pos += (int)si.nPage; break; |
| | | case SB_THUMBTRACK: |
| | | case SB_THUMBPOSITION: |
| | | pos = (int)si.nTrackPos; // â
32 使å¨ä½ç½® |
| | | break; |
| | | default: |
| | | return; |
| | | } |
| | | |
| | | pos = max(0, min(pos, maxPos)); |
| | | if (pos != m_scrollX) { |
| | | m_scrollX = pos; |
| | | SetScrollPos(SB_HORZ, m_scrollX); |
| | | Invalidate(FALSE); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pBar) |
| | | { |
| | | if (m_noScrollbars) return; // â æ°å¢ |
| | | |
| | | UNREFERENCED_PARAMETER(pBar); |
| | | |
| | | SCROLLINFO si = { sizeof(SCROLLINFO) }; |
| | | si.fMask = SIF_ALL; |
| | | GetScrollInfo(SB_VERT, &si); |
| | | |
| | | int pos = m_scrollY; |
| | | const int maxPos = max(0, (int)si.nMax - (int)si.nPage + 1); |
| | | |
| | | switch (nSBCode) |
| | | { |
| | | case SB_LINEUP: pos -= m_rowHeight; break; |
| | | case SB_LINEDOWN: pos += m_rowHeight; break; |
| | | case SB_PAGEUP: pos -= (int)si.nPage; break; |
| | | case SB_PAGEDOWN: pos += (int)si.nPage; break; |
| | | case SB_THUMBTRACK: |
| | | case SB_THUMBPOSITION: |
| | | pos = (int)si.nTrackPos; // â
32 使å¨ä½ç½® |
| | | break; |
| | | default: |
| | | return; |
| | | } |
| | | |
| | | pos = max(0, min(pos, maxPos)); |
| | | if (pos != m_scrollY) { |
| | | m_scrollY = pos; |
| | | SetScrollPos(SB_VERT, m_scrollY); |
| | | Invalidate(FALSE); |
| | | } |
| | | } |
| | | |
| | | BOOL CCarrierSlotGrid::OnMouseWheel(UINT, short zDelta, CPoint) |
| | | { |
| | | if (m_noScrollbars) return FALSE; // â æ°å¢ï¼å½»åºä¸æ» |
| | | |
| | | int delta = (zDelta > 0 ? -1 : +1) * (m_rowHeight * 3); |
| | | m_scrollY = max(0, m_scrollY + delta); |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | return TRUE; |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnShowWindow(BOOL bShow, UINT nStatus) |
| | | { |
| | | CWnd::OnShowWindow(bShow, nStatus); |
| | | if (bShow) { UpdateScrollRange(); Invalidate(FALSE); } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnWindowPosChanged(WINDOWPOS* wp) |
| | | { |
| | | CWnd::OnWindowPosChanged(wp); |
| | | if (wp && (wp->flags & SWP_SHOWWINDOW)) { UpdateScrollRange(); Invalidate(FALSE); } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnLButtonDown(UINT nFlags, CPoint pt) |
| | | { |
| | | // æ¯å¦æå¨å宽 |
| | | int edge = m_bAllowResize ? HitHeaderEdge(pt) : -1; // â ä¿®æ¹ |
| | | if (edge >= 0) |
| | | { |
| | | m_bResizing = true; |
| | | m_resizeEdge = edge; |
| | | m_resizeStartX = pt.x; |
| | | m_slotColCXStart = m_slotColCX; |
| | | m_portColCXsStart = m_portColCXs; |
| | | SetCapture(); |
| | | return; |
| | | } |
| | | |
| | | // Header ç¹å»ï¼ä»
å¤éæ¡åºåï¼ |
| | | if (GetHeaderRect().PtInRect(pt)) |
| | | { |
| | | for (int i = 1; i <= GetPortCount(); ++i) |
| | | { |
| | | CRect rItem = GetHeaderItemRect(i); |
| | | if (!rItem.PtInRect(pt)) continue; |
| | | |
| | | CRect rcCb = GetHeaderCheckboxRect(i); |
| | | if (!rcCb.PtInRect(pt)) return; |
| | | |
| | | int port = i - 1; |
| | | if (!SAFE_PORT(port) || m_ports[port].allocated) return; |
| | | |
| | | bool any = false, all = true; |
| | | for (auto& cell : m_ports[port].slots) { |
| | | if (!cell.hasGlass) continue; |
| | | any = true; if (!cell.checked) { all = false; break; } |
| | | } |
| | | if (!any) return; |
| | | CheckAllInPort(port, all ? FALSE : TRUE, TRUE); |
| | | return; |
| | | } |
| | | return; |
| | | } |
| | | |
| | | // Cell ç¹å» |
| | | CRect cli = GetClientRectNoSB(); |
| | | if (pt.y < cli.top + m_headerCY) return; |
| | | int yIn = pt.y - (cli.top + m_headerCY) + m_scrollY; |
| | | int row = yIn / m_rowHeight; |
| | | if (!SAFE_SLOT(row)) return; |
| | | |
| | | int x = pt.x + m_scrollX - cli.left; |
| | | int sub = 0; |
| | | if (x < m_slotColCX) sub = 0; |
| | | else { |
| | | x -= m_slotColCX; |
| | | sub = 1; |
| | | for (size_t i = 0; i < m_portColCXs.size(); ++i) { |
| | | if (x < m_portColCXs[i]) { sub = (int)i + 1; break; } |
| | | x -= m_portColCXs[i]; |
| | | sub = (int)i + 2; |
| | | } |
| | | if (sub < 1 || sub > GetPortCount()) return; |
| | | } |
| | | |
| | | if (sub == 0) return; |
| | | int port = sub - 1; |
| | | if (!SAFE_PORT(port)) return; |
| | | |
| | | auto& pc = m_ports[port]; |
| | | auto& cell = pc.slots[row]; |
| | | |
| | | CRect rc; if (!GetCellRect(row, sub, rc)) return; |
| | | |
| | | if (pc.allocated || !cell.hasGlass) return; |
| | | |
| | | if (GetCheckboxRect(rc).PtInRect(pt)) |
| | | { |
| | | cell.checked = !cell.checked; |
| | | NotifySelectionChanged(port, row, cell.checked); |
| | | Invalidate(FALSE); |
| | | return; |
| | | } |
| | | |
| | | if (m_bShowMatToggle && GetMaterialTagRect(rc).PtInRect(pt)) |
| | | { |
| | | cell.material = (cell.material == MAT_G1) ? MAT_G2 : MAT_G1; |
| | | NotifyMaterialChanged(port, row, cell.material); |
| | | Invalidate(FALSE); |
| | | return; |
| | | } |
| | | |
| | | CWnd::OnLButtonDown(nFlags, pt); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnLButtonUp(UINT nFlags, CPoint pt) |
| | | { |
| | | if (m_bResizing) |
| | | { |
| | | ReleaseCapture(); |
| | | m_bResizing = false; |
| | | m_resizeEdge = -1; |
| | | UpdateScrollRange(); |
| | | Invalidate(FALSE); |
| | | } |
| | | CWnd::OnLButtonUp(nFlags, pt); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::OnMouseMove(UINT nFlags, CPoint pt) |
| | | { |
| | | if (m_bResizing) |
| | | { |
| | | int dx = pt.x - m_resizeStartX; |
| | | if (m_resizeEdge == 0) |
| | | { |
| | | int nw = max(m_slotColMin, m_slotColCXStart + dx); |
| | | if (nw != m_slotColCX) { m_slotColCX = nw; UpdateScrollRange(); Invalidate(FALSE); } |
| | | } |
| | | else |
| | | { |
| | | int idx = m_resizeEdge - 1; // è°æ´ Port idx ç宽度 |
| | | int nw = max(m_portColMin, m_portColCXsStart[idx] + dx); |
| | | if (nw != m_portColCXs[idx]) { m_portColCXs[idx] = nw; UpdateScrollRange(); Invalidate(FALSE); } |
| | | } |
| | | return; |
| | | } |
| | | |
| | | int edge = HitHeaderEdge(pt); |
| | | if (edge != m_hitEdgeHover) |
| | | { |
| | | m_hitEdgeHover = edge; |
| | | if (m_hitEdgeHover >= 0) ::SetCursor(::LoadCursor(nullptr, IDC_SIZEWE)); |
| | | else ::SetCursor(::LoadCursor(nullptr, IDC_ARROW)); |
| | | } |
| | | } |
| | | |
| | | BOOL CCarrierSlotGrid::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) |
| | | { |
| | | CPoint pt; ::GetCursorPos(&pt); ScreenToClient(&pt); |
| | | if (m_bAllowResize && (m_bResizing || HitHeaderEdge(pt) >= 0)) |
| | | { |
| | | ::SetCursor(::LoadCursor(nullptr, IDC_SIZEWE)); |
| | | return TRUE; |
| | | } |
| | | return CWnd::OnSetCursor(pWnd, nHitTest, message); |
| | | } |
| | | |
| | | void CCarrierSlotGrid::NotifySelectionChanged(int port, int slot, BOOL checked) |
| | | { |
| | | // å
¼å®¹æ§ç WM_COMMANDï¼å¯çï¼ä¹å¯æ³¨éæï¼ |
| | | if (GetParent()) { |
| | | const int code = 0x2001; |
| | | GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); |
| | | } |
| | | // æ°ç WM_NOTIFYï¼å¸¦ä¸ç´¢å¼ä¸ç¶æ |
| | | if (GetParent()) { |
| | | CSG_SEL_CHANGE nm{}; |
| | | nm.hdr.hwndFrom = m_hWnd; |
| | | nm.hdr.idFrom = (UINT)GetDlgCtrlID(); |
| | | nm.hdr.code = CSGN_SEL_CHANGED; |
| | | nm.port = port; |
| | | nm.slot = slot; |
| | | nm.checked = checked; |
| | | GetParent()->SendMessage(WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotGrid::NotifyMaterialChanged(int port, int slot, int material) |
| | | { |
| | | if (GetParent()) { |
| | | const int code = 0x2002; |
| | | GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); |
| | | } |
| | | if (GetParent()) { |
| | | CSG_MAT_CHANGE nm{}; |
| | | nm.hdr.hwndFrom = m_hWnd; |
| | | nm.hdr.idFrom = (UINT)GetDlgCtrlID(); |
| | | nm.hdr.code = CSGN_MAT_CHANGED; |
| | | nm.port = port; |
| | | nm.slot = slot; |
| | | nm.material = material; |
| | | GetParent()->SendMessage(WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm); |
| | | } |
| | | } |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #pragma once |
| | | |
| | | #include <vector> |
| | | |
| | | #ifndef _AFX |
| | | #include <afxwin.h> |
| | | #endif |
| | | |
| | | |
| | | // æ¾å° CCarrierSlotGrid ç±»å®ä¹åæå
é¨ public: åºé½å¯ |
| | | enum { CSGN_SEL_CHANGED = 1, CSGN_MAT_CHANGED = 2 }; |
| | | |
| | | struct CSG_SEL_CHANGE { |
| | | NMHDR hdr; // hdr.code = CSGN_SEL_CHANGED |
| | | int port; // 0..GetPortCount()-1 |
| | | int slot; // 0..GetSlotCount()-1 |
| | | BOOL checked; |
| | | }; |
| | | |
| | | struct CSG_MAT_CHANGE { |
| | | NMHDR hdr; // hdr.code = CSGN_MAT_CHANGED |
| | | int port; |
| | | int slot; |
| | | int material; // 1=G1, 2=G2 |
| | | }; |
| | | |
| | | |
| | | class CCarrierSlotGrid : public CWnd |
| | | { |
| | | public: |
| | | enum MaterialType { MAT_G1 = 1, MAT_G2 = 2 }; |
| | | |
| | | struct SlotCell { |
| | | bool hasGlass = false; |
| | | CString coreId; |
| | | int material = MAT_G1; |
| | | bool checked = false; |
| | | }; |
| | | struct PortColumn { |
| | | CString portName; |
| | | CString carrierName; |
| | | bool allocated = false; |
| | | CString allocatedBy; |
| | | std::vector<SlotCell> slots; |
| | | }; |
| | | |
| | | public: |
| | | CCarrierSlotGrid(); |
| | | virtual ~CCarrierSlotGrid(); |
| | | |
| | | BOOL SubclassDlgItem(UINT nID, CWnd* pParent) { |
| | | BOOL ok = CWnd::SubclassDlgItem(nID, pParent); |
| | | if (ok) { |
| | | if (pParent && pParent->GetFont()) SetFont(pParent->GetFont()); |
| | | EnsureFonts(); |
| | | Invalidate(FALSE); |
| | | } |
| | | return ok; |
| | | } |
| | | virtual void PreSubclassWindow() override; |
| | | |
| | | // åå§å |
| | | void InitGrid(int nPorts, int nSlots); |
| | | void SetColumnWidths(int slotColWidth, int portColWidth); |
| | | void SetRowHeight(int cy); |
| | | void SetHeaderHeight(int cy); |
| | | void SetShowMaterialToggle(BOOL bShow); |
| | | |
| | | // 读/å |
| | | int GetPortCount() const { return (int)m_ports.size(); } |
| | | int GetSlotCount() const { return m_nSlots; } |
| | | |
| | | void SetPortInfo(int portIndex, LPCTSTR portName, LPCTSTR carrierName); |
| | | void SetPortAllocated(int portIndex, BOOL allocated, LPCTSTR byName = nullptr); |
| | | BOOL IsPortAllocated(int portIndex) const; |
| | | |
| | | void SetSlotGlass(int portIndex, int slotIndex, BOOL hasGlass, LPCTSTR coreId, int material); |
| | | void SetSlotChecked(int portIndex, int slotIndex, BOOL checked, BOOL bNotify = FALSE); |
| | | BOOL GetSlotChecked(int portIndex, int slotIndex) const; |
| | | |
| | | int GetSlotMaterialType(int portIndex, int slotIndex) const; |
| | | void SetSlotMaterialType(int portIndex, int slotIndex, int material, BOOL bNotify = TRUE); |
| | | |
| | | CString GetDisplayId(int portIndex, int slotIndex) const; |
| | | void CheckAllInPort(int portIndex, BOOL checked, BOOL bNotify = TRUE); |
| | | |
| | | void RebuildTexts(); |
| | | void EnableColumnResize(BOOL enable) { m_bAllowResize = !!enable; Invalidate(FALSE); } |
| | | |
| | | // è®¡ç®æä½³å¤§å°ï¼ |
| | | // - CalcBestClientSizeï¼å
容åºåï¼ä¸å«æ»å¨æ¡/é客æ·åºï¼å好容纳表头+ææè¡ãå
¨é¨å |
| | | // - CalcBestWindowSizeï¼å¨å½åçªå£æ ·å¼ä¸ï¼å°âå
容大å°â转æ¢ä¸ºçªå£å¤æ¡å¤§å°ï¼ä¼èè WS_BORDER/CLIENTEDGE çï¼ |
| | | // é»è®¤æâéèæ»å¨æ¡âçç®æ æ¥ç®ï¼å³ä¸æ WS_HSCROLL/WS_VSCROLL 计å
¥è°æ´ï¼ |
| | | // è®¡ç®æä½³å¤§å°ï¼æ¯æå¯éå®å
¨è¾¹è·ï¼é»è®¤æ DPI 约çäº 2pxï¼ |
| | | CSize CalcBestClientSize(int nSlotsOverride = -1) const; |
| | | CSize CalcBestWindowSize(BOOL includeNonClient = TRUE, |
| | | int nSlotsOverride = -1, |
| | | int extraPadX = -1, // -1 表示æ DPI èªå¨ |
| | | int extraPadY = -1) const; |
| | | |
| | | // æ°¸ä¹
ç¦ç¨ç³»ç»æ»å¨æ¡ï¼å»ææ ·å¼å¹¶å·æ°é客æ·åºï¼ |
| | | void DisableSystemScrollbars(); |
| | | |
| | | // æçªå£å°ºå¯¸è°å°æ£å¥½å®¹çº³ææå
容ï¼ä¸åºç°æ»å¨æ¡ï¼ |
| | | void ResizeWindowToFitAll(BOOL includeNonClient = TRUE, int nSlotsOverride = -1); |
| | | |
| | | // è¿å
¥/éåºæ æ»å¨æ¡æ¨¡å¼ï¼å»æ ·å¼ãæ¸
æ»å¨ãå¿½ç¥æ»å¨æ¶æ¯ï¼ |
| | | void SetNoScrollbarsMode(BOOL enable); |
| | | |
| | | // å¨âæ æ»å¨æ¡æ¨¡å¼âä¸ï¼æçªå£å°ºå¯¸è°å°å好容纳ææå
容ï¼ä¸åºç°æ»å¨æ¡ï¼ |
| | | void FitWindowToContentNoScroll(BOOL includeNonClient = TRUE, int nSlotsOverride = -1); |
| | | |
| | | protected: |
| | | // æ°æ® |
| | | int m_nSlots = 0; |
| | | std::vector<PortColumn> m_ports; |
| | | BOOL m_bShowMatToggle = TRUE; |
| | | |
| | | // 尺寸/æ»å¨ |
| | | int m_rowHeight = 26; |
| | | int m_headerCY = 28; |
| | | int m_slotColCX = 100; |
| | | std::vector<int> m_portColCXs; |
| | | int m_scrollY = 0; |
| | | int m_scrollX = 0; |
| | | int m_slotColMin = 60; |
| | | int m_portColMin = 80; |
| | | |
| | | // é¢è² |
| | | COLORREF m_colBg = RGB(255, 255, 255); |
| | | COLORREF m_colAlt = RGB(240, 242, 245); |
| | | COLORREF m_colLock = RGB(255, 244, 214); |
| | | COLORREF m_gridMajor = RGB(210, 214, 220); |
| | | COLORREF m_gridMinor = RGB(220, 224, 230); |
| | | COLORREF m_text = RGB(40, 40, 40); |
| | | COLORREF m_textDim = RGB(150, 150, 150); |
| | | |
| | | // åä½ |
| | | CFont m_fntText; |
| | | CFont m_fntBold; |
| | | CFont m_fntSmall; |
| | | |
| | | // æå¨å宽 |
| | | bool m_bResizing = false; |
| | | int m_resizeEdge = -1; // 0=Slot|Port1ï¼1..N-1=Port i|i+1 |
| | | int m_resizeStartX = 0; |
| | | int m_slotColCXStart = 0; |
| | | std::vector<int> m_portColCXsStart; |
| | | int m_hitEdgeHover = -1; |
| | | bool m_bAllowResize = true; // â æ°å¢ï¼æ¯å¦å
许æå¨å宽 |
| | | bool m_noScrollbars = false; // â æ°å¢ï¼æ æ»å¨æ¡æ¨¡å¼ |
| | | |
| | | // å·¥å
· |
| | | void EnsureFonts(); |
| | | void UpdateScrollRange(); |
| | | int GetTotalContentWidth() const; |
| | | void NotifySelectionChanged(int port, int slot, BOOL checked); |
| | | void NotifyMaterialChanged(int port, int slot, int material); |
| | | |
| | | // å ä½ |
| | | CRect GetClientRectNoSB() const; |
| | | BOOL GetCellRect(int row, int sub, CRect& rc) const; // sub: 0=Slot, 1..N=Port |
| | | CRect GetHeaderRect() const; |
| | | CRect GetHeaderItemRect(int iItem) const; |
| | | CRect GetHeaderCheckboxRect(int iItem) const; |
| | | CRect GetCheckboxRect(const CRect& cell) const; |
| | | CRect GetMaterialTagRect(const CRect& cell) const; |
| | | CRect GetStatusDotRect(const CRect& cell) const; |
| | | BOOL IsColumnResizeEnabled() const { return m_bAllowResize ? TRUE : FALSE; } |
| | | |
| | | int HitHeaderEdge(CPoint pt) const; |
| | | |
| | | // ç»å¶ |
| | | void DrawFlatCheckbox(CDC* pDC, const CRect& r, bool checked, bool disabled); |
| | | void PaintTo(CDC* pDC); |
| | | |
| | | protected: |
| | | // æ¶æ¯ |
| | | afx_msg BOOL OnEraseBkgnd(CDC* pDC); |
| | | afx_msg void OnPaint(); |
| | | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); |
| | | afx_msg void OnSize(UINT nType, int cx, int cy); |
| | | afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); |
| | | afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); // â
çºµåæ»å¨æ¡ |
| | | afx_msg void OnLButtonDown(UINT nFlags, CPoint pt); |
| | | afx_msg void OnLButtonUp(UINT nFlags, CPoint pt); |
| | | afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); |
| | | afx_msg void OnMouseMove(UINT nFlags, CPoint pt); |
| | | afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); |
| | | afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); |
| | | afx_msg void OnWindowPosChanged(WINDOWPOS* wp); |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #include "CCarrierSlotSelector.h" |
| | | |
| | | #define SAFE_PORT(p) ((p) >= 0 && (p) < (int)m_ports.size()) |
| | | #define SAFE_SLOT(s) ((s) >= 0 && (s) < m_nSlots) |
| | | |
| | | #ifndef LVS_EX_DOUBLEBUFFER |
| | | #define LVS_EX_DOUBLEBUFFER 0x00010000 |
| | | #endif |
| | | |
| | | BEGIN_MESSAGE_MAP(CCarrierSlotSelector, CListCtrl) |
| | | ON_WM_SHOWWINDOW() |
| | | ON_WM_WINDOWPOSCHANGED() |
| | | ON_WM_SIZE() |
| | | ON_WM_ERASEBKGND() |
| | | ON_WM_PAINT() // â
æ°å¢ |
| | | ON_WM_LBUTTONDOWN() |
| | | ON_WM_MOUSEMOVE() |
| | | ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CCarrierSlotSelector::OnCustomDraw) |
| | | END_MESSAGE_MAP() |
| | | |
| | | CCarrierSlotSelector::CCarrierSlotSelector() {} |
| | | CCarrierSlotSelector::~CCarrierSlotSelector() |
| | | { |
| | | if ((HFONT)m_fntText) m_fntText.DeleteObject(); |
| | | if ((HFONT)m_fntBold) m_fntBold.DeleteObject(); |
| | | if ((HFONT)m_fntSmall) m_fntSmall.DeleteObject(); |
| | | if ((HIMAGELIST)m_ilRowHeight) m_ilRowHeight.DeleteImageList(); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::PreSubclassWindow() |
| | | { |
| | | CListCtrl::PreSubclassWindow(); |
| | | |
| | | ModifyStyle(LVS_TYPEMASK, LVS_REPORT | LVS_SHOWSELALWAYS); |
| | | ModifyStyle(LVS_OWNERDRAWFIXED | LVS_OWNERDATA, 0); |
| | | |
| | | DWORD ex = GetExtendedStyle(); |
| | | ex |= LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER; |
| | | ex &= ~LVS_EX_GRIDLINES; // å
³éç³»ç»ç½æ ¼ï¼æ¹èªç» |
| | | SetExtendedStyle(ex); |
| | | |
| | | // 让é»è®¤ç»å¶ç¨æä»¬çåºè²ï¼è¿ä¸æ¥éä½ç½åºæºä¼ï¼å³ä½¿åªå¤èµ°äºé»è®¤è·¯å¾ï¼ |
| | | ListView_SetBkColor(m_hWnd, m_colBgNorm); |
| | | ListView_SetTextBkColor(m_hWnd, m_colBgNorm); |
| | | |
| | | EnsureFonts(); |
| | | SetRowHeight(m_rowHeight); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnShowWindow(BOOL bShow, UINT nStatus) |
| | | { |
| | | CListCtrl::OnShowWindow(bShow, nStatus); |
| | | if (bShow && !m_bFirstShown) |
| | | { |
| | | m_bFirstShown = TRUE; |
| | | RedrawWindow(nullptr, nullptr, |
| | | RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnWindowPosChanged(WINDOWPOS* wp) |
| | | { |
| | | CListCtrl::OnWindowPosChanged(wp); |
| | | if (wp && (wp->flags & SWP_SHOWWINDOW)) |
| | | { |
| | | RedrawWindow(nullptr, nullptr, |
| | | RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotSelector::EnsureFonts() |
| | | { |
| | | if (!(HFONT)m_fntText) |
| | | { |
| | | LOGFONT lf = { 0 }; |
| | | CFont* pSys = GetFont(); |
| | | if (pSys) pSys->GetLogFont(&lf); |
| | | else { lf.lfHeight = -14; lstrcpy(lf.lfFaceName, _T("Segoe UI")); } |
| | | m_fntText.CreateFontIndirect(&lf); |
| | | |
| | | lf.lfWeight = FW_SEMIBOLD; |
| | | m_fntBold.CreateFontIndirect(&lf); |
| | | |
| | | lf.lfWeight = FW_NORMAL; lf.lfHeight = -12; |
| | | m_fntSmall.CreateFontIndirect(&lf); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotSelector::InitGrid(int nPorts, int nSlots) |
| | | { |
| | | ASSERT(nPorts >= 1 && nSlots >= 1); |
| | | m_ports.clear(); |
| | | m_ports.resize(nPorts); |
| | | m_nSlots = nSlots; |
| | | for (auto& pc : m_ports) pc.slots.resize(m_nSlots); |
| | | |
| | | SetRedraw(FALSE); |
| | | DeleteAllItems(); |
| | | while (GetHeaderCtrl() && GetHeaderCtrl()->GetItemCount() > 0) |
| | | DeleteColumn(0); |
| | | |
| | | InsertColumn(0, _T("Slot"), LVCFMT_LEFT, m_slotColWidth); |
| | | for (int c = 0; c < nPorts; ++c) |
| | | { |
| | | CString col; col.Format(_T("Port %d"), c + 1); |
| | | InsertColumn(c + 1, col, LVCFMT_LEFT, m_portColWidth); |
| | | m_ports[c].portName = col; |
| | | m_ports[c].carrierName.Empty(); |
| | | } |
| | | |
| | | UpdateRowCount(); |
| | | RebuildTexts(); |
| | | SetRedraw(TRUE); |
| | | if (IsWindowVisible()) Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetColumnWidths(int slotColWidth, int portColWidth) |
| | | { |
| | | if (slotColWidth > 0) m_slotColWidth = slotColWidth; |
| | | if (portColWidth > 0) m_portColWidth = portColWidth; |
| | | SetColumnWidth(0, m_slotColWidth); |
| | | for (int c = 0; c < (int)m_ports.size(); ++c) SetColumnWidth(c + 1, m_portColWidth); |
| | | if (IsWindowVisible()) Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetRowHeight(int cy) |
| | | { |
| | | cy = max(18, min(cy, 64)); |
| | | m_rowHeight = cy; |
| | | |
| | | if ((HIMAGELIST)m_ilRowHeight) m_ilRowHeight.DeleteImageList(); |
| | | m_ilRowHeight.Create(1, m_rowHeight, ILC_COLOR32, 1, 1); |
| | | |
| | | // 1Ãcy éæä½å¾ |
| | | CBitmap bmp; bmp.CreateBitmap(1, m_rowHeight, 1, 32, nullptr); |
| | | m_ilRowHeight.Add(&bmp, RGB(0, 0, 0)); |
| | | SetImageList(&m_ilRowHeight, LVSIL_SMALL); |
| | | |
| | | if (IsWindowVisible()) Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::UpdateRowCount() |
| | | { |
| | | int cur = GetItemCount(); |
| | | if (cur < m_nSlots) |
| | | { |
| | | for (int i = cur; i < m_nSlots; ++i) |
| | | { |
| | | CString s; s.Format(_T("Slot %d"), i + 1); |
| | | InsertItem(i, s, 0); // 设 iImage=0ï¼è¡é«æ¥èª small image list |
| | | } |
| | | } |
| | | else if (cur > m_nSlots) |
| | | { |
| | | for (int i = cur - 1; i >= m_nSlots; --i) DeleteItem(i); |
| | | } |
| | | |
| | | // å·²æè¡ä¹ç»ä¸è®¾ iImage=0 |
| | | LVITEM lvi = { 0 }; |
| | | lvi.mask = LVIF_IMAGE; lvi.iImage = 0; |
| | | for (int i = 0; i < m_nSlots; ++i) { lvi.iItem = i; SetItem(&lvi); } |
| | | } |
| | | |
| | | void CCarrierSlotSelector::RebuildTexts() |
| | | { |
| | | // åå¤´ï¼æ¾ç¤º â已鿰/æ»æ§½æ° ï¼ [x]/[ ]â |
| | | for (int c = 0; c < (int)m_ports.size(); ++c) |
| | | { |
| | | int selected = 0; |
| | | int total = m_nSlots; |
| | | |
| | | bool anyCheckable = false; |
| | | bool allChecked = true; |
| | | |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | const auto& cell = m_ports[c].slots[r]; |
| | | if (cell.hasGlass) |
| | | { |
| | | anyCheckable = true; |
| | | if (cell.checked) ++selected; else allChecked = false; |
| | | } |
| | | } |
| | | if (!anyCheckable) allChecked = false; |
| | | |
| | | CString head; |
| | | CString chk = allChecked ? _T("[x]") : _T("[ ]"); |
| | | |
| | | if (!m_ports[c].carrierName.IsEmpty()) |
| | | head.Format(_T("%s (%s) %d/%d %s%s"), |
| | | m_ports[c].portName.GetString(), m_ports[c].carrierName.GetString(), |
| | | selected, total, |
| | | m_ports[c].allocated ? _T("[LOCK] ") : _T(""), |
| | | chk.GetString()); |
| | | else |
| | | head.Format(_T("%s %d/%d %s%s"), |
| | | m_ports[c].portName.GetString(), selected, total, |
| | | m_ports[c].allocated ? _T("[LOCK] ") : _T(""), |
| | | chk.GetString()); |
| | | |
| | | LVCOLUMN lvc = { 0 }; lvc.mask = LVCF_TEXT; lvc.pszText = head.GetBuffer(); |
| | | SetColumn(c + 1, &lvc); |
| | | head.ReleaseBuffer(); |
| | | } |
| | | |
| | | // è¡å¤´ææ¬ |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | CString s; s.Format(_T("Slot %d"), r + 1); |
| | | SetItemText(r, 0, s); |
| | | } |
| | | |
| | | // åå
æ ¼ä¸´æ¶ææ¬ |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | for (int c = 0; c < (int)m_ports.size(); ++c) |
| | | SetItemText(r, c + 1, GetDisplayId(c, r)); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetShowMaterialToggle(BOOL bShow) |
| | | { |
| | | m_bShowMatToggle = bShow; |
| | | if (IsWindowVisible()) Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetPortInfo(int portIndex, LPCTSTR portName, LPCTSTR carrierName) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | if (portName) m_ports[portIndex].portName = portName; |
| | | if (carrierName) m_ports[portIndex].carrierName = carrierName; |
| | | RebuildTexts(); |
| | | if (IsWindowVisible()) Invalidate(FALSE); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetPortAllocated(int portIndex, BOOL allocated, LPCTSTR byName) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | m_ports[portIndex].allocated = !!allocated; |
| | | if (byName) m_ports[portIndex].allocatedBy = byName; else m_ports[portIndex].allocatedBy.Empty(); |
| | | |
| | | if (allocated) |
| | | for (int r = 0; r < m_nSlots; ++r) m_ports[portIndex].slots[r].checked = false; |
| | | |
| | | // å·æ°æ´å |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | CRect rc; GetSubItemRect(r, portIndex + 1, LVIR_BOUNDS, rc); |
| | | InvalidateRect(&rc, FALSE); |
| | | } |
| | | RebuildTexts(); |
| | | } |
| | | |
| | | BOOL CCarrierSlotSelector::IsPortAllocated(int portIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return FALSE; |
| | | return m_ports[portIndex].allocated; |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetSlotGlass(int portIndex, int slotIndex, BOOL hasGlass, LPCTSTR coreId, int material) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | cell.hasGlass = !!hasGlass; |
| | | cell.coreId = coreId ? coreId : _T(""); |
| | | cell.material = (material == MAT_G2) ? MAT_G2 : MAT_G1; |
| | | if (!cell.hasGlass) cell.checked = false; |
| | | |
| | | CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); |
| | | InvalidateRect(&rc, FALSE); |
| | | RebuildTexts(); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetSlotChecked(int portIndex, int slotIndex, BOOL checked) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | if (m_ports[portIndex].allocated) return; |
| | | auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | if (!cell.hasGlass) return; |
| | | |
| | | cell.checked = !!checked; |
| | | NotifySelectionChanged(portIndex, slotIndex, cell.checked); |
| | | |
| | | CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); |
| | | InvalidateRect(&rc, FALSE); |
| | | RebuildTexts(); |
| | | } |
| | | |
| | | BOOL CCarrierSlotSelector::GetSlotChecked(int portIndex, int slotIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return FALSE; |
| | | return m_ports[portIndex].slots[slotIndex].checked ? TRUE : FALSE; |
| | | } |
| | | |
| | | int CCarrierSlotSelector::GetSlotMaterialType(int portIndex, int slotIndex) const |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return MAT_G1; |
| | | return m_ports[portIndex].slots[slotIndex].material; |
| | | } |
| | | |
| | | void CCarrierSlotSelector::SetSlotMaterialType(int portIndex, int slotIndex, int material, BOOL bNotify) |
| | | { |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; |
| | | if (m_ports[portIndex].allocated) return; |
| | | auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | if (!cell.hasGlass) return; |
| | | |
| | | int mt = (material == MAT_G2) ? MAT_G2 : MAT_G1; |
| | | if (cell.material != mt) |
| | | { |
| | | cell.material = mt; |
| | | if (bNotify) NotifyMaterialChanged(portIndex, slotIndex, cell.material); |
| | | CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); |
| | | InvalidateRect(&rc, FALSE); |
| | | } |
| | | } |
| | | |
| | | CString CCarrierSlotSelector::GetDisplayId(int portIndex, int slotIndex) const |
| | | { |
| | | CString s(_T("â")); |
| | | if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return s; |
| | | const auto& cell = m_ports[portIndex].slots[slotIndex]; |
| | | if (!cell.hasGlass) return s; |
| | | s.Format(_T("G%d-%s"), (cell.material == MAT_G2) ? 2 : 1, cell.coreId.GetString()); |
| | | return s; |
| | | } |
| | | |
| | | void CCarrierSlotSelector::CheckAllInPort(int portIndex, BOOL checked, BOOL bNotify) |
| | | { |
| | | if (!SAFE_PORT(portIndex)) return; |
| | | if (m_ports[portIndex].allocated) return; |
| | | |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | auto& cell = m_ports[portIndex].slots[r]; |
| | | if (!cell.hasGlass) continue; |
| | | if (cell.checked != !!checked) |
| | | { |
| | | cell.checked = !!checked; |
| | | if (bNotify) NotifySelectionChanged(portIndex, r, cell.checked); |
| | | } |
| | | CRect rc; GetSubItemRect(r, portIndex + 1, LVIR_BOUNDS, rc); |
| | | InvalidateRect(&rc, FALSE); |
| | | } |
| | | RebuildTexts(); |
| | | } |
| | | |
| | | BOOL CCarrierSlotSelector::OnEraseBkgnd(CDC* /*pDC*/) |
| | | { |
| | | // å
³é®ï¼ä¸è®©ç³»ç»æ¦ç½èæ¯ï¼ç¨èªç»å¨ PREPAINT é¶æ®µç»ä¸éºåº |
| | | return TRUE; |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnPaint() |
| | | { |
| | | CPaintDC dc(this); |
| | | CRect rc; GetClientRect(&rc); |
| | | |
| | | CDC memDC; |
| | | memDC.CreateCompatibleDC(&dc); |
| | | CBitmap bmp; |
| | | bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height()); |
| | | HGDIOBJ hOldBmp = memDC.SelectObject(bmp); |
| | | |
| | | // ç»ä¸åºè²ï¼é¿å
任使¦ç½ï¼ |
| | | memDC.FillSolidRect(rc, m_colBgNorm); |
| | | |
| | | // 让æ§ä»¶æå®¢æ·åºå
容âç»å°âå
åDCï¼ä¼è§¦å NM_CUSTOMDRAWï¼èµ°ä½ ç°æèªç»é»è¾ï¼ |
| | | // PRF_ERASEBKGND 让å
é¨å¦ææ³æ¦èæ¯ï¼ä¹å¨å
å鿦ï¼ä¸ä¼éªå± |
| | | SendMessage(WM_PRINTCLIENT, |
| | | reinterpret_cast<WPARAM>(memDC.m_hDC), |
| | | PRF_CLIENT | PRF_ERASEBKGND | PRF_CHILDREN | PRF_OWNED); |
| | | |
| | | // åæ¾å°å±å¹ |
| | | dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY); |
| | | |
| | | memDC.SelectObject(hOldBmp); |
| | | // bmp, memDC ææèªå¨éæ¾ |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnSize(UINT nType, int cx, int cy) |
| | | { |
| | | CListCtrl::OnSize(nType, cx, cy); |
| | | } |
| | | |
| | | CRect CCarrierSlotSelector::GetCheckboxRect(const CRect& cell) const |
| | | { |
| | | int sz = max(14, min(int(m_rowHeight * 0.70), 20)); |
| | | int leftPad = 8; |
| | | int top = cell.top + (m_rowHeight - sz) / 2; |
| | | return CRect(cell.left + leftPad, top, cell.left + leftPad + sz, top + sz); |
| | | } |
| | | |
| | | CRect CCarrierSlotSelector::GetMaterialTagRect(const CRect& cell) const |
| | | { |
| | | int tagH = max(14, min(int(m_rowHeight * 0.65), m_rowHeight - 8)); |
| | | int tagW = 32; |
| | | int rightPadForDot = 16; |
| | | int gap = 6; |
| | | int top = cell.top + (m_rowHeight - tagH) / 2; |
| | | int right = cell.right - rightPadForDot - gap; |
| | | return CRect(right - tagW, top, right, top + tagH); |
| | | } |
| | | |
| | | CRect CCarrierSlotSelector::GetStatusDotRect(const CRect& cell) const |
| | | { |
| | | int d = max(8, min(int(m_rowHeight * 0.42), 12)); |
| | | int rightPad = 6; |
| | | int top = cell.top + (m_rowHeight - d) / 2; |
| | | return CRect(cell.right - rightPad - d, top, cell.right - rightPad, top + d); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::DrawFlatCheckbox(CDC* pDC, const CRect& r, bool checked, bool disabled) |
| | | { |
| | | CBrush br(disabled ? RGB(245, 245, 245) : RGB(255, 255, 255)); |
| | | CPen pen(PS_SOLID, 1, disabled ? RGB(200, 200, 200) : RGB(130, 130, 135)); |
| | | CBrush* pOldB = pDC->SelectObject(&br); |
| | | CPen* pOldP = pDC->SelectObject(&pen); |
| | | pDC->RoundRect(r, CPoint(3, 3)); |
| | | pDC->SelectObject(pOldB); |
| | | pDC->SelectObject(pOldP); |
| | | br.DeleteObject(); pen.DeleteObject(); |
| | | |
| | | if (!checked) return; |
| | | |
| | | COLORREF c = disabled ? RGB(160, 160, 160) : RGB(40, 150, 90); |
| | | CPen penTick(PS_SOLID, max(2, r.Height() / 8), c); |
| | | CPen* pOld = pDC->SelectObject(&penTick); |
| | | POINT p1 = { r.left + r.Width() * 2 / 9, r.top + r.Height() * 5 / 9 }; |
| | | POINT p2 = { r.left + r.Width() * 4 / 9, r.top + r.Height() * 7 / 9 }; |
| | | POINT p3 = { r.left + r.Width() * 7 / 9, r.top + r.Height() * 3 / 9 }; |
| | | pDC->MoveTo(p1); pDC->LineTo(p2); pDC->LineTo(p3); |
| | | pDC->SelectObject(pOld); |
| | | penTick.DeleteObject(); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnLButtonDown(UINT nFlags, CPoint point) |
| | | { |
| | | LVHITTESTINFO ht = { 0 }; ht.pt = point; |
| | | int row = SubItemHitTest(&ht); |
| | | int sub = (row >= 0) ? ht.iSubItem : -1; |
| | | |
| | | if (row >= 0 && sub >= 1) |
| | | { |
| | | int port = sub - 1; |
| | | if (SAFE_PORT(port) && SAFE_SLOT(row)) |
| | | { |
| | | auto& pc = m_ports[port]; |
| | | auto& cell = pc.slots[row]; |
| | | CRect rcCell; GetSubItemRect(row, sub, LVIR_BOUNDS, rcCell); |
| | | |
| | | if (pc.allocated || !cell.hasGlass) |
| | | { |
| | | CListCtrl::OnLButtonDown(nFlags, point); |
| | | return; |
| | | } |
| | | |
| | | if (GetCheckboxRect(rcCell).PtInRect(point)) |
| | | { |
| | | cell.checked = !cell.checked; |
| | | NotifySelectionChanged(port, row, cell.checked); |
| | | InvalidateRect(&rcCell, FALSE); |
| | | RebuildTexts(); |
| | | return; |
| | | } |
| | | |
| | | if (m_bShowMatToggle && GetMaterialTagRect(rcCell).PtInRect(point)) |
| | | { |
| | | cell.material = (cell.material == MAT_G1) ? MAT_G2 : MAT_G1; |
| | | NotifyMaterialChanged(port, row, cell.material); |
| | | InvalidateRect(&rcCell, FALSE); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | CListCtrl::OnLButtonDown(nFlags, point); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnMouseMove(UINT nFlags, CPoint point) |
| | | { |
| | | CListCtrl::OnMouseMove(nFlags, point); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | NMLVCUSTOMDRAW* pCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR); |
| | | |
| | | switch (pCD->nmcd.dwDrawStage) |
| | | { |
| | | case CDDS_PREPAINT: |
| | | { |
| | | // å
³é®ï¼æ´æ§ä»¶é¢å
éºåºï¼é¿å
忬¡ hover/æ¾ç¤ºæ¶âå·ç½â |
| | | CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc); |
| | | CRect rcClient; GetClientRect(&rcClient); |
| | | pDC->FillSolidRect(rcClient, m_colBgNorm); |
| | | *pResult = CDRF_NOTIFYITEMDRAW; |
| | | return; |
| | | } |
| | | |
| | | case CDDS_ITEMPREPAINT: |
| | | *pResult = CDRF_NOTIFYSUBITEMDRAW; |
| | | return; |
| | | |
| | | case (CDDS_SUBITEM | CDDS_ITEMPREPAINT): |
| | | { |
| | | CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc); |
| | | int row = (int)pCD->nmcd.dwItemSpec; |
| | | int sub = pCD->iSubItem; |
| | | |
| | | CRect rc; GetSubItemRect(row, sub, LVIR_BOUNDS, rc); |
| | | |
| | | // èæ¯ |
| | | COLORREF bk = m_colBgNorm; |
| | | if (sub >= 1) |
| | | { |
| | | int port = sub - 1; |
| | | if (port % 2 == 0) bk = m_colBgAlt; // 交æ¿å |
| | | if (SAFE_PORT(port) && m_ports[port].allocated) // éå®å |
| | | bk = m_colLockBg; |
| | | } |
| | | pDC->FillSolidRect(rc, bk); |
| | | |
| | | // ç½æ ¼ï¼ä¸/å·¦å ç²ï¼å³/ä¸ç»çº¿ï¼ |
| | | CPen penTopLeft(PS_SOLID, (sub >= 1 && ((sub - 1) % 2 == 0)) ? 2 : 1, RGB(210, 214, 220)); |
| | | CPen* pOldPen = pDC->SelectObject(&penTopLeft); |
| | | pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.right, rc.top); |
| | | pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.left, rc.bottom); |
| | | pDC->SelectObject(pOldPen); penTopLeft.DeleteObject(); |
| | | |
| | | CPen penThin(PS_SOLID, 1, RGB(220, 224, 230)); |
| | | pOldPen = pDC->SelectObject(&penThin); |
| | | if (sub == GetHeaderCtrl()->GetItemCount() - 1) { pDC->MoveTo(rc.right - 1, rc.top); pDC->LineTo(rc.right - 1, rc.bottom); } |
| | | if (row == m_nSlots - 1) { pDC->MoveTo(rc.left, rc.bottom - 1); pDC->LineTo(rc.right, rc.bottom - 1); } |
| | | pDC->SelectObject(pOldPen); penThin.DeleteObject(); |
| | | |
| | | if (sub == 0) |
| | | { |
| | | CString s; s.Format(_T("Slot %d"), row + 1); |
| | | CFont* pOld = pDC->SelectObject(&m_fntBold); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(RGB(60, 60, 64)); |
| | | CRect rText = rc; rText.DeflateRect(8, 0, 8, 0); |
| | | pDC->DrawText(s, rText, DT_LEFT | DT_VCENTER | DT_SINGLELINE); |
| | | pDC->SelectObject(pOld); |
| | | } |
| | | else if (SAFE_PORT(sub - 1) && SAFE_SLOT(row)) |
| | | { |
| | | int port = sub - 1; |
| | | const auto& pc = m_ports[port]; |
| | | const auto& cell = pc.slots[row]; |
| | | |
| | | // æå¹³å¤éæ¡ |
| | | CRect rChk = GetCheckboxRect(rc); |
| | | DrawFlatCheckbox(pDC, rChk, cell.checked, pc.allocated || !cell.hasGlass); |
| | | |
| | | // ææ¬ |
| | | CString s = GetDisplayId(port, row); |
| | | CRect rText = rc; |
| | | int leftPad = rChk.right + 6; |
| | | CRect rDot = GetStatusDotRect(rc); |
| | | CRect rTag = GetMaterialTagRect(rc); |
| | | int rightPad = rc.right - min(rTag.left - 6, rDot.left - 6); |
| | | rText.DeflateRect(leftPad - rc.left, 0, rightPad, 0); |
| | | |
| | | CFont* pOld = pDC->SelectObject(&m_fntText); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(cell.hasGlass ? RGB(40, 40, 40) : RGB(150, 150, 150)); |
| | | pDC->DrawText(s, rText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); |
| | | pDC->SelectObject(pOld); |
| | | |
| | | // ç©ææ ç¾ï¼å¯éèï¼ |
| | | if (m_bShowMatToggle) |
| | | { |
| | | CRect rT = rTag; |
| | | COLORREF crBorder = (cell.material == MAT_G2) ? RGB(180, 150, 220) : RGB(120, 160, 220); |
| | | COLORREF crFill = (cell.material == MAT_G2) ? RGB(243, 235, 250) : RGB(233, 240, 252); |
| | | COLORREF crText = (cell.material == MAT_G2) ? RGB(90, 60, 150) : RGB(50, 90, 160); |
| | | if (pc.allocated || !cell.hasGlass) { crBorder = RGB(210, 210, 210); crFill = RGB(245, 245, 245); crText = RGB(160, 160, 160); } |
| | | CBrush br(crFill); CPen tagPen(PS_SOLID, 1, crBorder); |
| | | CPen* pOldP = pDC->SelectObject(&tagPen); |
| | | CBrush* pOldB = pDC->SelectObject(&br); |
| | | pDC->RoundRect(rT, CPoint(6, 6)); |
| | | pDC->SelectObject(pOldB); pDC->SelectObject(pOldP); |
| | | br.DeleteObject(); tagPen.DeleteObject(); |
| | | |
| | | CString t; t.Format(_T("G%d"), (cell.material == MAT_G2) ? 2 : 1); |
| | | CFont* pOldS = pDC->SelectObject(&m_fntSmall); |
| | | pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(crText); |
| | | pDC->DrawText(t, rT, DT_CENTER | DT_VCENTER | DT_SINGLELINE); |
| | | pDC->SelectObject(pOldS); |
| | | } |
| | | |
| | | // ç¶æç¹ |
| | | CRect rD = GetStatusDotRect(rc); |
| | | COLORREF dot = cell.hasGlass ? (pc.allocated ? RGB(215, 160, 60) : RGB(60, 170, 80)) : RGB(160, 160, 160); |
| | | CBrush bDot(dot); CBrush* pOldB = pDC->SelectObject(&bDot); |
| | | pDC->Ellipse(rD); |
| | | pDC->SelectObject(pOldB); bDot.DeleteObject(); |
| | | } |
| | | |
| | | *pResult = CDRF_SKIPDEFAULT; // å项å®å
¨èªç» |
| | | return; |
| | | } |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | *pResult = 0; |
| | | } |
| | | |
| | | BOOL CCarrierSlotSelector::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) |
| | | { |
| | | NMHDR* pNM = reinterpret_cast<NMHDR*>(lParam); |
| | | if (pNM && pNM->hwndFrom == GetHeaderCtrl()->GetSafeHwnd()) |
| | | { |
| | | switch (pNM->code) |
| | | { |
| | | case HDN_ITEMCLICKA: |
| | | case HDN_ITEMCLICKW: |
| | | { |
| | | HD_NOTIFY* phdn = reinterpret_cast<HD_NOTIFY*>(lParam); |
| | | OnHeaderClick(phdn->iItem); |
| | | if (pResult) *pResult = 0; |
| | | return TRUE; // æä»¬å·²å¤ç |
| | | } |
| | | default: break; |
| | | } |
| | | } |
| | | return CListCtrl::OnNotify(wParam, lParam, pResult); |
| | | } |
| | | |
| | | void CCarrierSlotSelector::OnHeaderClick(int iItem) |
| | | { |
| | | // iItem: 0=Slot åï¼>=1 为 Port å |
| | | if (iItem <= 0) return; |
| | | int port = iItem - 1; |
| | | if (!SAFE_PORT(port) || m_ports[port].allocated) return; |
| | | |
| | | // è®¡ç®æ¯å¦âå
¨éâ |
| | | bool anyCheckable = false; |
| | | bool allChecked = true; |
| | | for (int r = 0; r < m_nSlots; ++r) |
| | | { |
| | | const auto& cell = m_ports[port].slots[r]; |
| | | if (!cell.hasGlass) continue; |
| | | anyCheckable = true; |
| | | if (!cell.checked) { allChecked = false; break; } |
| | | } |
| | | if (!anyCheckable) return; |
| | | |
| | | // 忢ï¼è¥å·²å
¨é -> åæ¶å
¨éï¼å¦å -> å
¨é |
| | | CheckAllInPort(port, allChecked ? FALSE : TRUE, TRUE); |
| | | } |
| | | |
| | | // ==== ֪ͨ ==== |
| | | void CCarrierSlotSelector::NotifySelectionChanged(int /*port*/, int /*slot*/, BOOL /*checked*/) |
| | | { |
| | | if (GetParent()) |
| | | { |
| | | const int code = 0x2001; // CSSN_SELECTION_CHANGED |
| | | GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); |
| | | } |
| | | } |
| | | |
| | | void CCarrierSlotSelector::NotifyMaterialChanged(int /*port*/, int /*slot*/, int /*material*/) |
| | | { |
| | | if (GetParent()) |
| | | { |
| | | const int code = 0x2002; // CSSN_MATERIAL_CHANGED |
| | | GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #pragma once |
| | | |
| | | #include <vector> |
| | | #include <string> |
| | | |
| | | #ifndef _AFX |
| | | #include <afxwin.h> |
| | | #include <afxcmn.h> |
| | | #endif |
| | | |
| | | class CCarrierSlotSelector : public CListCtrl |
| | | { |
| | | public: |
| | | enum MaterialType { MAT_G1 = 1, MAT_G2 = 2 }; |
| | | |
| | | struct SlotCell |
| | | { |
| | | bool hasGlass = false; // æ¯å¦æç |
| | | CString coreId; // åºå®æ ¸å¿IDï¼ä¸å«åç¼ï¼ |
| | | int material = MAT_G1; // ä»
å½±åå±ç¤ºï¼G1/G2ï¼ |
| | | bool checked = false; // æ¯å¦å¾éå å·¥ |
| | | }; |
| | | |
| | | struct PortColumn |
| | | { |
| | | CString portName; // "Port 1" ... |
| | | CString carrierName; // "Carrier A" ... |
| | | bool allocated = false; // æ´åéå® |
| | | CString allocatedBy; // å ç¨è
|
| | | std::vector<SlotCell> slots; // size = m_nSlots |
| | | }; |
| | | |
| | | public: |
| | | CCarrierSlotSelector(); |
| | | virtual ~CCarrierSlotSelector(); |
| | | |
| | | // åå§å / 尺寸 |
| | | void InitGrid(int nPorts, int nSlots); |
| | | void SetColumnWidths(int slotColWidth, int portColWidth); |
| | | void SetRowHeight(int cy); // small image list æ§å¶è¡é« |
| | | |
| | | // å¤è§ |
| | | void SetShowMaterialToggle(BOOL bShow); |
| | | BOOL GetShowMaterialToggle() const { return m_bShowMatToggle; } |
| | | |
| | | // Port æ¥å£ |
| | | int GetPortCount() const { return (int)m_ports.size(); } |
| | | int GetSlotCount() const { return m_nSlots; } |
| | | void SetPortInfo(int portIndex, LPCTSTR portName, LPCTSTR carrierName); |
| | | void SetPortAllocated(int portIndex, BOOL allocated, LPCTSTR byName = nullptr); |
| | | BOOL IsPortAllocated(int portIndex) const; |
| | | |
| | | // Slot æ¥å£ |
| | | void SetSlotGlass(int portIndex, int slotIndex, BOOL hasGlass, LPCTSTR coreId /*å¯ç©º*/, int material /*1=G1,2=G2*/); |
| | | void SetSlotChecked(int portIndex, int slotIndex, BOOL checked); |
| | | BOOL GetSlotChecked(int portIndex, int slotIndex) const; |
| | | |
| | | int GetSlotMaterialType(int portIndex, int slotIndex) const; // 1/2 |
| | | void SetSlotMaterialType(int portIndex, int slotIndex, int material, BOOL bNotify = TRUE); |
| | | |
| | | CString GetDisplayId(int portIndex, int slotIndex) const; // "Gx-core" æ "â" |
| | | void RebuildTexts(); // å头计æ°ãåå
æ ¼ä¸´æ¶ææ¬ |
| | | |
| | | // å·¥å
·ï¼æ´åå
¨é/å
¨ä¸éï¼åªå½±å hasGlass==true çæ ¼åï¼ |
| | | void CheckAllInPort(int portIndex, BOOL checked, BOOL bNotify = TRUE); |
| | | |
| | | protected: |
| | | // å
鍿°æ® |
| | | BOOL m_bFirstShown = FALSE; // å页é¢é¦æ¬¡æ¾ç¤ºå强å¶ä¸æ¬¡å
¨ééç» |
| | | int m_nSlots = 0; |
| | | std::vector<PortColumn> m_ports; |
| | | BOOL m_bShowMatToggle = TRUE; |
| | | |
| | | // UI metrics |
| | | int m_rowHeight = 24; |
| | | int m_slotColWidth = 100; |
| | | int m_portColWidth = 180; |
| | | |
| | | // è¡é«å¾åå表 |
| | | CImageList m_ilRowHeight; |
| | | |
| | | // é¢è² |
| | | COLORREF m_colBgAlt = RGB(240, 242, 245); // 交æ¿åæµ
ç° |
| | | COLORREF m_colBgNorm = RGB(255, 255, 255); |
| | | COLORREF m_colLockBg = RGB(255, 244, 214); // éå®åæ·¡é» |
| | | |
| | | // åä½ |
| | | CFont m_fntText; |
| | | CFont m_fntBold; |
| | | CFont m_fntSmall; |
| | | |
| | | // åºåè®¡ç® |
| | | CRect GetCheckboxRect(const CRect& cell) const; |
| | | CRect GetMaterialTagRect(const CRect& cell) const; |
| | | CRect GetStatusDotRect(const CRect& cell) const; |
| | | |
| | | // å·¥å
· |
| | | void EnsureFonts(); |
| | | void UpdateRowCount(); |
| | | void DrawFlatCheckbox(CDC* pDC, const CRect& r, bool checked, bool disabled); // æå¹³å¤éæ¡ |
| | | |
| | | // éç¥ç¶çªå£ï¼WM_COMMAND 飿 ¼ï¼ |
| | | void NotifySelectionChanged(int port, int slot, BOOL checked); |
| | | void NotifyMaterialChanged(int port, int slot, int material); |
| | | |
| | | protected: |
| | | // MFC |
| | | virtual void PreSubclassWindow() override; |
| | | afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); |
| | | afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); |
| | | afx_msg void OnSize(UINT nType, int cx, int cy); |
| | | afx_msg BOOL OnEraseBkgnd(CDC* pDC); |
| | | afx_msg void OnPaint(); // â
æ°å¢ï¼èªå¸¦åç¼å²ç»å¶ |
| | | afx_msg void OnLButtonDown(UINT nFlags, CPoint point); |
| | | afx_msg void OnMouseMove(UINT nFlags, CPoint point); |
| | | afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); // æè· Header éç¥ |
| | | void OnHeaderClick(int iItem); |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // CPjPage1.cpp: å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | | #include "Servo.h" |
| | | #include "CCjPage1.h" |
| | | #include "afxdialogex.h" |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CCjPage1, CCjPageBase) |
| | | |
| | | CCjPage1::CCjPage1(CWnd* pParent /*=nullptr*/) |
| | | : CCjPageBase(IDD_CJ_PAGE1, pParent) |
| | | { |
| | | } |
| | | |
| | | CCjPage1::~CCjPage1() |
| | | { |
| | | } |
| | | |
| | | void CCjPage1::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CCjPageBase::DoDataExchange(pDX); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CCjPage1, CCjPageBase) |
| | | ON_WM_DESTROY() |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CPjPage1 æ¶æ¯å¤çç¨åº |
| | | |
| | | |
| | | BOOL CCjPage1::OnInitDialog() |
| | | { |
| | | CCjPageBase::OnInitDialog(); |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | void CCjPage1::OnDestroy() |
| | | { |
| | | CCjPageBase::OnDestroy(); |
| | | |
| | | // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç |
| | | } |
| | | |
| | | void CCjPage1::Resize() |
| | | { |
| | | CCjPageBase::Resize(); |
| | | /* |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | pItem = GetDlgItem(IDC_LABEL_NO_SEL); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow((rcClient.Width() - rcItem.Width()) / 2, |
| | | (rcClient.Height() - rcItem.Height()) / 2, |
| | | rcItem.Width(), rcItem.Height()); |
| | | */ |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "CCjPageBase.h" |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | class CCjPage1 : public CCjPageBase |
| | | { |
| | | DECLARE_DYNAMIC(CCjPage1) |
| | | |
| | | public: |
| | | CCjPage1(CWnd* pParent = nullptr); // æ åæé 彿° |
| | | virtual ~CCjPage1(); |
| | | |
| | | protected: |
| | | virtual void Resize(); |
| | | |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_CJ_PAGE1 }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnDestroy(); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // CPjPage1.cpp: å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | | #include "Servo.h" |
| | | #include "CCjPage2.h" |
| | | #include "afxdialogex.h" |
| | | #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) |
| | | |
| | | CCjPage2::CCjPage2(CWnd* pParent /*=nullptr*/) |
| | | : CCjPageBase(IDD_CJ_PAGE2, pParent) |
| | | { |
| | | m_nSelRadioId = 0; |
| | | } |
| | | |
| | | CCjPage2::~CCjPage2() |
| | | { |
| | | } |
| | | |
| | | void CCjPage2::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CCjPageBase::DoDataExchange(pDX); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CCjPage2, CCjPageBase) |
| | | ON_WM_DESTROY() |
| | | ON_EN_CHANGE(IDC_EDIT_PJ_ID, &CCjPage2::OnEnChangeEditPjId) |
| | | ON_CBN_SELCHANGE(IDC_COMBO_RECIPE, &CCjPage2::OnCbnSelchangeComboRecipe) |
| | | ON_BN_CLICKED(IDC_RADIO1, &CCjPage2::OnBnClickedRadio1) |
| | | ON_BN_CLICKED(IDC_RADIO2, &CCjPage2::OnBnClickedRadio2) |
| | | ON_BN_CLICKED(IDC_RADIO3, &CCjPage2::OnBnClickedRadio3) |
| | | 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() |
| | | |
| | | |
| | | // CPjPage1 æ¶æ¯å¤çç¨åº |
| | | |
| | | |
| | | void CCjPage2::OnSetContext(void* pContext) |
| | | { |
| | | UpdatePjData(); |
| | | } |
| | | |
| | | void CCjPage2::SetPjWarps(std::vector<PJWarp>& pjs) |
| | | { |
| | | m_pjWarps = pjs; |
| | | } |
| | | |
| | | BOOL CCjPage2::OnInitDialog() |
| | | { |
| | | CCjPageBase::OnInitDialog(); |
| | | |
| | | |
| | | m_grid.SubclassDlgItem(IDC_GRID1, this); |
| | | m_grid.InitGrid(4, 8); |
| | | m_grid.SetColumnWidths(100, 220); |
| | | m_grid.SetRowHeight(32); |
| | | m_grid.SetHeaderHeight(36); |
| | | m_grid.EnableColumnResize(FALSE); // ç¦æ¢æå¨å宽 |
| | | m_grid.SetShowMaterialToggle(TRUE); |
| | | m_grid.DisableSystemScrollbars(); |
| | | m_grid.ResizeWindowToFitAll(TRUE); // TRUE=å
å«é客æ·åºï¼è¾¹æ¡ãæ 颿 ï¼ |
| | | m_grid.SetNoScrollbarsMode(TRUE); // å½»åºç¦ç¨æ»å¨æ¡ |
| | | m_grid.FitWindowToContentNoScroll(TRUE); // çªå£å°ºå¯¸å好容纳å
¨é¨å
容ï¼ä¸åºç°æ»å¨æ¡ï¼ |
| | | |
| | | m_grid.SetPortInfo(0, _T("Port 1"), _T("")); |
| | | m_grid.SetPortInfo(1, _T("Port 2"), _T("")); |
| | | m_grid.SetPortInfo(2, _T("Port 3"), _T("")); |
| | | m_grid.SetPortInfo(3, _T("Port 4"), _T("")); |
| | | |
| | | |
| | | UpdatePjData(); |
| | | |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | void CCjPage2::OnDestroy() |
| | | { |
| | | CCjPageBase::OnDestroy(); |
| | | |
| | | // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç |
| | | } |
| | | |
| | | void CCjPage2::Resize() |
| | | { |
| | | CCjPageBase::Resize(); |
| | | |
| | | |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | pItem = GetDlgItem(IDC_GRID1); |
| | | 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() |
| | | { |
| | | //SERVO::CProcessJob* |
| | | if (m_pContext == nullptr) return -1; |
| | | PJWarp* pPjWarp = (PJWarp*)m_pContext; |
| | | SERVO::CProcessJob* pProcessJob = (SERVO::CProcessJob*)pPjWarp->pj; |
| | | |
| | | // æ´æ°åç§° |
| | | BOOL bOkName = TRUE; |
| | | char szBuffer[256]; |
| | | GetDlgItemText(IDC_EDIT_PJ_ID, szBuffer, 256); |
| | | for (auto item : m_pjWarps) { |
| | | if (item.pj != pProcessJob) { |
| | | SERVO::CProcessJob* temp = (SERVO::CProcessJob*)item.pj; |
| | | if (temp->id().compare(std::string(szBuffer)) == 0) { |
| | | bOkName = FALSE; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | if (!bOkName) { |
| | | AfxMessageBox("ä¸è½ä½¿ç¨åå
¶å®Process Jobç¸åçID"); |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | pProcessJob->setId(std::string(szBuffer)); |
| | | |
| | | // æ´æ°é
æ¹ |
| | | CString strRecipe; |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_RECIPE); |
| | | int idx = pComboBox->GetCurSel(); |
| | | if (idx >= 0) { |
| | | pComboBox->GetLBText(idx, strRecipe); |
| | | #ifdef UNICODE |
| | | CT2A utf8Str(strRecipe, CP_UTF8); |
| | | std::string recipe(utf8Str); |
| | | #else |
| | | std::string recipe(strRecipe.GetString()); |
| | | #endif |
| | | |
| | | pProcessJob->setRecipe(SERVO::RecipeMethod::NoTuning, recipe); |
| | | } |
| | | |
| | | |
| | | // æ´æ°Port |
| | | int port = -1; |
| | | static int ids[] = { IDC_RADIO1, IDC_RADIO2, IDC_RADIO3, IDC_RADIO4 }; |
| | | for (int i = 0; i < 4; i++) { |
| | | int state = ((CButton*)GetDlgItem(ids[i]))->GetCheck(); |
| | | if (state == BST_CHECKED) port = i; |
| | | } |
| | | pPjWarp->port = port; |
| | | |
| | | if (pPjWarp->port != -1) { |
| | | for (int i = 0; i < 8; i++) { |
| | | pPjWarp->checkSlot[i] = m_grid.GetSlotChecked(pPjWarp->port, i); |
| | | pPjWarp->material[i] = m_grid.GetSlotMaterialType(pPjWarp->port, i); |
| | | } |
| | | } |
| | | |
| | | |
| | | ContentChanged(1); |
| | | return 0; |
| | | } |
| | | |
| | | void CCjPage2::UpdatePjData() |
| | | { |
| | | if (m_pContext == nullptr) return; |
| | | |
| | | m_bContentChangedLock = TRUE; |
| | | |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_RECIPE); |
| | | pComboBox->ResetContent(); |
| | | std::vector<std::string> vecRecipe = RecipeManager::getInstance().getAllPPID(); |
| | | for (const auto& recipe : vecRecipe) { |
| | | pComboBox->AddString(CString(recipe.c_str())); |
| | | } |
| | | |
| | | |
| | | // ComboBox |
| | | PJWarp* pPjWarp = (PJWarp*)m_pContext; |
| | | SERVO::CProcessJob* pProcessJob = (SERVO::CProcessJob*)pPjWarp->pj; |
| | | SetDlgItemText(IDC_EDIT_PJ_ID, pProcessJob->id().c_str()); |
| | | int idx = pComboBox->FindStringExact(-1, pProcessJob->recipeSpec().c_str()); |
| | | if (idx != CB_ERR) pComboBox->SetCurSel(idx); |
| | | |
| | | |
| | | // 4个checkbox |
| | | static int ids[] = { IDC_RADIO1, IDC_RADIO2, IDC_RADIO3, IDC_RADIO4}; |
| | | static char* pszUsed[] = { "Port1(å·²å ç¨)", "Port2(å·²å ç¨)", "Port3(å·²å ç¨)", "Port4(å·²å ç¨)" }; |
| | | static char* pszUnUsed[] = { "Port1(å¯ç¨)", "Port2(å¯ç¨)", "Port3(å¯ç¨)", "Port4(å¯ç¨)" }; |
| | | |
| | | int portIndex = -1; |
| | | bool enable[] = {true, true, true, true}; |
| | | bool checked[] = { false, false, false, false }; |
| | | for (auto item : m_pjWarps) { |
| | | if (0 <= item.port && item.port <= 4 && item.pj != ((PJWarp*)m_pContext)->pj) { |
| | | enable[item.port] = false; |
| | | } |
| | | } |
| | | if (0 <= ((PJWarp*)m_pContext)->port && ((PJWarp*)m_pContext)->port <= 3) { |
| | | checked[((PJWarp*)m_pContext)->port] = true; |
| | | portIndex = ((PJWarp*)m_pContext)->port; |
| | | m_nSelRadioId = ids[((PJWarp*)m_pContext)->port]; |
| | | } |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | CButton* pButton = (CButton*)GetDlgItem(ids[i]); |
| | | pButton->SetCheck(checked[i] ? BST_CHECKED : BST_UNCHECKED); |
| | | pButton->SetWindowText(enable[i] ? pszUnUsed[i] : pszUsed[i]); |
| | | 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_bContentChangedLock = FALSE; |
| | | } |
| | | |
| | | void CCjPage2::OnEnChangeEditPjId() |
| | | { |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnCbnSelchangeComboRecipe() |
| | | { |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedRadio1() |
| | | { |
| | | BOOL lock[] = {TRUE, TRUE, TRUE, TRUE}; |
| | | if (IDC_RADIO1 == m_nSelRadioId) { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, 0); |
| | | m_nSelRadioId = 0; |
| | | } |
| | | else { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, IDC_RADIO1); |
| | | m_nSelRadioId = IDC_RADIO1; |
| | | lock[0] = FALSE; |
| | | } |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedRadio2() |
| | | { |
| | | BOOL lock[] = { TRUE, TRUE, TRUE, TRUE }; |
| | | if (IDC_RADIO2 == m_nSelRadioId) { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, 0); |
| | | m_nSelRadioId = 0; |
| | | } |
| | | else { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, IDC_RADIO2); |
| | | m_nSelRadioId = IDC_RADIO2; |
| | | lock[1] = FALSE; |
| | | } |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedRadio3() |
| | | { |
| | | BOOL lock[] = { TRUE, TRUE, TRUE, TRUE }; |
| | | if (IDC_RADIO3 == m_nSelRadioId) { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, 0); |
| | | m_nSelRadioId = 0; |
| | | } |
| | | else { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, IDC_RADIO3); |
| | | m_nSelRadioId = IDC_RADIO3; |
| | | lock[2] = FALSE; |
| | | } |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnBnClickedRadio4() |
| | | { |
| | | BOOL lock[] = { TRUE, TRUE, TRUE, TRUE }; |
| | | if (IDC_RADIO4 == m_nSelRadioId) { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, 0); |
| | | m_nSelRadioId = 0; |
| | | } |
| | | else { |
| | | CheckRadioButton(IDC_RADIO1, IDC_RADIO4, IDC_RADIO4); |
| | | m_nSelRadioId = IDC_RADIO4; |
| | | lock[3] = FALSE; |
| | | } |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | m_grid.SetPortAllocated(i, lock[i], _T("")); |
| | | GetDlgItem(btnID[i])->EnableWindow(!lock[i]); |
| | | } |
| | | |
| | | ContentChanged(0); |
| | | } |
| | | |
| | | void CCjPage2::OnGridSelChanged(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | auto* nm = reinterpret_cast<CSG_SEL_CHANGE*>(pNMHDR); |
| | | const int port = nm->port; |
| | | const int slot = nm->slot; |
| | | const BOOL chk = nm->checked; |
| | | |
| | | // è¿éåä½ çä¸å¡é»è¾ |
| | | // ä¾å¦ï¼æ´æ°ç¶ææ / 忥å
¶å®æ§ä»¶ / ç»è®¡æ°é |
| | | ContentChanged(0); |
| | | |
| | | /* |
| | | if (m_pContext != nullptr) { |
| | | PJWarp* pjWarp = (PJWarp*)m_pContext; |
| | | for (int i = 0; i < 8; i++) { |
| | | pjWarp->checkSlot[i] = m_grid.GetSlotChecked(port, i); |
| | | pjWarp->material[i] = m_grid.GetSlotMaterialType(port, i); |
| | | } |
| | | } |
| | | */ |
| | | |
| | | *pResult = 0; |
| | | } |
| | | |
| | | void CCjPage2::OnGridMatChanged(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | auto* nm = reinterpret_cast<CSG_MAT_CHANGE*>(pNMHDR); |
| | | const int port = nm->port; |
| | | const int slot = nm->slot; |
| | | const int mat = nm->material; // 1/2 |
| | | |
| | | // ä¾å¦ï¼å³å»å·æ°å³ä¾§é¢è§/è®°å½æ¥å¿ç |
| | | ContentChanged(0); |
| | | |
| | | /* |
| | | if (m_pContext != nullptr) { |
| | | PJWarp* pjWarp = (PJWarp*)m_pContext; |
| | | for (int i = 0; i < 8; i++) { |
| | | pjWarp->checkSlot[i] = m_grid.GetSlotChecked(port, i); |
| | | pjWarp->material[i] = m_grid.GetSlotMaterialType(port, i); |
| | | } |
| | | } |
| | | */ |
| | | |
| | | *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); |
| | | } |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "CCjPageBase.h" |
| | | #include "ProcessJob.h" |
| | | #include "CCarrierSlotGrid.h" |
| | | |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | class CCjPage2 : public CCjPageBase |
| | | { |
| | | DECLARE_DYNAMIC(CCjPage2) |
| | | |
| | | public: |
| | | CCjPage2(CWnd* pParent = nullptr); // æ åæé 彿° |
| | | virtual ~CCjPage2(); |
| | | |
| | | public: |
| | | void SetPjWarps(std::vector<PJWarp>& pjs); |
| | | |
| | | protected: |
| | | void Resize(); |
| | | virtual int OnApply(); |
| | | virtual void OnSetContext(void* pContext); |
| | | |
| | | private: |
| | | void UpdatePjData(); |
| | | |
| | | private: |
| | | CCarrierSlotGrid m_grid; |
| | | std::vector<PJWarp> m_pjWarps; |
| | | int m_nSelRadioId; |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_CJ_PAGE1 }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnDestroy(); |
| | | afx_msg void OnEnChangeEditPjId(); |
| | | afx_msg void OnCbnSelchangeComboRecipe(); |
| | | afx_msg void OnBnClickedRadio1(); |
| | | afx_msg void OnBnClickedRadio2(); |
| | | afx_msg void OnBnClickedRadio3(); |
| | | 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(); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // CPjPage1.cpp: å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | | #include "Servo.h" |
| | | #include "CCjPage3.h" |
| | | #include "afxdialogex.h" |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CCjPage3, CCjPageBase) |
| | | |
| | | CCjPage3::CCjPage3(CWnd* pParent /*=nullptr*/) |
| | | : CCjPageBase(IDD_CJ_PAGE3, pParent) |
| | | { |
| | | |
| | | } |
| | | |
| | | CCjPage3::~CCjPage3() |
| | | { |
| | | } |
| | | |
| | | void CCjPage3::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CCjPageBase::DoDataExchange(pDX); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CCjPage3, CCjPageBase) |
| | | ON_WM_DESTROY() |
| | | ON_EN_CHANGE(IDC_EDIT_CJ_ID, &CCjPage3::OnEnChangeEditCjId) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CPjPage1 æ¶æ¯å¤çç¨åº |
| | | |
| | | |
| | | BOOL CCjPage3::OnInitDialog() |
| | | { |
| | | CCjPageBase::OnInitDialog(); |
| | | |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | void CCjPage3::OnDestroy() |
| | | { |
| | | CCjPageBase::OnDestroy(); |
| | | |
| | | // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç |
| | | } |
| | | |
| | | void CCjPage3::Resize() |
| | | { |
| | | CCjPageBase::Resize(); |
| | | |
| | | /* |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | pItem = GetDlgItem(IDC_LABEL_NO_SEL); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow((rcClient.Width() - rcItem.Width()) / 2, |
| | | (rcClient.Height() - rcItem.Height()) / 2, |
| | | rcItem.Width(), rcItem.Height()); |
| | | */ |
| | | } |
| | | |
| | | 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 å¯¹è¯æ¡ |
| | | |
| | | class CCjPage3 : public CCjPageBase |
| | | { |
| | | DECLARE_DYNAMIC(CCjPage3) |
| | | |
| | | public: |
| | | CCjPage3(CWnd* pParent = nullptr); // æ åæé 彿° |
| | | virtual ~CCjPage3(); |
| | | |
| | | protected: |
| | | void Resize(); |
| | | virtual int OnApply(); |
| | | virtual void OnSetContext(void* pContext); |
| | | void UpdateCjData(); |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_CJ_PAGE1 }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnDestroy(); |
| | | afx_msg void OnEnChangeEditCjId(); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // CPjPage1.cpp: å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | | #include "Servo.h" |
| | | #include "CCjPageBase.h" |
| | | #include "afxdialogex.h" |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CCjPageBase, CDialogEx) |
| | | |
| | | CCjPageBase::CCjPageBase(UINT nID, CWnd* pPage) : CDialogEx(nID, pPage) |
| | | { |
| | | m_crBkgnd = RGB(255, 255, 255); |
| | | m_crBkgndCached = CLR_INVALID; |
| | | m_onContentChanged = nullptr; |
| | | m_bContentChangedLock = FALSE; |
| | | m_pContext = nullptr; |
| | | m_nContextType = 0; |
| | | } |
| | | |
| | | CCjPageBase::~CCjPageBase() |
| | | { |
| | | } |
| | | |
| | | void CCjPageBase::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CDialogEx::DoDataExchange(pDX); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CCjPageBase, CDialogEx) |
| | | ON_WM_CTLCOLOR() |
| | | ON_WM_SIZE() |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CPjPage1 æ¶æ¯å¤çç¨åº |
| | | |
| | | void CCjPageBase::SetTitle(CString strTitle) |
| | | { |
| | | SetDlgItemText(IDC_LABEL_TITLE, strTitle); |
| | | } |
| | | |
| | | void CCjPageBase::SetContext(void* pContext, int type) |
| | | { |
| | | m_pContext = pContext; |
| | | m_nContextType = type; |
| | | OnSetContext(pContext); |
| | | } |
| | | |
| | | void* CCjPageBase::GetContext() |
| | | { |
| | | return m_pContext; |
| | | } |
| | | |
| | | void CCjPageBase::SetOnContentChanged(ONCONTENTCHANGED onContentChanged) |
| | | { |
| | | m_onContentChanged = onContentChanged; |
| | | } |
| | | |
| | | BOOL CCjPageBase::OnInitDialog() |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | Resize(); |
| | | |
| | | |
| | | m_labelTitle.SubclassDlgItem(IDC_LABEL_TITLE, this); |
| | | m_labelTitle.Setpadding(PADDING_LEFT, 0); |
| | | m_labelTitle.Setpadding(PADDING_RIGHT, 0); |
| | | |
| | | ; |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | |
| | | HBRUSH CCjPageBase::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) |
| | | { |
| | | HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor); |
| | | |
| | | // æ³ç»åªäºæ§ä»¶æ¹åºè²å°±æå®ä»¬çç±»ååè¿æ¥ï¼ |
| | | const bool needCustomBg = |
| | | (nCtlColor == CTLCOLOR_STATIC) || |
| | | (nCtlColor == CTLCOLOR_DLG) || // å¯¹è¯æ¡åºè² |
| | | (nCtlColor == CTLCOLOR_BTN); // æé®ï¼å¯éï¼ |
| | | |
| | | if (needCustomBg) |
| | | { |
| | | // è¥ç¬¬ä¸æ¬¡åå»ºï¼æé¢è²æ¹ååé建 |
| | | if (m_brBkgnd.GetSafeHandle() == nullptr || m_crBkgndCached != m_crBkgnd) |
| | | { |
| | | if (m_brBkgnd.GetSafeHandle()) |
| | | m_brBkgnd.DeleteObject(); |
| | | |
| | | m_brBkgnd.CreateSolidBrush(m_crBkgnd); |
| | | m_crBkgndCached = m_crBkgnd; |
| | | } |
| | | |
| | | // ææ¬åæ¯/èæ¯è®¾ç½®ï¼ä»
影忿¬ç»å¶ï¼ |
| | | pDC->SetBkColor(m_crBkgnd); |
| | | pDC->SetTextColor(RGB(0, 0, 0)); |
| | | // å¦éè®©éæææ¬éæå å¨åºè²ä¸ï¼å¯ç¨ï¼ |
| | | // pDC->SetBkMode(TRANSPARENT); |
| | | |
| | | return (HBRUSH)m_brBkgnd; // å®å
¨çéå¼è½¬æ¢ |
| | | } |
| | | |
| | | // å
¶ä»æ§ä»¶ç±»å沿ç¨åºç±»é»è®¤çå·å |
| | | return hbr; |
| | | } |
| | | |
| | | void CCjPageBase::OnSize(UINT nType, int cx, int cy) |
| | | { |
| | | CDialogEx::OnSize(nType, cx, cy); |
| | | if (GetDlgItem(IDC_LABEL_TITLE) == nullptr) return; |
| | | Resize(); |
| | | } |
| | | |
| | | void CCjPageBase::Resize() |
| | | { |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | pItem = GetDlgItem(IDC_LABEL_TITLE); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(12, 8, rcClient.Width() - 24, rcItem.Height()); |
| | | } |
| | | |
| | | void CCjPageBase::ContentChanged(int code) |
| | | { |
| | | if (!m_bContentChangedLock && m_onContentChanged != nullptr) { |
| | | m_onContentChanged(this, code, m_pContext, m_nContextType); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "GroupLabel.h" |
| | | #include <functional> |
| | | |
| | | |
| | | typedef std::function<void(void* pFrom, int code, void* pContext, int contextType)> ONCONTENTCHANGED; |
| | | |
| | | |
| | | // CPjPage1 å¯¹è¯æ¡ |
| | | |
| | | class CCjPageBase : public CDialogEx |
| | | { |
| | | DECLARE_DYNAMIC(CCjPageBase) |
| | | |
| | | public: |
| | | CCjPageBase(UINT nID, CWnd* pPage); // æ åæé 彿° |
| | | virtual ~CCjPageBase(); |
| | | |
| | | public: |
| | | void SetTitle(CString strTitle); |
| | | virtual int OnApply() { return 0; }; |
| | | void SetOnContentChanged(ONCONTENTCHANGED onContentChanged); |
| | | void SetContext(void* pContext, int type); |
| | | void* GetContext(); |
| | | |
| | | protected: |
| | | virtual void Resize(); |
| | | virtual void ContentChanged(int code); |
| | | virtual void OnSetContext(void* pContext) { }; |
| | | |
| | | private: |
| | | COLORREF m_crBkgndCached; |
| | | CBrush m_brBkgnd; |
| | | CGroupLabel m_labelTitle; |
| | | ONCONTENTCHANGED m_onContentChanged; |
| | | |
| | | protected: |
| | | COLORREF m_crBkgnd; |
| | | BOOL m_bContentChangedLock; |
| | | void* m_pContext; |
| | | int m_nContextType; |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_CJ_PAGE1 }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); |
| | | afx_msg void OnSize(UINT nType, int cx, int cy); |
| | | }; |
| | |
| | | #include "SerializeUtil.h" |
| | | |
| | | static inline std::string trimCopy(std::string s) { |
| | | auto notspace = [](int ch) { return !std::isspace(ch); }; |
| | | s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace)); |
| | | s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end()); |
| | | s.erase(s.begin(), |
| | | std::find_if(s.begin(), s.end(), |
| | | [](char c) { return !std::isspace(static_cast<unsigned char>(c)); })); |
| | | s.erase(std::find_if(s.rbegin(), s.rend(), |
| | | [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }).base(), |
| | | s.end()); |
| | | return s; |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::addPjPointer(CProcessJob* pj) |
| | | { |
| | | for (auto item : m_pjs) { |
| | | if (item->id().compare(pj->id()) == 0) return false; |
| | | } |
| | | |
| | | m_pjs.push_back(pj); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::removePjPointer(const std::string& id) |
| | | { |
| | | for(auto iter = m_pjs.begin(); iter != m_pjs.end(); ++iter) { |
| | | if ((*iter)->id().compare(id) == 0) { |
| | | m_pjs.erase(iter); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | bool CControlJob::removePJ(const std::string& pjId) { |
| | | auto it = std::find(m_pjIds.begin(), m_pjIds.end(), pjId); |
| | | if (it == m_pjIds.end()) return false; |
| | |
| | | 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; |
| | |
| | | out = CControlJob(cjId); |
| | | out.setPriority(prio); |
| | | |
| | | // ç´æ¥æ¢å¤å
é¨ç¶æï¼è¥ä½ è¦æ±èµ°ç¶ææºï¼å¯å¨è¿éæåæ³è¿æ¸¡è°ç¨ queue()/start()/...ï¼ |
| | | // ç®åï¼ç´æ¥èµå¼ï¼ä½ å¨ CControlJob.cpp å
é¨ï¼å¯è®¿é®ç§ææåï¼ |
| | | struct Access : CControlJob { |
| | | using CControlJob::m_state; |
| | | using CControlJob::m_failReason; |
| | | using CControlJob::m_tQueued; |
| | | using CControlJob::m_tStart; |
| | | using CControlJob::m_tEnd; |
| | | using CControlJob::m_pjIds; |
| | | }; |
| | | auto& a = reinterpret_cast<Access&>(out); |
| | | a.m_state = static_cast<CJState>(st); |
| | | a.m_failReason = std::move(failText); |
| | | a.m_tQueued = std::move(tQ); |
| | | a.m_tStart = std::move(tS); |
| | | a.m_tEnd = std::move(tE); |
| | | a.m_pjIds = std::move(pjIds); |
| | | out.m_state = static_cast<CJState>(st); |
| | | out.m_failReason = std::move(failText); |
| | | out.m_tQueued = std::move(tQ); |
| | | out.m_tStart = std::move(tS); |
| | | out.m_tEnd = std::move(tE); |
| | | out.m_pjIds = std::move(pjIds); |
| | | |
| | | 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; } |
| | |
| | | bool containsPJ(const std::string& pjId) const; |
| | | const std::vector<std::string>& pjIds() const noexcept { return m_pjIds; } |
| | | bool setPJs(const std::vector<CProcessJob*>& pjs); |
| | | bool removePjPointer(const std::string& id); |
| | | bool addPjPointer(CProcessJob* pj); |
| | | void clearPJs() { m_pjIds.clear(); } |
| | | const std::vector<CProcessJob*>& getPjs() { return m_pjs; }; |
| | | |
| | |
| | | const std::function<bool(const std::string&)>& getPjExistsFn, |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ); |
| | | const std::vector<CControlJob::ValidationIssue>& CControlJob::issues(); |
| | | 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); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // CControlJobManagerDlg.cpp: å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | | #include "Servo.h" |
| | | #include "CControlJobManagerDlg.h" |
| | | #include "afxdialogex.h" |
| | | #include "ToolUnits.h" |
| | | #include "RecipeManager.h" |
| | | |
| | | |
| | | bool CControlJobManagerDlg::m_bHasState = false; |
| | | CControlJobManagerDlg::State CControlJobManagerDlg::m_state{}; |
| | | |
| | | // CControlJobManagerDlg å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CControlJobManagerDlg, CDialogEx) |
| | | |
| | | CControlJobManagerDlg::CControlJobManagerDlg(CWnd* pParent /*=nullptr*/) |
| | | : CDialogEx(IDD_DIALOG_CONTROL_JOB_MANAGER, pParent) |
| | | { |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | CControlJobManagerDlg::~CControlJobManagerDlg() |
| | | { |
| | | |
| | | } |
| | | |
| | | void CControlJobManagerDlg::FreeState() |
| | | { |
| | | if (!m_bHasState) return; |
| | | for (auto item : m_state.pjWarps) { |
| | | delete (SERVO::CProcessJob*)item.pj; |
| | | } |
| | | m_state.pjWarps.clear(); |
| | | |
| | | if (m_state.pControlJob != nullptr) { |
| | | delete m_state.pControlJob; |
| | | m_state.pControlJob = nullptr; |
| | | } |
| | | m_bHasState = false; |
| | | } |
| | | |
| | | void CControlJobManagerDlg::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CDialogEx::DoDataExchange(pDX); |
| | | DDX_Control(pDX, IDC_TREE1, m_tree); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CControlJobManagerDlg, CDialogEx) |
| | | ON_WM_SIZE() |
| | | ON_WM_GETMINMAXINFO() |
| | | ON_NOTIFY(TVN_ITEMCHANGED, IDC_TREE1, &CControlJobManagerDlg::OnTvnItemChangedTree) |
| | | ON_NOTIFY(NM_CLICK, IDC_TREE1, &CControlJobManagerDlg::OnTreeClick) // æ°å¢ |
| | | ON_NOTIFY(TVN_KEYDOWN, IDC_TREE1, &CControlJobManagerDlg::OnTreeKeyDown) // æ°å¢ |
| | | ON_MESSAGE(WM_AFTER_TVCHECK, &CControlJobManagerDlg::OnAfterTvCheck) // æ°å¢ |
| | | ON_WM_DESTROY() |
| | | ON_BN_CLICKED(IDC_BUTTON_APPLY, &CControlJobManagerDlg::OnBnClickedButtonApply) |
| | | ON_NOTIFY(TVN_SELCHANGING, IDC_TREE1, &CControlJobManagerDlg::OnTvnSelchangingTree1) |
| | | ON_BN_CLICKED(IDC_BUTTON_BATH_COMPLETION, &CControlJobManagerDlg::OnBnClickedButtonBathCompletion) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CControlJobManagerDlg æ¶æ¯å¤çç¨åº |
| | | |
| | | |
| | | BOOL CControlJobManagerDlg::OnInitDialog() |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | |
| | | auto onContentChanged = [&](void* pFrom, int code, void* pContext, int contextType) -> void { |
| | | if (0 == code) { |
| | | GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(TRUE); |
| | | } |
| | | else if (1 == code) { |
| | | if (contextType == 1) { |
| | | UpProcessJobId((PJWarp*)pContext); |
| | | } |
| | | else if (contextType == 2) { |
| | | UpControlJobId((SERVO::CControlJob*)pContext); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // page1 |
| | | CCjPage1* pPage1 = new CCjPage1(this); |
| | | pPage1->Create(IDD_CJ_PAGE1, this); |
| | | pPage1->SetTitle(_T("æªéæ©")); |
| | | pPage1->SetOnContentChanged(onContentChanged); |
| | | pPage1->ShowWindow(SW_SHOW); |
| | | m_pages.push_back(pPage1); |
| | | |
| | | // page2 |
| | | CCjPage2* pPage2 = new CCjPage2(this); |
| | | pPage2->Create(IDD_CJ_PAGE2, this); |
| | | pPage2->SetTitle(_T("ProcessJob")); |
| | | pPage2->SetOnContentChanged(onContentChanged); |
| | | m_pages.push_back(pPage2); |
| | | |
| | | // page3 |
| | | CCjPage3* pPage3 = new CCjPage3(this); |
| | | pPage3->Create(IDD_CJ_PAGE3, this); |
| | | pPage3->SetTitle(_T("ControlJob")); |
| | | pPage3->SetOnContentChanged(onContentChanged); |
| | | m_pages.push_back(pPage3); |
| | | |
| | | |
| | | // tree |
| | | m_tree.ModifyStyle(0, TVS_CHECKBOXES); |
| | | |
| | | |
| | | InitData(); |
| | | UpdateControlJob(); |
| | | UpdateCtrlState(); |
| | | Resize(); |
| | | |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnSize(UINT nType, int cx, int cy) |
| | | { |
| | | CDialogEx::OnSize(nType, cx, cy); |
| | | if (GetDlgItem(IDC_TREE1) == nullptr) return; |
| | | |
| | | Resize(); |
| | | } |
| | | |
| | | void CControlJobManagerDlg::Resize() |
| | | { |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | |
| | | GetDlgItem(IDCANCEL)->GetWindowRect(&rcItem); |
| | | ScreenToClient(&rcItem); |
| | | |
| | | const int LEFTWIDTH = 218; |
| | | int x = 12, y = 12; |
| | | int x2 = rcClient.right - 12; |
| | | int y2 = rcClient.bottom - 12; |
| | | |
| | | |
| | | // å
ç§»å¨æé® |
| | | pItem = GetDlgItem(IDC_BUTTON_APPLY); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x2 - rcItem.Width(), y2 - rcItem.Height(), rcItem.Width(), rcItem.Height()); |
| | | x2 -= rcItem.Width(); |
| | | x2 -= 8; |
| | | |
| | | pItem = GetDlgItem(IDC_BUTTON_BATH_COMPLETION); |
| | | pItem->GetWindowRect(&rcItem); |
| | | pItem->MoveWindow(x2 - rcItem.Width(), y2 - rcItem.Height(), rcItem.Width(), rcItem.Height()); |
| | | x += rcItem.Width(); |
| | | x += 8; |
| | | |
| | | y2 -= rcItem.Height(); |
| | | y2 -= 8; |
| | | |
| | | |
| | | // æ æ§ä»¶ |
| | | x = 12; |
| | | y = 12; |
| | | pItem = GetDlgItem(IDC_TREE1); |
| | | pItem->MoveWindow(x, y, LEFTWIDTH, y2 - y); |
| | | x += LEFTWIDTH; |
| | | x += 5; |
| | | |
| | | |
| | | // åé¡µé¢ |
| | | x2 = rcClient.right - 12; |
| | | for (auto page : m_pages) { |
| | | page->MoveWindow(x, 12, x2 - x, y2 - 12); |
| | | } |
| | | |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) |
| | | { |
| | | CDialogEx::OnGetMinMaxInfo(lpMMI); |
| | | |
| | | // 设置æå°å®½é«ï¼æ¯å¦ 400x300ï¼ |
| | | lpMMI->ptMinTrackSize.x = 600; |
| | | lpMMI->ptMinTrackSize.y = 400; |
| | | |
| | | // ä¹å¯ä»¥é¡ºä¾¿è®¾ç½®æå¤§å®½é« |
| | | // lpMMI->ptMaxTrackSize.x = 800; |
| | | // lpMMI->ptMaxTrackSize.y = 600; |
| | | } |
| | | |
| | | void CControlJobManagerDlg::UpdateCtrlState() |
| | | { |
| | | GetDlgItem(IDC_BUTTON_BATH_COMPLETION)->EnableWindow(true); |
| | | } |
| | | |
| | | void CControlJobManagerDlg::UpdateControlJob() |
| | | { |
| | | m_tree.DeleteAllItems(); |
| | | if (m_pControlJob == nullptr) return; |
| | | |
| | | HTREEITEM hRoot = m_tree.InsertItem(m_pControlJob->id().c_str(), 0, 0); |
| | | m_tree.SetItemData(hRoot, (DWORD_PTR)m_pControlJob); |
| | | m_tree.SetItemState(hRoot, 0, TVIS_STATEIMAGEMASK); |
| | | for (auto& item : m_pjWarps) { |
| | | HTREEITEM hItem = m_tree.InsertItem(((SERVO::CProcessJob*)item.pj)->id().c_str(), 0, 0, hRoot); |
| | | m_tree.SetItemData(hItem, (DWORD_PTR)&item); |
| | | m_tree.SetItemState(hItem, INDEXTOSTATEIMAGEMASK(item.addToCj ? 2 : 1), TVIS_STATEIMAGEMASK); |
| | | } |
| | | m_tree.Expand(hRoot, TVE_EXPAND); |
| | | } |
| | | |
| | | bool CControlJobManagerDlg::AddPorcessJob(SERVO::CProcessJob* pj) |
| | | { |
| | | if (m_pControlJob == nullptr) return false; |
| | | return m_pControlJob->addPjPointer(pj); |
| | | } |
| | | |
| | | bool CControlJobManagerDlg::RemovePorcessJob(SERVO::CProcessJob* pj) |
| | | { |
| | | if (m_pControlJob == nullptr) return false; |
| | | return m_pControlJob->removePjPointer(pj->id()); |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnTvnItemChangedTree(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | auto* p = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); |
| | | UINT oldState = p->itemOld.state, newState = p->itemNew.state; |
| | | HTREEITEM hItem = p->itemNew.hItem; |
| | | |
| | | if (((oldState ^ newState) & TVIS_STATEIMAGEMASK) != 0) { |
| | | const int idx = (newState & TVIS_STATEIMAGEMASK) >> 12; // 1=æªé,2=å·²é |
| | | const bool checked = (idx == 2); |
| | | |
| | | PJWarp* pjWarp = (PJWarp*)m_tree.GetItemData(hItem); |
| | | if (pjWarp != nullptr) { |
| | | CString s; s.Format("%s %d", ((SERVO::CProcessJob*)pjWarp->pj)->id().c_str(), |
| | | checked ? "" : ""); |
| | | AfxMessageBox(s); |
| | | } |
| | | } |
| | | |
| | | |
| | | *pResult = 0; |
| | | } |
| | | |
| | | // å½ä¸å¤éæ¡ï¼ç¨ NM_CLICK åå½ä¸æµè¯ï¼ç¶åâæ»åâè¯»åæ°ç¶æ |
| | | void CControlJobManagerDlg::OnTreeClick(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | *pResult = 0; |
| | | |
| | | DWORD pos = ::GetMessagePos(); |
| | | CPoint pt(GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); |
| | | m_tree.ScreenToClient(&pt); |
| | | |
| | | TVHITTESTINFO ht{}; ht.pt = pt; |
| | | HTREEITEM hItem = m_tree.HitTest(&ht); |
| | | if (hItem && (ht.flags & TVHT_ONITEMSTATEICON)) { |
| | | // 让 TreeView å
忢ï¼å弿¥è¯»åæç»ç¶æ |
| | | PostMessage(WM_AFTER_TVCHECK, (WPARAM)hItem, 0); |
| | | } |
| | | } |
| | | |
| | | // ç©ºæ ¼é®ä¹ä¼åæ¢å¤éæ¡ |
| | | void CControlJobManagerDlg::OnTreeKeyDown(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | *pResult = 0; |
| | | auto* p = reinterpret_cast<LPNMTVKEYDOWN>(pNMHDR); |
| | | if (p->wVKey == VK_SPACE) { |
| | | HTREEITEM hItem = m_tree.GetSelectedItem(); |
| | | if (hItem) PostMessage(WM_AFTER_TVCHECK, (WPARAM)hItem, 0); |
| | | } |
| | | } |
| | | |
| | | // ç»ä¸å¤çï¼è¯»æç»ç¶æ + ä½ çä¸å¡ï¼ |
| | | LRESULT CControlJobManagerDlg::OnAfterTvCheck(WPARAM wParam, LPARAM /*lParam*/) |
| | | { |
| | | HTREEITEM hItem = (HTREEITEM)wParam; |
| | | if (!hItem) return 0; |
| | | |
| | | // åªå¤ç第äºå±ï¼æ ¹çç´æ¥åèç¹ï¼å¯éï¼ |
| | | auto getLevel = [&](HTREEITEM h) { |
| | | int lv = 0; for (HTREEITEM p = m_tree.GetParentItem(h); p; p = m_tree.GetParentItem(p)) ++lv; return lv; |
| | | }; |
| | | if (getLevel(hItem) != 1) return 0; |
| | | |
| | | BOOL checked = m_tree.GetCheck(hItem); |
| | | |
| | | // ä½ çä¸å¡é»è¾ï¼ä¿®æ£äº CString::Format çåæ°ç±»åï¼ |
| | | auto* pjWarp = reinterpret_cast<PJWarp*>(m_tree.GetItemData(hItem)); |
| | | if (pjWarp) { |
| | | pjWarp->addToCj = checked; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnTvnSelchangingTree1(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); |
| | | |
| | | bool allow = FALSE; |
| | | HTREEITEM hOldSel = pNMTreeView->itemOld.hItem; |
| | | HTREEITEM hSel = pNMTreeView->itemNew.hItem; |
| | | if (hSel != nullptr) { |
| | | HTREEITEM hParent = m_tree.GetParentItem(hSel); |
| | | if (hParent == nullptr) { |
| | | 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) { |
| | | if (0 == ShowPage(1)) { |
| | | PJWarp* pjWarp = (PJWarp*)m_tree.GetItemData(hSel); |
| | | ((CCjPage2*)m_pages[1])->SetPjWarps(m_pjWarps); |
| | | m_pages[1]->SetContext(pjWarp, 1); |
| | | } |
| | | else { |
| | | allow = TRUE; |
| | | } |
| | | } |
| | | else { |
| | | // æç¥å
â 第ä¸å±åä»¥ä¸ â Glass |
| | | } |
| | | } |
| | | |
| | | *pResult = allow; |
| | | } |
| | | |
| | | int CControlJobManagerDlg::ShowPage(int index) |
| | | { |
| | | ASSERT(0 <= index && index <= 2); |
| | | |
| | | for (int i = 0; i < 3; i++) { |
| | | if (m_pages[i]->IsWindowVisible()) { |
| | | int ret = m_pages[i]->OnApply(); |
| | | if (ret != 0) return -1; |
| | | } |
| | | |
| | | m_pages[i]->ShowWindow(index == i ? SW_SHOW : SW_HIDE); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnDestroy() |
| | | { |
| | | CDialogEx::OnDestroy(); |
| | | SaveState(); |
| | | |
| | | for (auto page : m_pages) { |
| | | page->DestroyWindow(); |
| | | delete page; |
| | | } |
| | | } |
| | | |
| | | void CControlJobManagerDlg::InitData() |
| | | { |
| | | LoadState(); |
| | | if (m_pControlJob != nullptr) return; |
| | | |
| | | m_pControlJob = new SERVO::CControlJob("CJ" + CToolUnits::NowStrSec()); |
| | | |
| | | char szBuffer[256]; |
| | | for (int i = 0; i < 4; i++) { |
| | | sprintf_s(szBuffer, 256, "PJ%03d", i + 1); |
| | | SERVO::CProcessJob* pj = new SERVO::CProcessJob(std::string(szBuffer)); |
| | | PJWarp pjWarp = {}; |
| | | pjWarp.pj = pj; |
| | | pjWarp.port = -1; |
| | | m_pjWarps.push_back(pjWarp); |
| | | } |
| | | } |
| | | |
| | | void CControlJobManagerDlg::OnBnClickedButtonApply() |
| | | { |
| | | for (auto item : m_pages) { |
| | | if (item->IsWindowVisible()) { |
| | | if (0 == item->OnApply()) { |
| | | GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(FALSE); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void CControlJobManagerDlg::UpProcessJobId(PJWarp* pjWarp) |
| | | { |
| | | // æ´æ°æ æ§ä»¶ |
| | | // éåæ ¹èç¹ |
| | | HTREEITEM hRoot = m_tree.GetRootItem(); |
| | | while (hRoot) { |
| | | // éå第äºå±åèç¹ |
| | | HTREEITEM hChild = m_tree.GetChildItem(hRoot); |
| | | while (hChild) { |
| | | DWORD_PTR data = m_tree.GetItemData(hChild); |
| | | if ((void*)data == pjWarp) { |
| | | SERVO::CProcessJob* pj = (SERVO::CProcessJob*)pjWarp->pj; |
| | | m_tree.SetItemText(hChild, pj->id().c_str()); |
| | | return; // æ¾å°å°±è¿å |
| | | } |
| | | hChild = m_tree.GetNextSiblingItem(hChild); |
| | | } |
| | | |
| | | hRoot = m_tree.GetNextSiblingItem(hRoot); |
| | | } |
| | | } |
| | | |
| | | 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; |
| | | |
| | | // æ s_state -> æååé |
| | | m_pControlJob = m_state.pControlJob; |
| | | m_pjWarps = m_state.pjWarps; |
| | | } |
| | | |
| | | void CControlJobManagerDlg::SaveState() |
| | | { |
| | | m_state.pControlJob = m_pControlJob; |
| | | m_state.pjWarps = m_pjWarps; |
| | | m_bHasState = true; |
| | | } |
| | | |
| | | 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()) { |
| | | int ret = m_pages[i]->OnApply(); |
| | | if (ret != 0) return ; |
| | | } |
| | | } |
| | | GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(FALSE); |
| | | |
| | | |
| | | // å
æ£æ¥æ°æ®æ£ç¡®æ§ |
| | | int checkCount = 0; |
| | | for (auto item : m_pjWarps) { |
| | | if (!item.addToCj) continue; |
| | | checkCount++; |
| | | } |
| | | if (checkCount == 0) { |
| | | AfxMessageBox(_T("æ¨æ²¡æéæ©è¦è¿è¡å·¥èºå¤ççProcess Job!\n请å¨è¦è¿è¡å·¥èºå¤ççProcess Jobåæå¾ã")); |
| | | return; |
| | | } |
| | | |
| | | |
| | | 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); |
| | | |
| | | bool bProcessStart[] = {false, false, false, false}; |
| | | std::vector<SERVO::CProcessJob*> pjs; |
| | | for (auto item : m_pjWarps) { |
| | | if (!item.addToCj) continue; |
| | | if (item.port == -1) continue; |
| | | BOOL bCheck = FALSE; |
| | | for (int i = 0; i < 8; i++) { |
| | | if (item.checkSlot[i]) { |
| | | bCheck = TRUE; |
| | | break; |
| | | } |
| | | } |
| | | 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 = pPorts[item.port]->getCassetteId(); |
| | | for (int i = 0; i < 8; i++) { |
| | | if (item.checkSlot[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()); |
| | | } |
| | | |
| | | |
| | | if (pjs.empty()) { |
| | | AfxMessageBox(_T("没æéè¦è¿è¡å·¥èºå¤ççProcess Job!\nå¯è½æªéæ©Portæéæ©ä»»ä½ç©æã")); |
| | | return; |
| | | } |
| | | |
| | | m_pControlJob->setPJs(pjs); |
| | | m_pControlJob->clearIssues(); |
| | | int nRet = master.setProcessJobs(pjs); |
| | | |
| | | // 没æé®é¢ç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); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "CCjPage1.h" |
| | | #include "CCjPage2.h" |
| | | #include "CCjPage3.h" |
| | | #include "ApredTreeCtrl2.h" |
| | | |
| | | |
| | | #define WM_AFTER_TVCHECK (WM_USER + 1000) |
| | | |
| | | // CControlJobManagerDlg å¯¹è¯æ¡ |
| | | |
| | | class CControlJobManagerDlg : public CDialogEx |
| | | { |
| | | DECLARE_DYNAMIC(CControlJobManagerDlg) |
| | | |
| | | public: |
| | | CControlJobManagerDlg(CWnd* pParent = nullptr); // æ åæé 彿° |
| | | virtual ~CControlJobManagerDlg(); |
| | | static void FreeState(); |
| | | |
| | | private: |
| | | void Resize(); |
| | | void UpdateCtrlState(); |
| | | void UpdateControlJob(); |
| | | 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(); |
| | | int ShowPage(int index); |
| | | |
| | | private: |
| | | std::vector<CCjPageBase*> m_pages; |
| | | SERVO::CControlJob* m_pControlJob; |
| | | std::vector<PJWarp> m_pjWarps; |
| | | CApredTreeCtrl2 m_tree; |
| | | |
| | | public: |
| | | struct State { |
| | | SERVO::CControlJob* pControlJob = nullptr; |
| | | std::vector<PJWarp> pjWarps; |
| | | }; |
| | | static bool m_bHasState; |
| | | static State m_state; |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_DIALOG_CONTROL_JOB_MANAGER }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnSize(UINT nType, int cx, int cy); |
| | | afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); |
| | | afx_msg void OnTvnItemChangedTree(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnDestroy(); |
| | | afx_msg void OnBnClickedButtonApply(); |
| | | afx_msg void OnTvnSelchangingTree1(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnBnClickedButtonBathCompletion(); |
| | | afx_msg void OnTreeClick(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnTreeKeyDown(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg LRESULT OnAfterTvCheck(WPARAM wParam, LPARAM lParam); |
| | | }; |
| | |
| | | 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); |
| | |
| | | |
| | | auto rawData = processData.getParamsRawData(); |
| | | std::vector<CParam> tempParams; |
| | | this->parsingParams((const char*)rawData.data(), rawData.size(), tempParams); |
| | | this->parsingProcessData((const char*)rawData.data(), rawData.size(), tempParams); |
| | | int n = processData.getTotalParameter(); |
| | | std::vector<CParam> params(tempParams.begin(), tempParams.begin() + min(n, (int)tempParams.size())); |
| | | pGlass->addParams(params); |
| | |
| | | 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; |
| | | } |
| | |
| | | return -1; |
| | | }); |
| | | pStep->setName(STEP_EQ_FAC_DATA_REPORT); |
| | | pStep->setProp("Port", (void*)port); |
| | | pStep->setProp("Port", (void*)(__int64)port); |
| | | pStep->setWriteSignalDev(writeSignalDev); |
| | | if (addStep(STEP_ID_FAC_DATA_REPORT, pStep) != 0) { |
| | | delete pStep; |
| | |
| | | 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"; |
| | |
| | | |
| | | return strOut; |
| | | } |
| | | |
| | | // ========== SVæ°æ®ç®¡çæ¥å£å®ç° ========== |
| | | |
| | | void CGlass::addSVData(int machineId, const std::string& dataType, const SVDataItem& dataItem) { |
| | | m_svDatas[machineId][dataType].push_back(dataItem); |
| | | } |
| | | |
| | | void CGlass::addSVData(int machineId, const std::string& dataType, double value) { |
| | | auto now = std::chrono::system_clock::now(); |
| | | m_svDatas[machineId][dataType].emplace_back(now, value); |
| | | } |
| | | |
| | | void CGlass::addSVData(int machineId, const std::string& dataType, int64_t timestamp, double value) { |
| | | // å°int64_tæ¶é´æ³è½¬æ¢ä¸ºsystem_clock::time_point |
| | | std::chrono::system_clock::time_point timePoint{ |
| | | std::chrono::milliseconds(timestamp) // å设timestampæ¯æ¯«ç§ |
| | | // 妿æ¯ç§ï¼ä½¿ç¨ï¼std::chrono::seconds(timestamp) |
| | | }; |
| | | m_svDatas[machineId][dataType].emplace_back(timePoint, value); |
| | | } |
| | | |
| | | void CGlass::addSVData(int machineId, const std::string& dataType, const std::vector<SVDataItem>& dataItems) { |
| | | auto& dataList = m_svDatas[machineId][dataType]; |
| | | dataList.insert(dataList.end(), dataItems.begin(), dataItems.end()); |
| | | } |
| | | |
| | | std::vector<SVDataItem> CGlass::getSVData(int machineId, const std::string& dataType) const { |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | auto dataIt = machineIt->second.find(dataType); |
| | | if (dataIt != machineIt->second.end()) { |
| | | return dataIt->second; |
| | | } |
| | | } |
| | | return std::vector<SVDataItem>(); |
| | | } |
| | | |
| | | std::vector<std::string> CGlass::getSVDataTypes(int machineId) const { |
| | | std::vector<std::string> types; |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | for (const auto& pair : machineIt->second) { |
| | | types.push_back(pair.first); |
| | | } |
| | | } |
| | | return types; |
| | | } |
| | | |
| | | std::unordered_map<std::string, std::vector<SVDataItem>> CGlass::getMachineSVData(int machineId) const { |
| | | auto it = m_svDatas.find(machineId); |
| | | if (it != m_svDatas.end()) { |
| | | return it->second; |
| | | } |
| | | return std::unordered_map<std::string, std::vector<SVDataItem>>(); |
| | | } |
| | | |
| | | const std::unordered_map<int, std::unordered_map<std::string, std::vector<SVDataItem>>>& CGlass::getAllSVData() const { |
| | | return m_svDatas; |
| | | } |
| | | |
| | | bool CGlass::hasSVData(int machineId, const std::string& dataType) const { |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | return machineIt->second.find(dataType) != machineIt->second.end(); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | bool CGlass::hasMachineSVData(int machineId) const { |
| | | return m_svDatas.find(machineId) != m_svDatas.end(); |
| | | } |
| | | |
| | | std::vector<int> CGlass::getMachineIdsWithSVData() const { |
| | | std::vector<int> machineIds; |
| | | for (const auto& pair : m_svDatas) { |
| | | machineIds.push_back(pair.first); |
| | | } |
| | | return machineIds; |
| | | } |
| | | |
| | | void CGlass::clearSVData(int machineId, const std::string& dataType) { |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | machineIt->second.erase(dataType); |
| | | // å¦æè¯¥æºå¨æ²¡æå
¶ä»æ°æ®äºï¼ä¹æ¸
餿ºå¨æ¡ç® |
| | | if (machineIt->second.empty()) { |
| | | m_svDatas.erase(machineIt); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void CGlass::clearMachineSVData(int machineId) { |
| | | m_svDatas.erase(machineId); |
| | | } |
| | | |
| | | void CGlass::clearAllSVData() { |
| | | m_svDatas.clear(); |
| | | } |
| | | |
| | | size_t CGlass::getSVDataCount(int machineId, const std::string& dataType) const { |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | auto dataIt = machineIt->second.find(dataType); |
| | | if (dataIt != machineIt->second.end()) { |
| | | return dataIt->second.size(); |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | size_t CGlass::getMachineSVDataCount(int machineId) const { |
| | | size_t total = 0; |
| | | auto machineIt = m_svDatas.find(machineId); |
| | | if (machineIt != m_svDatas.end()) { |
| | | for (const auto& pair : machineIt->second) { |
| | | total += pair.second.size(); |
| | | } |
| | | } |
| | | return total; |
| | | } |
| | | |
| | | size_t CGlass::getTotalSVDataCount() const { |
| | | size_t total = 0; |
| | | for (const auto& machinePair : m_svDatas) { |
| | | for (const auto& dataPair : machinePair.second) { |
| | | total += dataPair.second.size(); |
| | | } |
| | | } |
| | | return total; |
| | | } |
| | | |
| | | std::vector<std::pair<int, SVDataItem>> CGlass::findSVDataByType(const std::string& dataType) const { |
| | | std::vector<std::pair<int, SVDataItem>> result; |
| | | for (const auto& machinePair : m_svDatas) { |
| | | auto dataIt = machinePair.second.find(dataType); |
| | | if (dataIt != machinePair.second.end()) { |
| | | for (const auto& item : dataIt->second) { |
| | | result.emplace_back(machinePair.first, item); |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | namespace SERVO { |
| | | /// æ°æ®é¡¹ï¼æ¶é´æ³ + æ°å¼ |
| | | struct SVDataItem { |
| | | std::chrono::system_clock::time_point timestamp; |
| | | double value; // æè
æ ¹æ®å®é
æ
åµä½¿ç¨å
¶ä»ç±»å |
| | | |
| | | SVDataItem(std::chrono::system_clock::time_point ts, double val) |
| | | : timestamp(ts), value(val) {} |
| | | }; |
| | | |
| | | /// PJ çå½å¨æï¼è´´è¿ E40 常è§ç¶æï¼ |
| | | enum class GlsState : uint8_t { |
| | | NoState = 0, |
| | |
| | | void addParams(std::vector<CParam>& params); |
| | | std::vector<CParam>& getParams(); |
| | | |
| | | // ========== SVæ°æ®ç®¡çæ¥å£ï¼æ°è®¾è®¡ï¼========== |
| | | |
| | | // æ·»å æ°æ®å°æå®æºå¨çæå®æ°æ®ç±»å |
| | | void addSVData(int machineId, const std::string& dataType, const SVDataItem& dataItem); |
| | | void addSVData(int machineId, const std::string& dataType, double value); // èªå¨ä½¿ç¨å½åæ¶é´ |
| | | void addSVData(int machineId, const std::string& dataType, int64_t timestamp, double value); |
| | | |
| | | // æ¹éæ·»å æ°æ®å°æå®æºå¨çæå®æ°æ®ç±»å |
| | | void addSVData(int machineId, const std::string& dataType, const std::vector<SVDataItem>& dataItems); |
| | | |
| | | // è·åæå®æºå¨çæå®æ°æ®ç±»åçæææ°æ® |
| | | std::vector<SVDataItem> getSVData(int machineId, const std::string& dataType) const; |
| | | |
| | | // è·åæå®æºå¨çæææ°æ®ç±»å |
| | | std::vector<std::string> getSVDataTypes(int machineId) const; |
| | | |
| | | // è·åæå®æºå¨çæææ°æ®ï¼ææ°æ®ç±»åç»ç»ï¼ |
| | | std::unordered_map<std::string, std::vector<SVDataItem>> getMachineSVData(int machineId) const; |
| | | |
| | | // è·åæææºå¨çæ°æ® |
| | | const std::unordered_map<int, std::unordered_map<std::string, std::vector<SVDataItem>>>& getAllSVData() const; |
| | | |
| | | // æ£æ¥æå®æºå¨æ¯å¦ææå®ç±»åçæ°æ® |
| | | bool hasSVData(int machineId, const std::string& dataType) const; |
| | | |
| | | // æ£æ¥æå®æºå¨æ¯å¦æä»»ä½æ°æ® |
| | | bool hasMachineSVData(int machineId) const; |
| | | |
| | | // è·åæææSVæ°æ®çæºå¨ID |
| | | std::vector<int> getMachineIdsWithSVData() const; |
| | | |
| | | // æ¸
空æå®æºå¨çæå®æ°æ®ç±»åçæ°æ® |
| | | void clearSVData(int machineId, const std::string& dataType); |
| | | |
| | | // æ¸
空æå®æºå¨çæææ°æ® |
| | | void clearMachineSVData(int machineId); |
| | | |
| | | // æ¸
ç©ºæææºå¨çæææ°æ® |
| | | void clearAllSVData(); |
| | | |
| | | // è·åæå®æºå¨çæå®æ°æ®ç±»åçæ°æ®æ°é |
| | | size_t getSVDataCount(int machineId, const std::string& dataType) const; |
| | | |
| | | // è·åæå®æºå¨çæ»æ°æ®æ°é |
| | | size_t getMachineSVDataCount(int machineId) const; |
| | | |
| | | // è·åæææºå¨çæ»æ°æ®æ°é |
| | | size_t getTotalSVDataCount() const; |
| | | |
| | | // è·åæå®æ°æ®ç±»åå¨æææºå¨ä¸çæ°æ® |
| | | std::vector<std::pair<int, SVDataItem>> findSVDataByType(const std::string& dataType) const; |
| | | |
| | | private: |
| | | MaterialsType m_type; |
| | | std::string m_strID; |
| | |
| | | BOOL m_bScheduledForProcessing; /* æ¯å¦å°å å·¥å¤ç */ |
| | | CProcessJob* m_pProcessJob; |
| | | std::vector<CParam> m_params; // å·¥èºåæ° |
| | | |
| | | // æ°çä¸å±æ°æ®ç»æï¼æºå¨ID -> æ°æ®ç±»å -> æ°æ®å表 |
| | | std::unordered_map<int, std::unordered_map<std::string, std::vector<SVDataItem>>> m_svDatas; |
| | | }; |
| | | } |
| | | |
| | |
| | | index += sizeof(short); |
| | | |
| | | memcpy(&m_nQTime[1], &pszBuffer[index], sizeof(short)); |
| | | index += sizeof(int); |
| | | index += sizeof(short); |
| | | |
| | | memcpy(&m_nQTime[2], &pszBuffer[index], sizeof(int)); |
| | | memcpy(&m_nQTime[2], &pszBuffer[index], sizeof(short)); |
| | | index += sizeof(short); |
| | | |
| | | memcpy(&m_nQTimeOverFlag, &pszBuffer[index], sizeof(short)); |
| | |
| | | |
| | | // ä»é
置读åºçenableï¼åå§åæ¶åç»efem |
| | | static int i_enable[4] = { 0 }; |
| | | if ((++i_enable[m_nIndex]) == 10 + m_nIndex) { |
| | | if ((++i_enable[m_nIndex]) == 20 + m_nIndex) { |
| | | eablePort(m_bEnable, [&](int code) -> int { |
| | | LOGI("<LoadPort-%d>eablePort:code=%d", m_nIndex, code); |
| | | return 0; |
| | |
| | | m_portStatusReport.serialize(ar); |
| | | } |
| | | else { |
| | | int temp; |
| | | ar >> m_nIndex; |
| | | m_portStatusReport.serialize(ar); |
| | | } |
| | |
| | | void CLoadPort::setIndex(unsigned int index) |
| | | { |
| | | m_nIndex = index; |
| | | |
| | | std::string id = "Port" + std::to_string(index + 1); |
| | | m_portStatusReport.setCassetteId(id.c_str()); |
| | | } |
| | | |
| | | unsigned int CLoadPort::getIndex() |
| | |
| | | #include "RecipeManager.h" |
| | | #include <fstream> |
| | | #include "SerializeUtil.h" |
| | | #include "CServoUtilsTool.h" |
| | | |
| | | |
| | | 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) |
| | |
| | | m_bBatch = false; |
| | | m_nContinuousTransferCount = 0; |
| | | m_nContinuousTransferStep = CTStep_Unknow; |
| | | m_nContinuousWorkingPort = 0; |
| | | m_nContinuousWorkingSlot = 0; |
| | | m_pControlJob = nullptr; |
| | | m_nTestFlag = 0; |
| | | InitializeCriticalSection(&m_criticalSection); |
| | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // 读ç¼åæ°æ® |
| | | readCache(); |
| | | loadState(); |
| | | |
| | | |
| | | // 宿¶å¨ |
| | |
| | | // çæ§bitçº¿ç¨ |
| | | m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this, |
| | | 0, &m_nReadBitsThreadAddr); |
| | | |
| | | |
| | | // æ²çº¿æå¡ |
| | | CreateDAQBridgeServer(); |
| | | |
| | | |
| | | LOGI("<Master>åå§å宿."); |
| | |
| | | } |
| | | 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) { |
| | |
| | | } |
| | | |
| | | // Measurement -> LoadPort |
| | | for (int s = 0; s < 4; s++) { |
| | | PortType pt = pLoadPorts[s]->getPortType(); |
| | | for (int p = 0; p < 4; p++) { |
| | | if (p != m_nContinuousWorkingPort) continue; |
| | | PortType pt = pLoadPorts[p]->getPortType(); |
| | | if ((m_nContinuousTransferStep == CTStep_Unknow || m_nContinuousTransferStep == CTStep_BakeCooling_Measurement) |
| | | && !rmd.armState[0] && pLoadPorts[s]->isEnable() |
| | | && !rmd.armState[0] && pLoadPorts[p]->isEnable() |
| | | && (pt == PortType::Unloading || pt == PortType::Both) |
| | | && pLoadPorts[s]->getPortStatus() == PORT_INUSE) { |
| | | && pLoadPorts[p]->getPortStatus() == PORT_INUSE) { |
| | | for (int slot = 0; slot < SLOT_MAX; slot++) { |
| | | if (slot != m_nContinuousWorkingSlot) continue; |
| | | m_pActiveRobotTask = createTransferTask_continuous_transfer(pMeasurement, |
| | | 0, pLoadPorts[s], slot); |
| | | 0, pLoadPorts[p], slot); |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | m_nContinuousTransferStep = CTStep_Measurement_LoadPort; |
| | | m_nContinuousTransferStep = CTStep_end; |
| | |
| | | } |
| | | |
| | | // LoadPort -> Aligner |
| | | for (int s = 0; s < 4; s++) { |
| | | PortType pt = pLoadPorts[s]->getPortType(); |
| | | for (int p = 0; p < 4; p++) { |
| | | PortType pt = pLoadPorts[p]->getPortType(); |
| | | if ((m_nContinuousTransferStep == CTStep_Unknow || m_nContinuousTransferStep == CTStep_end) |
| | | && !rmd.armState[0] && pLoadPorts[s]->isEnable() |
| | | && !rmd.armState[0] && pLoadPorts[p]->isEnable() |
| | | && (pt == PortType::Loading || pt == PortType::Both) |
| | | && pLoadPorts[s]->getPortStatus() == PORT_INUSE) { |
| | | && pLoadPorts[p]->getPortStatus() == PORT_INUSE) { |
| | | for (int slot = 0; slot < SLOT_MAX; slot++) { |
| | | m_pActiveRobotTask = createTransferTask_continuous_transfer(pLoadPorts[s], |
| | | m_pActiveRobotTask = createTransferTask_continuous_transfer(pLoadPorts[p], |
| | | slot, pAligner, 0); |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | m_nContinuousTransferStep = CTStep_LoadPort_Aligner; |
| | | m_nContinuousWorkingPort = p; |
| | | m_nContinuousWorkingSlot = slot; |
| | | LOGI("<ContinuousTransfer>åä¼ æµè¯ï¼å¼å§æ¬éä»»å¡(LoadPort -> Aligner)..."); |
| | | pEFEM->setContext(m_pActiveRobotTask->getContext()); |
| | | goto CT_PORT_GET; |
| | |
| | | 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) { |
| | | // å®ä¹ Bonder çç¹å®æ å° |
| | | std::vector<std::pair<int, int>> bonderMapping = { |
| | | {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, |
| | | {8, 8}, {9, 9}, {10, 10}, {11, 11}, {12, 12}, {13, 13}, {14, 14}, {15, 15}, {16, 16} |
| | | }; |
| | | |
| | | CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(0); |
| | | auto& dataTypes = CServoUtilsTool::getEqDataTypes(); |
| | | auto& bonderTypes = dataTypes[eqid]; |
| | | for (const auto& mapping : bonderMapping) { |
| | | int paramIndex = mapping.first; |
| | | int channel = mapping.second; |
| | | |
| | | if (paramIndex < params.size() && channel - 1 < bonderTypes.size()) { |
| | | if(m_pCollector != nullptr) |
| | | m_pCollector->buffersPush(eqid, channel, ts, params.at(paramIndex).getDoubleValue()); |
| | | if(pGlass != nullptr) |
| | | pGlass->addSVData(eqid, bonderTypes[channel], ts, params.at(paramIndex).getDoubleValue()); |
| | | } |
| | | } |
| | | } |
| | | else if (eqid == EQ_ID_VACUUMBAKE) { |
| | | // å®ä¹ VACUUMBAKE çç¹å®æ å° |
| | | std::vector<std::pair<int, int>> vacuumMapping = { |
| | | {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, |
| | | {10, 8}, {11, 9}, {12, 10}, {13, 11}, {14, 12}, {15, 13}, {16, 14} |
| | | }; |
| | | |
| | | CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(0); |
| | | auto& dataTypes = CServoUtilsTool::getEqDataTypes(); |
| | | auto& vacuumbakeTypes = dataTypes[eqid]; |
| | | for (const auto& mapping : vacuumMapping) { |
| | | int paramIndex = mapping.first; |
| | | int channel = mapping.second; |
| | | |
| | | if (paramIndex < params.size() && channel - 1 < vacuumbakeTypes.size()) { |
| | | if (m_pCollector != nullptr) |
| | | m_pCollector->buffersPush(eqid, channel, ts, params.at(paramIndex).getDoubleValue()); |
| | | if (pGlass != nullptr) |
| | | pGlass->addSVData(eqid, vacuumbakeTypes[channel], ts, params.at(paramIndex).getDoubleValue()); |
| | | } |
| | | } |
| | | } |
| | | else if (eqid == EQ_ID_BAKE_COOLING) { |
| | | // å®ä¹ BAKE_COOLING çç¹å®æ å° |
| | | std::vector<std::pair<int, int>> coolingMapping = { |
| | | {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, |
| | | {11, 7}, {12, 8}, {13, 9}, {14, 10}, {15, 11}, {16, 12} |
| | | }; |
| | | |
| | | CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(0); |
| | | auto& dataTypes = CServoUtilsTool::getEqDataTypes(); |
| | | auto& coolingTypes = dataTypes[eqid]; |
| | | for (const auto& mapping : coolingMapping) { |
| | | int paramIndex = mapping.first; |
| | | int channel = mapping.second; |
| | | |
| | | if (paramIndex < params.size() && channel - 1 < coolingTypes.size()) { |
| | | if (m_pCollector != nullptr) |
| | | m_pCollector->buffersPush(eqid, channel, ts, params.at(paramIndex).getDoubleValue()); |
| | | if (pGlass != nullptr) |
| | | pGlass->addSVData(eqid, coolingTypes[channel], ts, params.at(paramIndex).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; |
| | | } |
| | | |
| | | bool CMaster::canCompleteControlJob() |
| | | { |
| | | return m_pControlJob != nullptr && m_state == SERVO::MASTERSTATE::READY; |
| | | } |
| | | |
| | | bool CMaster::canDeleteControlJob() |
| | | { |
| | | return m_pControlJob != nullptr |
| | | && m_pControlJob->state() == CJState::NoState |
| | | && m_state == SERVO::MASTERSTATE::READY; |
| | | } |
| | | |
| | | int CMaster::getWipGlasses(std::vector<CGlass*>& glasses) |
| | | { |
| | | for (auto eq : m_listEquipment) { |
| | |
| | | |
| | | 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) 为ééè®¾ç½®âæ²çº¿åç§°â |
| | | auto& dataTypes = CServoUtilsTool::getEqDataTypes(); |
| | | auto& bonderTypes = dataTypes[EQ_ID_Bonder1]; |
| | | for (size_t i = 0; i < bonderTypes.size(); ++i) { |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, i + 1, bonderTypes[i].c_str()); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, i + 1, bonderTypes[i].c_str()); |
| | | } |
| | | |
| | | auto& vacuumbakeTypes = dataTypes[EQ_ID_VACUUMBAKE]; |
| | | for (size_t i = 0; i < vacuumbakeTypes.size(); ++i) { |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, i + 1, vacuumbakeTypes[i].c_str()); |
| | | } |
| | | |
| | | auto& coolingTypes = dataTypes[EQ_ID_BAKE_COOLING]; |
| | | for (size_t i = 0; i < coolingTypes.size(); ++i) { |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, i + 1, coolingTypes[i].c_str()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | #pragma once |
| | | #pragma once |
| | | #include <list> |
| | | #include "CEquipment.h" |
| | | #include "CEFEM.h" |
| | |
| | | #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); } |
| | |
| | | CEquipment* pTarEq, int nTarSlot, int armNo = 1); |
| | | |
| | | public: |
| | | // ââ IResourceView è¦å ââï¼æ³¨æ constï¼ |
| | | // ââ IResourceView è¦å ââï¼æ³¨æ constï¼ |
| | | bool isProcessJobsEmpty() const override; |
| | | bool recipeExists(const std::string& ppid) const override; |
| | | bool carrierPresent(const std::string& carrierId) const override; |
| | |
| | | std::string& getLastErrorText(); |
| | | |
| | | public: |
| | | // æ°å¢å½æ° |
| | | // æ°å¢å½æ° |
| | | CProcessJob* acquireNextProcessJob(); |
| | | CGlass* acquireNextGlass(); |
| | | int acquireGlassToQueue(); |
| | |
| | | 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(); |
| | | |
| | | // DAQ Bridgeé©ç¨¿å§ |
| | | Collector* getCollector() const { return m_pCollector; } |
| | | |
| | | private: |
| | | CRITICAL_SECTION m_criticalSection; |
| | |
| | | bool m_bBatch; |
| | | |
| | | private: |
| | | /* çæ§æ¯ç¹ä½ç线ç¨*/ |
| | | /* çæ§æ¯ç¹ä½ç线ç¨*/ |
| | | HANDLE m_hEventReadBitsThreadExit[2]; |
| | | HANDLE m_hReadBitsThreadHandle; |
| | | unsigned m_nReadBitsThreadAddr; |
| | | |
| | | // è°åº¦çº¿ç¨ |
| | | // è°åº¦çº¿ç¨ |
| | | HANDLE m_hDispatchEvent; |
| | | HANDLE m_hEventDispatchThreadExit[2]; |
| | | HANDLE m_hDispatchThreadHandle; |
| | | unsigned m_nDispatchThreadAddr; |
| | | |
| | | // å¯å¨æ¶é´ï¼è¿è¡æ¶é´ï¼ç¶æ |
| | | // å¯å¨æ¶é´ï¼è¿è¡æ¶é´ï¼ç¶æ |
| | | ULONGLONG m_ullStartTime; |
| | | ULONGLONG m_ullRunTime; |
| | | MASTERSTATE m_state; |
| | | |
| | | // å½åä»»å¡å已宿任å¡å表 |
| | | // å½åä»»å¡å已宿任å¡å表 |
| | | CRobotTask* m_pActiveRobotTask; |
| | | std::list< CRobotTask* > m_listTask; |
| | | |
| | | // é误代ç |
| | | // é误代ç |
| | | int m_nLastError; |
| | | std::string m_strLastError; |
| | | |
| | | // å¨å¼å§å·¥èºåæ¯å¦å
éè¦å
æ¯è¾map |
| | | // å¨å¼å§å·¥èºåæ¯å¦å
éè¦å
æ¯è¾map |
| | | BOOL m_isCompareMapsBeforeProceeding; |
| | | BOOL m_bJobMode; |
| | | |
| | | |
| | | // åä¼ åæ°è®¡æ° |
| | | // åä¼ åæ°è®¡æ° |
| | | int m_nContinuousTransferCount; |
| | | int m_nContinuousTransferStep; |
| | | int m_nContinuousWorkingPort; |
| | | int m_nContinuousWorkingSlot; |
| | | |
| | | // æ°å¢å·²ç»å¼å§å¤ççProcessJobå表 |
| | | // æ°å¢å·²ç»å¼å§å¤ççProcessJobå表 |
| | | std::vector<CProcessJob*> m_inProcesJobs; |
| | | std::vector<CProcessJob*> m_completeProcessJobs; |
| | | std::vector<CGlass*> m_queueGlasses; |
| | |
| | | |
| | | int m_nTestFlag; |
| | | std::list<CGlass*> m_bufGlass; |
| | | |
| | | private: |
| | | Collector* m_pCollector = nullptr; |
| | | void CreateDAQBridgeServer(); |
| | | }; |
| | | } |
| | | |
| | |
| | | params.push_back(CParam("æ£æµé度", "", this->getName().c_str(), v * 0.001)); |
| | | i += 4; |
| | | |
| | | return (int)params.size(); |
| | | } |
| | | |
| | | int CMeasurement::parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | | { |
| | | ASSERT(pszData); |
| | | if (size < 250) return 0; |
| | | int i = 0, v; |
| | | |
| | | |
| | | // 1.æ£æµåè½å¯ç¨/ç¦ç¨ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("æ£æµåè½å¯ç¨/ç¦ç¨", "", this->getName().c_str(), v)); |
| | | i += 2; |
| | | |
| | | // 2.æ£æµé度 |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24; |
| | | params.push_back(CParam("æ£æµé度", "", this->getName().c_str(), v * 0.001)); |
| | | i += 4; |
| | | |
| | | // 3.æ£æµ1æ°æ® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24; |
| | | params.push_back(CParam("æ£æµ1æ°æ®", "", this->getName().c_str(), v * 0.001)); |
| | | i += 4; |
| | | |
| | | |
| | | // 4.æ£æµ2æ°æ® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24; |
| | | params.push_back(CParam("æ£æµ2æ°æ®", "", this->getName().c_str(), v * 0.001)); |
| | | i += 4; |
| | | |
| | | return (int)params.size(); |
| | | } |
| | | |
| | | int CMeasurement::parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | | { |
| | | return parsingParams(pszData, size, params); |
| | | } |
| | | |
| | | int CMeasurement::parsingSVData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | |
| | | CHMPropertyPage::OnSize(nType, cx, cy); |
| | | if (GetDlgItem(IDC_LIST1) == nullptr) return; |
| | | |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24); |
| | |
| | | // ====== å¼å
³ï¼1=å¯ç¨åæ°æ®ï¼åªæ¿æ¢ DB æ¥è¯¢ï¼ï¼0=ç¨çå® DB ====== |
| | | #define USE_FAKE_DB_DEMO 0 |
| | | |
| | | // ====== å¼å
³ï¼1=å¯ç¨æ¨¡æä¼ æå¨æ°æ®çæï¼0=使ç¨ç宿°æ® ====== |
| | | #define USE_MOCK_SENSOR_DATA 0 |
| | | |
| | | #if USE_FAKE_DB_DEMO |
| | | #include <ctime> |
| | | #include <atlconv.h> // CStringA |
| | |
| | | return true; |
| | | } |
| | | |
| | | // è¾
å©å½æ°ï¼å° ANSI CString åå
¥æä»¶ä¸º UTF-8 ç¼ç |
| | | bool CPageGlassList::WriteAnsiStringAsUtf8ToFile(const CString& ansiContent, const CString& filePath) |
| | | { |
| | | CFile file; |
| | | if (!file.Open(filePath, CFile::modeCreate | CFile::modeWrite)) { |
| | | return false; |
| | | } |
| | | |
| | | // åå
¥ UTF-8 BOM |
| | | const unsigned char bom[] = { 0xEF, 0xBB, 0xBF }; |
| | | file.Write(bom, 3); |
| | | |
| | | // å° ANSI 转æ¢ä¸º Unicode |
| | | int unicodeLength = MultiByteToWideChar(CP_ACP, 0, |
| | | ansiContent, ansiContent.GetLength(), |
| | | NULL, 0); |
| | | |
| | | if (unicodeLength <= 0) { |
| | | file.Close(); |
| | | return false; |
| | | } |
| | | |
| | | wchar_t* unicodeBuffer = new wchar_t[unicodeLength + 1]; |
| | | MultiByteToWideChar(CP_ACP, 0, |
| | | ansiContent, ansiContent.GetLength(), |
| | | unicodeBuffer, unicodeLength); |
| | | unicodeBuffer[unicodeLength] = 0; |
| | | |
| | | // å° Unicode 转æ¢ä¸º UTF-8 |
| | | int utf8Length = WideCharToMultiByte(CP_UTF8, 0, |
| | | unicodeBuffer, unicodeLength, |
| | | NULL, 0, NULL, NULL); |
| | | |
| | | bool success = false; |
| | | if (utf8Length > 0) { |
| | | char* utf8Buffer = new char[utf8Length]; |
| | | WideCharToMultiByte(CP_UTF8, 0, |
| | | unicodeBuffer, unicodeLength, |
| | | utf8Buffer, utf8Length, NULL, NULL); |
| | | |
| | | file.Write(utf8Buffer, utf8Length); |
| | | delete[] utf8Buffer; |
| | | success = true; |
| | | } |
| | | |
| | | delete[] unicodeBuffer; |
| | | file.Close(); |
| | | return success; |
| | | } |
| | | |
| | | // CPageGlassList å¯¹è¯æ¡ |
| | | |
| | |
| | | ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CPageGlassList::OnBnClickedButtonPrevPage) |
| | | ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CPageGlassList::OnBnClickedButtonNextPage) |
| | | ON_NOTIFY(ELCN_SHOWFULLTEXT, IDC_LIST_ALARM, &CPageGlassList::OnShowFullText) |
| | | ON_BN_CLICKED(IDC_BUTTON_EXPORT_ROW, &CPageGlassList::OnBnClickedButtonExportRow) |
| | | END_MESSAGE_MAP() |
| | | |
| | | // ===== ç§æå°å·¥å
· ===== |
| | |
| | | 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(); |
| | |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::OnBnClickedButtonExportRow() |
| | | { |
| | | int nSelected = m_listCtrl.GetSelectionMark(); |
| | | if (nSelected == -1) { |
| | | AfxMessageBox(_T("请å
éæ©ä¸è¡è®°å½ï¼")); |
| | | return; |
| | | } |
| | | |
| | | // ç´æ¥ä»ç¬¬ä¸åè·å ID |
| | | CString strId = m_listCtrl.GetItemText(nSelected, 1); |
| | | |
| | | if (strId.IsEmpty()) { |
| | | AfxMessageBox(_T("WIPè®°å½æä¸æ¯æä¿å")); |
| | | return; |
| | | } |
| | | |
| | | // æ°æ®åºè®°å½ |
| | | long long recordId = _ttoi64(strId); |
| | | |
| | | // 仿°æ®åºæ¥è¯¢å®æ´è®°å½ |
| | | auto& db = GlassLogDb::Instance(); |
| | | auto row = db.queryById(recordId); |
| | | |
| | | if (!row) { |
| | | AfxMessageBox(_T("æ¥è¯¢è®°å½å¤±è´¥")); |
| | | return; |
| | | } |
| | | |
| | | // ä½¿ç¨ Glass ID æå»ºé»è®¤æä»¶å |
| | | CString strDefaultFileName; |
| | | CString strGlassId = row->classId.c_str(); |
| | | |
| | | // ç§»é¤æä»¶åä¸çéæ³å符 |
| | | CString strSanitizedGlassId = strGlassId; |
| | | strSanitizedGlassId.Remove('\\'); |
| | | strSanitizedGlassId.Remove('/'); |
| | | strSanitizedGlassId.Remove(':'); |
| | | strSanitizedGlassId.Remove('*'); |
| | | strSanitizedGlassId.Remove('?'); |
| | | strSanitizedGlassId.Remove('"'); |
| | | strSanitizedGlassId.Remove('<'); |
| | | strSanitizedGlassId.Remove('>'); |
| | | strSanitizedGlassId.Remove('|'); |
| | | |
| | | strDefaultFileName.Format(_T("Glass_%s.csv"), strSanitizedGlassId); |
| | | |
| | | // æä»¶ä¿åå¯¹è¯æ¡ï¼è®¾ç½®é»è®¤æä»¶å |
| | | CFileDialog fileDialog(FALSE, _T("csv"), strDefaultFileName, |
| | | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, |
| | | _T("CSV Files (*.csv)|*.csv|JSON Files (*.json)|*.json||")); |
| | | |
| | | if (fileDialog.DoModal() != IDOK) return; |
| | | |
| | | CString filePath = fileDialog.GetPathName(); |
| | | CString fileExt = fileDialog.GetFileExt(); |
| | | |
| | | if (fileExt.CompareNoCase(_T("json")) == 0) { |
| | | ExportToJson(*row, filePath); |
| | | } |
| | | else { |
| | | ExportToCsv(*row, filePath); |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::ExportToJson(const GlassLogDb::Row& row, const CString& filePath) |
| | | { |
| | | // ä¿å为 JSON |
| | | if (!row.pretty.empty()) { |
| | | CFile file; |
| | | if (file.Open(filePath, CFile::modeCreate | CFile::modeWrite)) { |
| | | file.Write(row.pretty.c_str(), row.pretty.length()); |
| | | file.Close(); |
| | | |
| | | CString strSuccess; |
| | | strSuccess.Format(_T("è®°å½å·²ä¿å为JSONæä»¶ï¼\n%s"), filePath); |
| | | AfxMessageBox(strSuccess); |
| | | } |
| | | else { |
| | | AfxMessageBox(_T("ä¿åæä»¶å¤±è´¥")); |
| | | } |
| | | } |
| | | else { |
| | | AfxMessageBox(_T("è¯¥è®°å½æ²¡æJSONæ°æ®")); |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::ExportToCsv(const GlassLogDb::Row& row, const CString& filePath) |
| | | { |
| | | CString csvContent; |
| | | |
| | | // === 第ä¸é¨åï¼åºç¡ä¿¡æ¯ === |
| | | ExportBasicInfo(csvContent, row); |
| | | |
| | | // === 第äºé¨åï¼å·¥èºåæ° === |
| | | ExportProcessParams(csvContent, row); |
| | | |
| | | // === 第ä¸é¨åï¼ä¼ æå¨æ°æ®è¯¦æ
=== |
| | | ExportSensorData(csvContent, row); |
| | | |
| | | // 使ç¨è¾
å©å½æ°ä¿å为 UTF-8 ç¼ç |
| | | if (WriteAnsiStringAsUtf8ToFile(csvContent, filePath)) { |
| | | CString strSuccess; |
| | | strSuccess.Format(_T("è®°å½å·²ä¿å为CSVæä»¶ï¼\n%s"), filePath); |
| | | AfxMessageBox(strSuccess); |
| | | } |
| | | else { |
| | | AfxMessageBox(_T("ä¿åæä»¶å¤±è´¥")); |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::ExportBasicInfo(CString& csvContent, const GlassLogDb::Row& row) |
| | | { |
| | | csvContent += _T("=== åºç¡ä¿¡æ¯ ===\n"); |
| | | csvContent += _T("ID,Cassetteåºåå·,Jobåºåå·,Glass ID,ç©æç±»å,ç¶æ,å¼å§æ¶é´,ç»ææ¶é´,ç»å®Glass ID,AOIç»æ,è·¯å¾\n"); |
| | | |
| | | CString baseInfoRow; |
| | | baseInfoRow.Format(_T("%lld,%d,%d,%s,%d,%d,%s,%s,%s,%d,%s\n"), |
| | | row.id, row.cassetteSeqNo, row.jobSeqNo, |
| | | CString(row.classId.c_str()), row.materialType, row.state, |
| | | CString(row.tStart.c_str()), CString(row.tEnd.c_str()), |
| | | CString(row.buddyId.c_str()), row.aoiResult, |
| | | CString(row.path.c_str())); |
| | | csvContent += baseInfoRow; |
| | | } |
| | | |
| | | void CPageGlassList::ExportProcessParams(CString& csvContent, const GlassLogDb::Row& row) |
| | | { |
| | | csvContent += _T("\n=== å·¥èºåæ° ===\n"); |
| | | |
| | | // 妿æ pretty åæ®µï¼è§£æå·¥èºåæ° |
| | | if (!row.pretty.empty()) { |
| | | SERVO::CGlass tempGlass; |
| | | if (GlassJson::FromString(row.pretty, tempGlass)) { |
| | | auto& params = tempGlass.getParams(); |
| | | if (!params.empty()) { |
| | | // å·¥èºåæ°è¡¨å¤´ |
| | | csvContent += _T("åæ°åç§°,åæ°ID,æ°å¼,æºå¨åå
\n"); |
| | | |
| | | // å·¥èºåæ°æ°æ® |
| | | for (auto& param : params) { |
| | | CString paramRow; |
| | | CString valueStr; |
| | | |
| | | // æ ¹æ®åæ°ç±»åæ ¼å¼åæ°å¼ |
| | | if (param.getValueType() == PVT_INT) { |
| | | valueStr.Format(_T("%d"), param.getIntValue()); |
| | | } |
| | | else { |
| | | valueStr.Format(_T("%.3f"), param.getDoubleValue()); |
| | | } |
| | | |
| | | paramRow.Format(_T("%s,%s,%s,%s\n"), |
| | | CString(param.getName().c_str()), |
| | | CString(param.getId().c_str()), |
| | | valueStr, |
| | | CString(param.getUnit().c_str())); |
| | | |
| | | csvContent += paramRow; |
| | | } |
| | | } |
| | | else { |
| | | csvContent += _T("æ å·¥èºåæ°æ°æ®\n"); |
| | | } |
| | | } |
| | | else { |
| | | csvContent += _T("æ æ³è§£æå·¥èºåæ°\n"); |
| | | } |
| | | } |
| | | else { |
| | | csvContent += _T("æ å·¥èºåæ°æ°æ®\n"); |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::ExportSensorData(CString& csvContent, const GlassLogDb::Row& row) |
| | | { |
| | | csvContent += _T("\n=== ä¼ æå¨æ°æ®è¯¦æ
===\n"); |
| | | |
| | | // 妿æ pretty åæ®µï¼è§£æä¼ æå¨æ°æ® |
| | | if (!row.pretty.empty()) { |
| | | SERVO::CGlass tempGlass; |
| | | if (GlassJson::FromString(row.pretty, tempGlass)) { |
| | | #if USE_MOCK_SENSOR_DATA |
| | | // çææ¨¡æçSVDataç¨äºæµè¯ |
| | | GenerateMockSVData(tempGlass); |
| | | #endif |
| | | // 对æ¯ä¸ªæºå¨çæè¡¨æ ¼ |
| | | for (const auto& machinePair : tempGlass.getAllSVData()) { |
| | | int machineId = machinePair.first; |
| | | CString machineName = CString(SERVO::CServoUtilsTool::getEqName(machineId).c_str()); |
| | | |
| | | csvContent += _T("\n[") + machineName + _T("]\n"); |
| | | |
| | | // è·å该æºå¨çé¢å®ä¹åé¡ºåº |
| | | auto columnOrder = getMachineColumnOrder(machineId); |
| | | |
| | | if (columnOrder.empty()) { |
| | | csvContent += _T("æ é¢å®ä¹åé
ç½®\n"); |
| | | continue; |
| | | } |
| | | |
| | | // æå»ºè¡¨å¤´ - ç´æ¥ä½¿ç¨ä¸æåå |
| | | CString header = _T("æ¶é´æ³(ms),æ¬å°æ¶é´"); |
| | | for (const auto& dataType : columnOrder) { |
| | | header += _T(","); |
| | | header += CString(dataType.c_str()); // ç´æ¥ä½¿ç¨ä¸æåå |
| | | } |
| | | header += _T("\n"); |
| | | csvContent += header; |
| | | |
| | | // æ£æ¥æ¯å¦ææ°æ® |
| | | if (machinePair.second.empty()) { |
| | | csvContent += _T("æ ä¼ æå¨æ°æ®\n"); |
| | | continue; |
| | | } |
| | | |
| | | // 使ç¨ç¬¬ä¸ä¸ªæ°æ®ç±»åçæ¶é´åºåä½ä¸ºåºå |
| | | const std::string& firstDataType = columnOrder[0]; |
| | | auto firstDataTypeIt = machinePair.second.find(firstDataType); |
| | | if (firstDataTypeIt == machinePair.second.end() || firstDataTypeIt->second.empty()) { |
| | | csvContent += _T("æ åºåæ°æ®ç±»åæ°æ®\n"); |
| | | continue; |
| | | } |
| | | |
| | | const auto& timeSeries = firstDataTypeIt->second; |
| | | |
| | | // å¯¹äºæ¯ä¸ªæ¶é´ç¹ï¼è¾åºä¸è¡æ°æ® |
| | | for (size_t i = 0; i < timeSeries.size(); i++) { |
| | | auto timestamp = timeSeries[i].timestamp; |
| | | |
| | | // æ¶é´æ³ï¼æ¯«ç§ï¼ |
| | | auto ms = timePointToMs(timestamp); |
| | | CString row; |
| | | row.Format(_T("%lld,"), ms); |
| | | |
| | | // æ¬å°æ¶é´å符串 |
| | | CString localTime = CString(timePointToString(timestamp).c_str()); |
| | | row += localTime; |
| | | |
| | | // æç
§é¢å®ä¹çå顺åºè¾åºæ°æ® |
| | | for (const auto& dataType : columnOrder) { |
| | | row += _T(","); |
| | | |
| | | auto dataTypeIt = machinePair.second.find(dataType); |
| | | if (dataTypeIt != machinePair.second.end() && i < dataTypeIt->second.size()) { |
| | | // ç´æ¥æç´¢å¼è·åæ°æ® |
| | | CString valueStr; |
| | | valueStr.Format(_T("%.3f"), dataTypeIt->second[i].value); |
| | | row += valueStr; |
| | | } |
| | | else { |
| | | // ç论ä¸ä¸åºè¯¥åçï¼å 为æ¨è¯´æ²¡æç©ºå¼ |
| | | row += _T("N/A"); |
| | | } |
| | | } |
| | | row += _T("\n"); |
| | | csvContent += row; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | csvContent += _T("æ æ³è§£æä¼ æå¨æ°æ®\n"); |
| | | } |
| | | } |
| | | else { |
| | | csvContent += _T("æ ä¼ æå¨æ°æ®\n"); |
| | | } |
| | | } |
| | | |
| | | void CPageGlassList::OnBnClickedButtonPrevPage() |
| | | { |
| | | if (m_nCurPage > 1) { |
| | |
| | | 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); } |
| | |
| | | |
| | | return CDialogEx::PreTranslateMessage(pMsg); |
| | | } |
| | | |
| | | // è·åæºå¨é¢å®ä¹çåé¡ºåº |
| | | std::vector<std::string> CPageGlassList::getMachineColumnOrder(int machineId) |
| | | { |
| | | auto dataTypes = SERVO::CServoUtilsTool::getEqDataTypes(); |
| | | auto it = dataTypes.find(machineId); |
| | | return it != dataTypes.end() ? it->second : std::vector<std::string>(); |
| | | } |
| | | |
| | | // æ¶é´æ³è½¬æ¢ä¸ºå符串 |
| | | std::string CPageGlassList::timePointToString(const std::chrono::system_clock::time_point& tp) |
| | | { |
| | | auto time_t = std::chrono::system_clock::to_time_t(tp); |
| | | std::tm tm; |
| | | localtime_s(&tm, &time_t); |
| | | char buffer[20]; |
| | | std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm); |
| | | return buffer; |
| | | } |
| | | |
| | | // æ¶é´æ³è½¬æ¢ä¸ºæ¯«ç§ |
| | | int64_t CPageGlassList::timePointToMs(const std::chrono::system_clock::time_point& tp) |
| | | { |
| | | return std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count(); |
| | | } |
| | | |
| | | // çææ¨¡æçSVDataç¨äºæµè¯ |
| | | void CPageGlassList::GenerateMockSVData(SERVO::CGlass& glass) |
| | | { |
| | | // è·åè®¾å¤æ°æ®ç±»åé
ç½® |
| | | auto& dataTypes = SERVO::CServoUtilsTool::getEqDataTypes(); |
| | | |
| | | // 为æ¯ä¸ªè®¾å¤çææ¨¡ææ°æ® |
| | | for (const auto& machinePair : dataTypes) { |
| | | int machineId = machinePair.first; |
| | | const auto& dataTypeList = machinePair.second; |
| | | |
| | | // çææ¶é´åºåï¼ä»å½åæ¶é´å¾åæ¨10åéï¼æ¯1ç§ä¸ä¸ªæ°æ®ç¹ |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto startTime = now - std::chrono::minutes(10); |
| | | |
| | | // 为æ¯ä¸ªæ°æ®ç±»åçææ¨¡ææ°æ® |
| | | for (const auto& dataType : dataTypeList) { |
| | | std::vector<SERVO::SVDataItem> mockData; |
| | | |
| | | // çæ600ä¸ªæ°æ®ç¹ï¼10åé * 60个ç¹/åéï¼ |
| | | for (int i = 0; i < 600; ++i) { |
| | | auto timestamp = startTime + std::chrono::seconds(i * 1); |
| | | |
| | | // æ ¹æ®è®¾å¤ç±»ååæ°æ®ç±»åçæä¸åçæ¨¡æå¼ |
| | | double value = GenerateMockValue(machineId, dataType, i); |
| | | |
| | | mockData.emplace_back(timestamp, value); |
| | | } |
| | | |
| | | // å°æ¨¡ææ°æ®æ·»å å°glasså¯¹è±¡ä¸ |
| | | glass.addSVData(machineId, dataType, mockData); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æ ¹æ®è®¾å¤ç±»ååæ°æ®ç±»åçææ¨¡ææ°å¼ |
| | | double CPageGlassList::GenerateMockValue(int machineId, const std::string& dataType, int index) |
| | | { |
| | | // åºç¡å¼èå´ |
| | | double baseValue = 0.0; |
| | | double variation = 0.0; |
| | | |
| | | // æ ¹æ®è®¾å¤ç±»å设置åºç¡å¼ |
| | | switch (machineId) { |
| | | case EQ_ID_Bonder1: |
| | | case EQ_ID_Bonder2: |
| | | if (dataType.find("åå") != std::string::npos) { |
| | | baseValue = 50.0; // åååºç¡å¼ |
| | | variation = 10.0; // ååååèå´ |
| | | } else if (dataType.find("温度") != std::string::npos) { |
| | | baseValue = 180.0; // 温度åºç¡å¼ |
| | | variation = 5.0; // 温度ååèå´ |
| | | } else if (dataType.find("æ©å±å¼") != std::string::npos) { |
| | | baseValue = 100.0; // æ©å±å¼åºç¡å¼ |
| | | variation = 15.0; // æ©å±å¼ååèå´ |
| | | } |
| | | break; |
| | | |
| | | case EQ_ID_VACUUMBAKE: |
| | | if (dataType.find("æ©å±å¼") != std::string::npos) { |
| | | baseValue = 80.0; |
| | | variation = 12.0; |
| | | } else if (dataType.find("温度") != std::string::npos) { |
| | | baseValue = 200.0; |
| | | variation = 8.0; |
| | | } |
| | | break; |
| | | |
| | | case EQ_ID_BAKE_COOLING: |
| | | if (dataType.find("温度") != std::string::npos) { |
| | | baseValue = 25.0; // å·å´æ¸©åº¦ |
| | | variation = 3.0; |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | baseValue = 50.0; |
| | | variation = 5.0; |
| | | break; |
| | | } |
| | | |
| | | // æ·»å æ¶é´ç¸å
³çè¶å¿åéæºåå |
| | | double timeTrend = sin(index * 0.1) * 2.0; // æ£å¼¦æ³¢è¶å¿ |
| | | double randomNoise = (rand() % 100 - 50) / 100.0 * variation * 0.3; // éæºåªå£° |
| | | |
| | | return baseValue + timeTrend + randomNoise; |
| | | } |
| | |
| | | #include "CExpandableListCtrl.h" |
| | | #include "GlassLogDb.h" |
| | | |
| | | // ====== ç¼è¯å¼å
³è¯´æ ====== |
| | | // USE_MOCK_SENSOR_DATA: 1=å¯ç¨æ¨¡æä¼ æå¨æ°æ®çæï¼0=使ç¨ç宿°æ® |
| | | // å¨ CPageGlassList.cpp ä¸å®ä¹ |
| | | |
| | | |
| | | // CPageGlassList å¯¹è¯æ¡ |
| | | |
| | |
| | | void UpdateWipData(); |
| | | bool eraseGlassInVector(SERVO::CGlass* pGlass, std::vector<SERVO::CGlass*>& glasses); |
| | | void UpdateWipRow(unsigned int index, SERVO::CGlass* pGlass); |
| | | bool WriteAnsiStringAsUtf8ToFile(const CString& ansiContent, const CString& filePath); |
| | | void ExportToCsv(const GlassLogDb::Row& row, const CString& filePath); |
| | | void ExportToJson(const GlassLogDb::Row& row, const CString& filePath); |
| | | void ExportBasicInfo(CString& csvContent, const GlassLogDb::Row& row); |
| | | void ExportProcessParams(CString& csvContent, const GlassLogDb::Row& row); |
| | | void ExportSensorData(CString& csvContent, const GlassLogDb::Row& row); |
| | | static std::vector<std::string> getMachineColumnOrder(int machineId); |
| | | static std::string timePointToString(const std::chrono::system_clock::time_point& tp); |
| | | static int64_t timePointToMs(const std::chrono::system_clock::time_point& tp); |
| | | void GenerateMockSVData(SERVO::CGlass& glass); |
| | | double GenerateMockValue(int machineId, const std::string& dataType, int index); |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | |
| | | afx_msg void OnShowFullText(NMHDR* pNMHDR, LRESULT* pResult); |
| | | virtual BOOL PreTranslateMessage(MSG* pMsg); |
| | | DECLARE_MESSAGE_MAP() |
| | | public: |
| | | afx_msg void OnBnClickedButtonExportRow(); |
| | | }; |
| | |
| | | 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() |
| | |
| | | CHMPropertyPage::OnSize(nType, cx, cy); |
| | | if (GetDlgItem(IDC_LIST1) == nullptr) return; |
| | | |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24); |
| | |
| | | |
| | | if (GetDlgItem(IDC_LIST1) == nullptr) return; |
| | | |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24); |
| | |
| | | |
| | | 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) |
| | |
| | | |
| | | |
| | | namespace SERVO { |
| | | static std::unordered_map<int, std::vector<std::string>> EQ_DATA_TYPES = { |
| | | {EQ_ID_Bonder1, { |
| | | "æ°ååå", "ä¸è
åå", "管éç空è§å¼", "è
ä½ç空è§å¼", |
| | | "ä¸è
温度1", "ä¸è
温度2", "ä¸è
温度3", "ä¸è
温度4", |
| | | "ä¸è
温度5", "ä¸è
温度6", "ä¸è
温度1", "ä¸è
温度2", |
| | | "ä¸è
温度3", "ä¸è
温度4", "ä¸è
温度5", "ä¸è
温度6" |
| | | }}, |
| | | {EQ_ID_Bonder2, { |
| | | "æ°ååå", "ä¸è
åå", "管éç空è§å¼", "è
ä½ç空è§å¼", |
| | | "ä¸è
温度1", "ä¸è
温度2", "ä¸è
温度3", "ä¸è
温度4", |
| | | "ä¸è
温度5", "ä¸è
温度6", "ä¸è
温度1", "ä¸è
温度2", |
| | | "ä¸è
温度3", "ä¸è
温度4", "ä¸è
温度5", "ä¸è
温度6" |
| | | }}, |
| | | {EQ_ID_VACUUMBAKE, { |
| | | "Aè
ç空è§å¼", "Aè
温æ§1", "Aè
温æ§2", "Aè
温æ§4", |
| | | "Aè
温æ§5", "Aè
温æ§6", "Aè
温æ§7", "Bè
ç空è§å¼", |
| | | "Bè
温æ§1", "Bè
温æ§2", "Bè
温æ§4", "Bè
温æ§5", |
| | | "Bè
温æ§6", "Bè
温æ§7" |
| | | }}, |
| | | {EQ_ID_BAKE_COOLING, { |
| | | "Açç¤æ¸©æ§1", "Açç¤æ¸©æ§2", "Açç¤æ¸©æ§4", "Açç¤æ¸©æ§5", |
| | | "Açç¤æ¸©æ§6", "Açç¤æ¸©æ§7", "Bçç¤æ¸©æ§1", "Bçç¤æ¸©æ§2", |
| | | "Bçç¤æ¸©æ§4", "Bçç¤æ¸©æ§5", "Bçç¤æ¸©æ§6", "Bçç¤æ¸©æ§7" |
| | | }} |
| | | }; |
| | | |
| | | CServoUtilsTool::CServoUtilsTool() |
| | | { |
| | | |
| | |
| | | CServoUtilsTool::~CServoUtilsTool() |
| | | { |
| | | |
| | | } |
| | | |
| | | std::string CServoUtilsTool::getEqName(int eqid) |
| | | { |
| | | switch (eqid) |
| | | { |
| | | case EQ_ID_LOADPORT1: |
| | | return "Port1"; |
| | | case EQ_ID_LOADPORT2: |
| | | return "Port2"; |
| | | case EQ_ID_LOADPORT3: |
| | | return "Port3"; |
| | | case EQ_ID_LOADPORT4: |
| | | return "Port4"; |
| | | case EQ_ID_ALIGNER: |
| | | return "Aligner"; |
| | | case EQ_ID_FLIPER: |
| | | return "Fliper"; |
| | | case EQ_ID_VACUUMBAKE: |
| | | return "VacuumBake"; |
| | | case EQ_ID_Bonder1: |
| | | return "Bonder1"; |
| | | case EQ_ID_Bonder2: |
| | | return "Bonder2"; |
| | | case EQ_ID_BAKE_COOLING: |
| | | return "BakeCooling"; |
| | | case EQ_ID_MEASUREMENT: |
| | | return "AOI"; |
| | | case EQ_ID_ARM_TRAY1: |
| | | return "ArmTray1"; |
| | | case EQ_ID_ARM_TRAY2: |
| | | return "ArmTray2"; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | return ""; |
| | | } |
| | | |
| | | std::string CServoUtilsTool::getEqUnitName(int eqid, int unit) |
| | |
| | | if (unit == 1) return "çç¤Bè
"; |
| | | } |
| | | |
| | | if (eqid == EQ_ID_VACUUMBAKE) { |
| | | if (unit == 0) return "çç¤Aè
"; |
| | | if (unit == 1) return "çç¤Bè
"; |
| | | } |
| | | |
| | | if (eqid == EQ_ID_Bonder1) { |
| | | return "Bonder1"; |
| | | } |
| | |
| | | |
| | | if (unit == 0) return "åçç¤Aè
"; |
| | | if (unit == 1) return "å·å´A"; |
| | | if (unit == 0) return "åçç¤Bè
"; |
| | | if (unit == 1) return "å·å´B"; |
| | | if (unit == 2) return "åçç¤Bè
"; |
| | | if (unit == 3) return "å·å´B"; |
| | | } |
| | | |
| | | if (eqid == EQ_ID_MEASUREMENT) { |
| | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | std::unordered_map<int, std::vector<std::string>>& CServoUtilsTool::getEqDataTypes() |
| | | { |
| | | return EQ_DATA_TYPES; |
| | | } |
| | | } |
| | |
| | | virtual ~CServoUtilsTool(); |
| | | |
| | | public: |
| | | static std::string getEqName(int eqid); |
| | | static std::string getEqUnitName(int eqid, int unit); |
| | | static std::string getEqUnitName(int eqid, int unit, int slot); |
| | | static std::string getMaterialsTypeText(MaterialsType type); |
| | | static std::string getGlassStateText(SERVO::GlsState state); |
| | | static std::string getInspResultText(SERVO::InspResult result); |
| | | static std::unordered_map<int, std::vector<std::string>>& getEqDataTypes(); |
| | | }; |
| | | } |
| | | |
| | |
| | | |
| | | int CVacuumBake::parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& params) |
| | | { |
| | | return parsingParams(pszData, size, params); |
| | | ASSERT(pszData); |
| | | if (size < 250) return 0; |
| | | int i = 0, v; |
| | | |
| | | |
| | | // 1.å·¥èºåæ°åºå· |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("å·¥èºåæ°åºå·", "", this->getName().c_str(), v)); |
| | | i += 2; |
| | | |
| | | if (v == 1) { |
| | | // 2.A_è
å çæ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("A_è
å çæ¶é´", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 2; |
| | | |
| | | // 3.A_è
ç ´ç空æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("A_è
ç ´ç空æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | |
| | | // 4.A_è
ç空å°è¾¾å¼ |
| | | params.push_back(CParam("A_è
ç空å°è¾¾å¼", "", this->getName().c_str(), (double)toFloat(&pszData[i]))); |
| | | i += 4; |
| | | |
| | | // 5.A_è
温æ§è¡¨ä¸»æ§æ¸©åº¦è®¾å® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24; |
| | | params.push_back(CParam("A_è
温æ§è¡¨ä¸»æ§æ¸©åº¦è®¾å®", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 4; |
| | | } |
| | | else if (v == 1) { |
| | | // 2.B_è
å çæ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("B_è
å çæ¶é´", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 2; |
| | | |
| | | // 3.A_è
ç ´ç空æ¶é´ |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8; |
| | | params.push_back(CParam("B_è
ç ´ç空æ¶é´", "", this->getName().c_str(), v * 0.01f)); |
| | | i += 2; |
| | | |
| | | // 4.A_è
ç空å°è¾¾å¼ |
| | | params.push_back(CParam("B_è
ç空å°è¾¾å¼", "", this->getName().c_str(), (double)toFloat(&pszData[i]))); |
| | | i += 4; |
| | | |
| | | // 5.A_è
温æ§è¡¨ä¸»æ§æ¸©åº¦è®¾å® |
| | | v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24; |
| | | params.push_back(CParam("B_è
温æ§è¡¨ä¸»æ§æ¸©åº¦è®¾å®", "", this->getName().c_str(), v * 0.1f)); |
| | | i += 4; |
| | | } |
| | | |
| | | return (int)params.size(); |
| | | } |
| | | |
| | | int CVacuumBake::parsingSVData(const char* pszData, size_t size, std::vector<CParam>& params) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #include "ClientListDlg.h" |
| | | #include "afxdialogex.h" |
| | | #include "../DAQBridge/core/Collector.h" |
| | | #include "CMaster.h" |
| | | #include "Model.h" |
| | | #include "Servo.h" |
| | | #include <chrono> |
| | | #include <iomanip> |
| | | #include <sstream> |
| | | |
| | | // CClientListDlg å¯¹è¯æ¡ |
| | | |
| | | IMPLEMENT_DYNAMIC(CClientListDlg, CDialogEx) |
| | | |
| | | CClientListDlg::CClientListDlg(CWnd* pParent /*=nullptr*/) |
| | | : CDialogEx(IDD_DIALOG_CLIENT_LIST, pParent) |
| | | { |
| | | } |
| | | |
| | | CClientListDlg::~CClientListDlg() |
| | | { |
| | | } |
| | | |
| | | void CClientListDlg::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CDialogEx::DoDataExchange(pDX); |
| | | DDX_Control(pDX, IDC_LIST_CLIENTS, m_listClients); |
| | | } |
| | | |
| | | BEGIN_MESSAGE_MAP(CClientListDlg, CDialogEx) |
| | | ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CClientListDlg::OnBnClickedRefresh) |
| | | ON_WM_SYSCOMMAND() |
| | | END_MESSAGE_MAP() |
| | | |
| | | // CClientListDlg æ¶æ¯å¤çç¨åº |
| | | |
| | | BOOL CClientListDlg::OnInitDialog() |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | |
| | | // åå§åå表æ§ä»¶ |
| | | m_listClients.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP); |
| | | |
| | | // æ·»å å |
| | | m_listClients.InsertColumn(0, _T("IPå°å"), LVCFMT_LEFT, 120); |
| | | m_listClients.InsertColumn(1, _T("端å£"), LVCFMT_CENTER, 80); |
| | | m_listClients.InsertColumn(2, _T("çæ¬ç¶æ"), LVCFMT_CENTER, 100); |
| | | m_listClients.InsertColumn(3, _T("è¿æ¥ç¶æ"), LVCFMT_CENTER, 100); |
| | | m_listClients.InsertColumn(4, _T("è¿æ¥æ¶é´"), LVCFMT_LEFT, 150); |
| | | |
| | | // å·æ°å®¢æ·ç«¯å表 |
| | | RefreshClientList(); |
| | | |
| | | return TRUE; // é¤éå°ç¦ç¹è®¾ç½®å°æ§ä»¶ï¼å¦åè¿å TRUE |
| | | } |
| | | |
| | | void CClientListDlg::OnBnClickedRefresh() |
| | | { |
| | | RefreshClientList(); |
| | | } |
| | | |
| | | void CClientListDlg::OnSysCommand(UINT nID, LPARAM lParam) |
| | | { |
| | | if (nID == SC_CLOSE) |
| | | { |
| | | CDialogEx::OnCancel(); |
| | | return; |
| | | } |
| | | CDialogEx::OnSysCommand(nID, lParam); |
| | | } |
| | | |
| | | void CClientListDlg::RefreshClientList() |
| | | { |
| | | // æ¸
空å½åå表 |
| | | m_listClients.DeleteAllItems(); |
| | | m_clients.clear(); |
| | | |
| | | // è·åCollectorå®ä¾ |
| | | extern CServoApp theApp; |
| | | SERVO::CMaster& master = theApp.m_model.getMaster(); |
| | | Collector* pCollector = master.getCollector(); |
| | | |
| | | if (pCollector) |
| | | { |
| | | // è·åçå®ç客æ·ç«¯å表 |
| | | auto clientSummaries = pCollector->getClientList(); |
| | | |
| | | // è½¬æ¢æ°æ®æ ¼å¼ |
| | | for (const auto& summary : clientSummaries) |
| | | { |
| | | ClientInfo client; |
| | | client.ip = summary.ip; |
| | | client.port = summary.port; |
| | | client.versionOk = summary.versionOk; |
| | | client.status = summary.versionOk ? "å·²è¿æ¥" : "çæ¬ä¸å¹é
"; |
| | | |
| | | // è·åå½åæ¶é´ä½ä¸ºè¿æ¥æ¶é´ï¼å®é
å®ç°ä¸åºè¯¥ä»Collectorè·åçå®è¿æ¥æ¶é´ï¼ |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto time_t = std::chrono::system_clock::to_time_t(now); |
| | | std::tm tm; |
| | | localtime_s(&tm, &time_t); |
| | | |
| | | std::ostringstream oss; |
| | | oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); |
| | | client.connectTime = oss.str(); |
| | | |
| | | m_clients.push_back(client); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // å¦ææ æ³è·åCollectorå®ä¾ï¼æ¾ç¤ºæç¤ºä¿¡æ¯ |
| | | ClientInfo noData; |
| | | noData.ip = "æ æ³è·åæ°æ®"; |
| | | noData.port = 0; |
| | | noData.versionOk = false; |
| | | noData.status = "Collectoræªåå§å"; |
| | | noData.connectTime = ""; |
| | | m_clients.push_back(noData); |
| | | } |
| | | |
| | | // æ´æ°å表æ¾ç¤º |
| | | UpdateClientList(m_clients); |
| | | } |
| | | |
| | | void CClientListDlg::UpdateClientList(const std::vector<ClientInfo>& clients) |
| | | { |
| | | m_listClients.DeleteAllItems(); |
| | | |
| | | for (size_t i = 0; i < clients.size(); ++i) |
| | | { |
| | | const ClientInfo& client = clients[i]; |
| | | |
| | | int nItem = m_listClients.InsertItem(i, CString(client.ip.c_str())); |
| | | m_listClients.SetItemText(nItem, 1, CString(std::to_string(client.port).c_str())); |
| | | m_listClients.SetItemText(nItem, 2, client.versionOk ? _T("æ£å¸¸") : _T("å¼å¸¸")); |
| | | m_listClients.SetItemText(nItem, 3, CString(client.status.c_str())); |
| | | m_listClients.SetItemText(nItem, 4, CString(client.connectTime.c_str())); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include "afxwin.h" |
| | | #include <vector> |
| | | #include <string> |
| | | |
| | | // 客æ·ç«¯ä¿¡æ¯ç»æ |
| | | struct ClientInfo { |
| | | std::string ip; |
| | | uint16_t port; |
| | | bool versionOk; |
| | | std::string status; |
| | | std::string connectTime; |
| | | }; |
| | | |
| | | // CClientListDlg å¯¹è¯æ¡ |
| | | |
| | | class CClientListDlg : public CDialogEx |
| | | { |
| | | DECLARE_DYNAMIC(CClientListDlg) |
| | | |
| | | public: |
| | | CClientListDlg(CWnd* pParent = nullptr); // æ åæé 彿° |
| | | virtual ~CClientListDlg(); |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_DIALOG_CLIENT_LIST }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | |
| | | public: |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnBnClickedRefresh(); |
| | | afx_msg void OnSysCommand(UINT nID, LPARAM lParam); |
| | | |
| | | private: |
| | | void RefreshClientList(); |
| | | void UpdateClientList(const std::vector<ClientInfo>& clients); |
| | | |
| | | private: |
| | | CListCtrl m_listClients; |
| | | std::vector<ClientInfo> m_clients; |
| | | }; |
| | |
| | | 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(); |
| | |
| | | root["path"] = std::move(arr); |
| | | } |
| | | |
| | | root["payload_version"] = 1; |
| | | // SVæ°æ®ï¼ä¸å±ç»æåºåå |
| | | { |
| | | Json::Value svDataObj(Json::objectValue); |
| | | const auto& allSVData = g.getAllSVData(); |
| | | |
| | | for (const auto& machinePair : allSVData) { |
| | | int machineId = machinePair.first; |
| | | const auto& dataTypes = machinePair.second; |
| | | |
| | | Json::Value machineObj(Json::objectValue); |
| | | for (const auto& dataTypePair : dataTypes) { |
| | | const std::string& dataType = dataTypePair.first; |
| | | const auto& dataItems = dataTypePair.second; |
| | | |
| | | Json::Value dataArray(Json::arrayValue); |
| | | for (const auto& item : dataItems) { |
| | | Json::Value itemObj(Json::objectValue); |
| | | // æ¶é´æ³è½¬æ¢ä¸ºæ¯«ç§å符串 |
| | | auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( |
| | | item.timestamp.time_since_epoch()).count(); |
| | | itemObj["t"] = std::to_string(ms); |
| | | itemObj["v"] = item.value; |
| | | dataArray.append(itemObj); |
| | | } |
| | | machineObj[dataType] = dataArray; |
| | | } |
| | | svDataObj[std::to_string(machineId)] = machineObj; |
| | | } |
| | | root["sv_datas"] = svDataObj; |
| | | } |
| | | |
| | | root["payload_version"] = 2; // çæ¬å级ï¼å 为æ°å¢äºsv_datasåæ®µ |
| | | return root; |
| | | } |
| | | |
| | |
| | | if (JBool(n, "processed", false)) tail->processEnd(); |
| | | } |
| | | } |
| | | |
| | | // SVæ°æ®ï¼ååºååä¸å±ç»æ |
| | | if (root.isMember("sv_datas") && root["sv_datas"].isObject()) { |
| | | g.clearAllSVData(); // æ¸
ç©ºç°ææ°æ® |
| | | |
| | | const auto& svDataObj = root["sv_datas"]; |
| | | auto memberNames = svDataObj.getMemberNames(); |
| | | |
| | | for (const auto& machineIdStr : memberNames) { |
| | | int machineId = std::stoi(machineIdStr); |
| | | const auto& machineObj = svDataObj[machineIdStr]; |
| | | |
| | | auto dataTypeNames = machineObj.getMemberNames(); |
| | | for (const auto& dataType : dataTypeNames) { |
| | | const auto& dataArray = machineObj[dataType]; |
| | | if (dataArray.isArray()) { |
| | | for (const auto& itemObj : dataArray) { |
| | | long long timestampMs = 0; |
| | | double value = 0.0; |
| | | |
| | | if (get_ll_from_json(itemObj, "t", timestampMs)) { |
| | | value = JDouble(itemObj, "v", 0.0); |
| | | // æ·»å SVæ°æ® |
| | | g.addSVData(machineId, dataType, timestampMs, value); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ==================== 便æ·å°è£
==================== |
| | |
| | | } |
| | | FromJson(j, g); |
| | | return true; |
| | | } |
| | | } |
| | |
| | | ofs.flush(); |
| | | return rows; |
| | | } |
| | | |
| | | std::optional<GlassLogDb::Row> GlassLogDb::queryById(long long id) { |
| | | std::lock_guard<std::mutex> lk(mtx_); |
| | | |
| | | const char* sql = |
| | | "SELECT id, cassette_seq_no, job_seq_no, class_id, material_type, state," |
| | | " IFNULL(strftime('%Y-%m-%d %H:%M:%S', t_start, 'localtime'), '')," |
| | | " IFNULL(strftime('%Y-%m-%d %H:%M:%S', t_end, 'localtime'), '')," |
| | | " buddy_id, aoi_result, path, params, pretty" |
| | | " FROM " GLASS_LOG_TABLE |
| | | " WHERE id = ?"; |
| | | |
| | | sqlite3_stmt* stmt = nullptr; |
| | | try { |
| | | throwIf(sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr), db_, "prepare queryById"); |
| | | throwIf(sqlite3_bind_int64(stmt, 1, id), db_, "bind id"); |
| | | |
| | | std::optional<Row> result; |
| | | |
| | | int rc = sqlite3_step(stmt); |
| | | if (rc == SQLITE_ROW) { |
| | | Row row; |
| | | row.id = sqlite3_column_int64(stmt, 0); |
| | | row.cassetteSeqNo = sqlite3_column_int(stmt, 1); |
| | | row.jobSeqNo = sqlite3_column_int(stmt, 2); |
| | | row.classId = safe_text(stmt, 3); |
| | | row.materialType = sqlite3_column_int(stmt, 4); |
| | | row.state = sqlite3_column_int(stmt, 5); |
| | | row.tStart = safe_text(stmt, 6); |
| | | row.tEnd = safe_text(stmt, 7); |
| | | row.buddyId = safe_text(stmt, 8); |
| | | row.aoiResult = sqlite3_column_int(stmt, 9); |
| | | row.path = safe_text(stmt, 10); |
| | | row.params = safe_text(stmt, 11); |
| | | row.pretty = safe_text(stmt, 12); |
| | | |
| | | result = std::move(row); |
| | | } |
| | | else if (rc != SQLITE_DONE) { |
| | | throwIf(rc, db_, "queryById step"); |
| | | } |
| | | |
| | | sqlite3_finalize(stmt); |
| | | return result; |
| | | } |
| | | catch (const std::exception& e) { |
| | | if (stmt) sqlite3_finalize(stmt); |
| | | TRACE("GlassLogDb::queryById exception: %s\n", e.what()); |
| | | return std::nullopt; |
| | | } |
| | | } |
| | | |
| | |
| | | int limit = 50, |
| | | int offset = 0); |
| | | |
| | | // æ ID æ¥è¯¢åæ¡è®°å½ï¼å
å« pretty åæ®µï¼ |
| | | std::optional<Row> queryById(long long id); |
| | | |
| | | // ç»è®¡ä¸ filters ç¸åæ¡ä»¶çæ»æ° |
| | | long long count(const Filters& filters = {}); |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #include "GroupLabel.h" |
| | | |
| | | |
| | | CGroupLabel::CGroupLabel() |
| | | { |
| | | m_crBkgnd = RGB(255, 255, 255); |
| | | m_crLine = RGB(188, 188, 188); |
| | | m_crText = RGB(88, 88, 88); |
| | | m_nPadding[PADDING_LEFT] = 5; |
| | | m_nPadding[PADDING_TOP] = 5; |
| | | m_nPadding[PADDING_RIGHT] = 5; |
| | | m_nPadding[PADDING_BOTTOM] = 5; |
| | | m_nTextAlign = TEXT_ALIGN_CENTER; |
| | | m_bEnableResize = FALSE; |
| | | } |
| | | |
| | | |
| | | CGroupLabel::~CGroupLabel() |
| | | { |
| | | } |
| | | BEGIN_MESSAGE_MAP(CGroupLabel, CStatic) |
| | | ON_WM_PAINT() |
| | | ON_WM_LBUTTONDOWN() |
| | | ON_WM_SETCURSOR() |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | void CGroupLabel::EnableResize() |
| | | { |
| | | m_bEnableResize = TRUE; |
| | | |
| | | DWORD dwStyle = GetStyle(); |
| | | dwStyle |= SS_NOTIFY; |
| | | SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle); |
| | | } |
| | | |
| | | void CGroupLabel::DisableResize() |
| | | { |
| | | m_bEnableResize = FALSE; |
| | | } |
| | | |
| | | void CGroupLabel::OnPaint() |
| | | { |
| | | CPaintDC dc(this); // device context for painting |
| | | // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç |
| | | // ä¸ä¸ºç»å¾æ¶æ¯è°ç¨ CStatic::OnPaint() |
| | | |
| | | |
| | | HDC hMemDC; |
| | | HBITMAP hBitmap; |
| | | RECT rcClient; |
| | | CString strText; |
| | | HFONT hFont; |
| | | HBRUSH hBrushBK; |
| | | |
| | | |
| | | ::GetClientRect(m_hWnd, &rcClient); |
| | | hMemDC = ::CreateCompatibleDC(dc.m_hDC); |
| | | hBitmap = ::CreateCompatibleBitmap(dc.m_hDC, rcClient.right - rcClient.left, |
| | | rcClient.bottom - rcClient.top); |
| | | ::SelectObject(hMemDC, hBitmap); |
| | | ::SetBkMode(hMemDC, TRANSPARENT); |
| | | |
| | | |
| | | // èæ¯é¢è² |
| | | hBrushBK = CreateSolidBrush(m_crBkgnd); |
| | | ::FillRect(hMemDC, &rcClient, hBrushBK); |
| | | DeleteObject(hBrushBK); |
| | | |
| | | |
| | | // çªå£æ é¢ |
| | | int x1, x2, x3, x4; |
| | | x1 = rcClient.left + m_nPadding[PADDING_LEFT]; |
| | | x4 = rcClient.right - m_nPadding[PADDING_RIGHT]; |
| | | hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); |
| | | ::SelectObject(hMemDC, hFont); |
| | | ::SetTextColor(hMemDC, m_crText); |
| | | char szTitle[256]; |
| | | int nTextLen = ::GetWindowText(m_hWnd, szTitle, 256); |
| | | if (nTextLen > 0) { |
| | | RECT rcTitle; |
| | | SIZE sizeText; |
| | | |
| | | rcTitle.left = x1; |
| | | rcTitle.top = rcClient.top + 2; |
| | | rcTitle.bottom = rcClient.bottom - 2; |
| | | rcTitle.right = x4; |
| | | |
| | | #define TEXT_SPAGE 12 |
| | | GetTextExtentPoint32(hMemDC, szTitle, nTextLen, &sizeText); |
| | | if (TEXT_ALIGN_LEFT == m_nTextAlign) { |
| | | ::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_LEFT | DT_VCENTER | DT_SINGLELINE); |
| | | x1 += sizeText.cx + TEXT_SPAGE; |
| | | } |
| | | else if (TEXT_ALIGN_CENTER == m_nTextAlign) { |
| | | ::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_CENTER | DT_VCENTER | DT_SINGLELINE); |
| | | x2 = x1 + (x4 - x1 - sizeText.cx - TEXT_SPAGE * 2) / 2; |
| | | x3 = x2 + sizeText.cx + TEXT_SPAGE * 2; |
| | | } |
| | | else { |
| | | ::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); |
| | | x4 -= (sizeText.cx + TEXT_SPAGE); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | // åé线 |
| | | HPEN hPen = CreatePen(PS_SOLID, 1, m_crLine); |
| | | HPEN hOldPen = (HPEN)SelectObject(hMemDC, hPen); |
| | | int y = (rcClient.bottom - rcClient.top) / 2; |
| | | |
| | | if (TEXT_ALIGN_LEFT == m_nTextAlign) { |
| | | ::MoveToEx(hMemDC, x1, y, NULL); |
| | | ::LineTo(hMemDC, x4, y); |
| | | } |
| | | else if (TEXT_ALIGN_CENTER == m_nTextAlign) { |
| | | ::MoveToEx(hMemDC, x1, y, NULL); |
| | | ::LineTo(hMemDC, x2, y); |
| | | ::MoveToEx(hMemDC, x3, y, NULL); |
| | | ::LineTo(hMemDC, x4, y); |
| | | } |
| | | else { |
| | | ::MoveToEx(hMemDC, x1, y, NULL); |
| | | ::LineTo(hMemDC, x4, y); |
| | | } |
| | | |
| | | SelectObject(hMemDC, hOldPen); |
| | | ::DeleteObject(hPen); |
| | | |
| | | |
| | | // EndPaint |
| | | ::BitBlt(dc.m_hDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, |
| | | hMemDC, 0, 0, SRCCOPY); |
| | | ::DeleteObject(hBitmap); |
| | | ::DeleteDC(hMemDC); |
| | | } |
| | | |
| | | void CGroupLabel::SetTextAlignMode(int nAlign) |
| | | { |
| | | if (nAlign == TEXT_ALIGN_LEFT || nAlign == TEXT_ALIGN_CENTER || nAlign == TEXT_ALIGN_RIGHT) { |
| | | m_nTextAlign = nAlign; |
| | | |
| | | RECT rcClient; |
| | | ::GetClientRect(m_hWnd, &rcClient); |
| | | ::InvalidateRect(m_hWnd, &rcClient, TRUE); |
| | | } |
| | | } |
| | | |
| | | void CGroupLabel::Setpadding(int type, unsigned int nPadding) |
| | | { |
| | | if (type >= PADDING_LEFT && PADDING_LEFT <= PADDING_BOTTOM) { |
| | | m_nPadding[type] = nPadding; |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * è®¾ç½®èæ¯è² |
| | | * color -- èæ¯è² |
| | | */ |
| | | void CGroupLabel::SetBkgndColor(COLORREF color) |
| | | { |
| | | m_crBkgnd = color; |
| | | } |
| | | |
| | | /* |
| | | * è®¾ç½®ææ¬è² |
| | | * color -- èæ¯è² |
| | | */ |
| | | void CGroupLabel::SetTextColor(COLORREF color) |
| | | { |
| | | m_crText = color; |
| | | |
| | | RECT rcClient; |
| | | ::GetClientRect(m_hWnd, &rcClient); |
| | | ::InvalidateRect(m_hWnd, &rcClient, TRUE); |
| | | } |
| | | |
| | | /* |
| | | * è®¾ç½®çº¿è² |
| | | * color -- èæ¯è² |
| | | */ |
| | | void CGroupLabel::SetLineColor(COLORREF color) |
| | | { |
| | | m_crLine = color; |
| | | |
| | | RECT rcClient; |
| | | ::GetClientRect(m_hWnd, &rcClient); |
| | | ::InvalidateRect(m_hWnd, &rcClient, TRUE); |
| | | } |
| | | |
| | | void CGroupLabel::OnLButtonDown(UINT nFlags, CPoint point) |
| | | { |
| | | if (!m_bEnableResize) { |
| | | CStatic::OnLButtonDown(nFlags, point); |
| | | return; |
| | | } |
| | | |
| | | CPoint pt, ptNew; |
| | | pt = point; |
| | | int nMoveY = 0; |
| | | |
| | | // ææé¼ æ æ¶æ¯ï¼æ£æµæ¯å¦æå¨ |
| | | CRect rcParent, rcWindows; |
| | | GetClientRect(&rcWindows); |
| | | ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows); |
| | | ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows.right); |
| | | GetParent()->GetClientRect(&rcParent); |
| | | ::ClientToScreen(GetParent()->m_hWnd, (LPPOINT)&rcParent); |
| | | HDC hDC = ::GetDC(::GetDesktopWindow()); |
| | | ::DrawFocusRect(hDC, &rcWindows); |
| | | |
| | | if (::GetCapture() == NULL) { |
| | | SetCapture(); |
| | | ASSERT(this == GetCapture()); |
| | | AfxLockTempMaps(); |
| | | for (;;) { |
| | | MSG msg; |
| | | VERIFY(::GetMessage(&msg, NULL, 0, 0)); |
| | | |
| | | if (GetCapture() != this) break; |
| | | |
| | | switch (msg.message) |
| | | { |
| | | case WM_MOUSEMOVE: |
| | | ptNew = msg.pt; |
| | | if (ptNew.y < rcParent.top) ptNew.y = rcParent.top; |
| | | ::DrawFocusRect(hDC, &rcWindows); |
| | | rcWindows.top = ptNew.y - 3; |
| | | rcWindows.bottom = ptNew.y + 3; |
| | | ::DrawFocusRect(hDC, &rcWindows); |
| | | ::ScreenToClient(m_hWnd, &ptNew); |
| | | break; |
| | | |
| | | case WM_LBUTTONUP: |
| | | ptNew = msg.pt; |
| | | ::ScreenToClient(m_hWnd, &ptNew); |
| | | nMoveY = ptNew.y - pt.y; |
| | | goto ExitLoop; |
| | | |
| | | case WM_KEYDOWN: |
| | | if (msg.wParam == VK_ESCAPE) { |
| | | goto ExitLoop; |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | DispatchMessage(&msg); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | ExitLoop: |
| | | ::DrawFocusRect(hDC, &rcWindows); |
| | | ::ReleaseDC(::GetDesktopWindow(), hDC); |
| | | ReleaseCapture(); |
| | | ::InvalidateRect(m_hWnd, NULL, TRUE); |
| | | GetParent()->SendMessage(ID_MSG_RESIZEY, nMoveY, 0); |
| | | AfxUnlockTempMaps(FALSE); |
| | | } |
| | | |
| | | CStatic::OnLButtonDown(nFlags, point); |
| | | } |
| | | |
| | | BOOL CGroupLabel::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) |
| | | { |
| | | if (m_bEnableResize) { |
| | | ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); |
| | | return TRUE; |
| | | } |
| | | |
| | | return CStatic::OnSetCursor(pWnd, nHitTest, message); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | |
| | | #define PADDING_LEFT 0 |
| | | #define PADDING_TOP 1 |
| | | #define PADDING_RIGHT 2 |
| | | #define PADDING_BOTTOM 3 |
| | | |
| | | #define TEXT_ALIGN_LEFT 0 |
| | | #define TEXT_ALIGN_CENTER 1 |
| | | #define TEXT_ALIGN_RIGHT 3 |
| | | |
| | | #define ID_MSG_RESIZEY WM_USER+123 |
| | | |
| | | class CGroupLabel : public CStatic |
| | | { |
| | | public: |
| | | CGroupLabel(); |
| | | ~CGroupLabel(); |
| | | |
| | | |
| | | public: |
| | | void SetBkgndColor(COLORREF color); |
| | | void SetTextColor(COLORREF color); |
| | | void SetLineColor(COLORREF color); |
| | | void Setpadding(int type, unsigned int nPadding); |
| | | void SetTextAlignMode(int nAlign); |
| | | void EnableResize(); |
| | | void DisableResize(); |
| | | |
| | | private: |
| | | COLORREF m_crBkgnd; |
| | | unsigned int m_nPadding[4]; |
| | | COLORREF m_crLine; |
| | | COLORREF m_crText; |
| | | int m_nTextAlign; |
| | | |
| | | private: |
| | | BOOL m_bEnableResize; |
| | | |
| | | DECLARE_MESSAGE_MAP() |
| | | afx_msg void OnPaint(); |
| | | public: |
| | | afx_msg void OnLButtonDown(UINT nFlags, CPoint point); |
| | | afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); |
| | | }; |
| | | |
| | |
| | | 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(); |
| | |
| | | std::regex((LPTSTR)(LPCTSTR)m_strFilterText)); |
| | | } |
| | | catch (const std::regex_error& e) { |
| | | |
| | | TRACE(_T("æ£å¨è¡¨è¾¾å¼å¹é
æ£æµå¼å¸¸: %s\n"), e.what()); |
| | | } |
| | | } |
| | | if (m_filterMode == FilterMode::Exclude) { |
| | |
| | | |
| | | namespace SERVO { |
| | | static inline std::string trimCopy(std::string s) { |
| | | auto notspace = [](int ch) { return !std::isspace(ch); }; |
| | | s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace)); |
| | | s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end()); |
| | | s.erase(s.begin(), |
| | | std::find_if(s.begin(), s.end(), |
| | | [](char c) { return !std::isspace(static_cast<unsigned char>(c)); })); |
| | | s.erase(std::find_if(s.rbegin(), s.rend(), |
| | | [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }).base(), |
| | | s.end()); |
| | | return s; |
| | | } |
| | | |
| | |
| | | CProcessJob::CProcessJob(std::string pjId) |
| | | : m_pjId(trimCopy(pjId)) |
| | | { |
| | | clampString(m_pjId, MAX_ID_LEN); |
| | | } |
| | | |
| | | void CProcessJob::setId(std::string& id) |
| | | { |
| | | m_pjId = trimCopy(id); |
| | | clampString(m_pjId, MAX_ID_LEN); |
| | | } |
| | | |
| | |
| | | m_pauseEvents.erase(std::unique(m_pauseEvents.begin(), m_pauseEvents.end()), m_pauseEvents.end()); |
| | | } |
| | | |
| | | const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issues() |
| | | const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issues() const |
| | | { |
| | | return m_issues; |
| | | } |
| | |
| | | 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; |
| | |
| | | } |
| | | } |
| | | |
| | | 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 --------- |
| | | void CProcessJob::serialize(std::ostream& os) const { |
| | | // Í· |
| | |
| | | |
| | | // é
æ¹ |
| | | uint8_t recipeType = static_cast<uint8_t>(m_recipeMethod); |
| | | write_pod(os, m_recipeMethod); |
| | | write_pod(os, recipeType); |
| | | write_string(os, m_recipeSpec); |
| | | |
| | | // ç©æï¼å¤ Carrier & Slotï¼ |
| | |
| | | return "InProcess"; |
| | | break; |
| | | case SERVO::PJState::Paused: |
| | | return "Queued"; |
| | | return "Paused"; |
| | | break; |
| | | case SERVO::PJState::Aborting: |
| | | return "Aborting"; |
| | | break; |
| | | case SERVO::PJState::Completed: |
| | | return "Queued"; |
| | | return "Completed"; |
| | | break; |
| | | case SERVO::PJState::Aborted: |
| | | return "Aborted"; |
| | |
| | | return ""; |
| | | } |
| | | |
| | | CarrierSlotInfo* CProcessJob::getCarrier(std::string& strId) |
| | | CarrierSlotInfo* CProcessJob::getCarrier(const std::string& strId) |
| | | { |
| | | for (auto& item : m_carriers) { |
| | | if (item.carrierId.compare(strId) == 0) { |
| | |
| | | |
| | | 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 { |
| | |
| | | explicit CProcessJob(std::string pjId); |
| | | |
| | | const std::string& id() const noexcept { return m_pjId; } |
| | | void setId(std::string& id); |
| | | const std::string& parentCjId() const noexcept { return m_parentCjId; } |
| | | PJState state() const noexcept { return m_state; } |
| | | StartPolicy startPolicy() const noexcept { return m_startPolicy; } |
| | |
| | | }; |
| | | // è¿åé®é¢æ¸
åï¼ç©º=éè¿ï¼ |
| | | bool validate(const IResourceView& rv); |
| | | const std::vector<ValidationIssue>& issues(); |
| | | const std::vector<ValidationIssue>& issues() const; |
| | | |
| | | // ââ ç¶ææºï¼å¸¦å®å«ï¼ââ |
| | | bool queue(); // NoState -> Queued |
| | |
| | | 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; } |
| | | CarrierSlotInfo* getCarrier(std::string& strId); |
| | | CarrierSlotInfo* getCarrier(const std::string& strId); |
| | | |
| | | // å¤å®æ¯å¦âæè½½å
·/å¡ä½âæ¹å¼ |
| | | bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); } |
| | |
| | | |
| | | // é误å表 |
| | | 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(); |
| | | }; |
| | | } |
| | | |
| | |
| | | #include "EqsGraphWnd.h" |
| | | #include "MapPosWnd.h" |
| | | #include "HmTab.h" |
| | | #include "CControlJobManagerDlg.h" |
| | | |
| | | |
| | | // 声æå
¨å±åéï¼ç¨äºç®¡ç GDI+ åå§å |
| | |
| | | |
| | | int CServoApp::ExitInstance() |
| | | { |
| | | CControlJobManagerDlg::FreeState(); |
| | | m_model.term(); |
| | | HSMS_Term(); |
| | | RX_Term(); |
| | |
| | | <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="..\jsoncpp\include\json\writer.h" /> |
| | | <ClInclude Include="..\jsoncpp\lib_json\json_batchallocator.h" /> |
| | | <ClInclude Include="CBaseDlg.h" /> |
| | | <ClInclude Include="CCarrierSlotGrid.h" /> |
| | | <ClInclude Include="CCarrierSlotSelector.h" /> |
| | | <ClInclude Include="CCjPage2.h" /> |
| | | <ClInclude Include="CCjPage3.h" /> |
| | | <ClInclude Include="CCjPageBase.h" /> |
| | | <ClInclude Include="CControlJob.h" /> |
| | | <ClInclude Include="CControlJobDlg.h" /> |
| | | <ClInclude Include="CControlJobManagerDlg.h" /> |
| | | <ClInclude Include="CCustomCheckBox.h" /> |
| | | <ClInclude Include="CCollectionEvent.h" /> |
| | | <ClInclude Include="CEquipmentPage3.h" /> |
| | | <ClInclude Include="CExpandableListCtrl.h" /> |
| | | <ClInclude Include="CGlassPool.h" /> |
| | | <ClInclude Include="ChangePasswordDlg.h" /> |
| | | <ClInclude Include="ClientListDlg.h" /> |
| | | <ClInclude Include="CMyStatusbar.h" /> |
| | | <ClInclude Include="CPageCollectionEvent.h" /> |
| | | <ClInclude Include="CPageGlassList.h" /> |
| | |
| | | <ClInclude Include="CPageReport.h" /> |
| | | <ClInclude Include="CPageVarialbles.h" /> |
| | | <ClInclude Include="CParam.h" /> |
| | | <ClInclude Include="CCjPage1.h" /> |
| | | <ClInclude Include="CProcessDataListDlg.h" /> |
| | | <ClInclude Include="CReport.h" /> |
| | | <ClInclude Include="CRobotCmdContainerDlg.h" /> |
| | |
| | | <ClInclude Include="GridControl\TitleTip.h" /> |
| | | <ClInclude Include="CRobotTask.h" /> |
| | | <ClInclude Include="CSlot.h" /> |
| | | <ClInclude Include="GroupLabel.h" /> |
| | | <ClInclude Include="HorizontalLine.h" /> |
| | | <ClInclude Include="InputDialog.h" /> |
| | | <ClInclude Include="JobSlotGrid.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> |
| | |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> |
| | | </ClCompile> |
| | | <ClCompile Include="CBaseDlg.cpp" /> |
| | | <ClCompile Include="CCarrierSlotGrid.cpp" /> |
| | | <ClCompile Include="CCarrierSlotSelector.cpp" /> |
| | | <ClCompile Include="CCjPage2.cpp" /> |
| | | <ClCompile Include="CCjPage3.cpp" /> |
| | | <ClCompile Include="CCjPageBase.cpp" /> |
| | | <ClCompile Include="CControlJob.cpp" /> |
| | | <ClCompile Include="CControlJobDlg.cpp" /> |
| | | <ClCompile Include="CControlJobManagerDlg.cpp" /> |
| | | <ClCompile Include="CCustomCheckBox.cpp" /> |
| | | <ClCompile Include="CCollectionEvent.cpp" /> |
| | | <ClCompile Include="CEquipmentPage3.cpp" /> |
| | | <ClCompile Include="CExpandableListCtrl.cpp" /> |
| | | <ClCompile Include="CGlassPool.cpp" /> |
| | | <ClCompile Include="ChangePasswordDlg.cpp" /> |
| | | <ClCompile Include="ClientListDlg.cpp" /> |
| | | <ClCompile Include="CMyStatusbar.cpp" /> |
| | | <ClCompile Include="CPageCollectionEvent.cpp" /> |
| | | <ClCompile Include="CPageGlassList.cpp" /> |
| | |
| | | <ClCompile Include="CPageReport.cpp" /> |
| | | <ClCompile Include="CPageVarialbles.cpp" /> |
| | | <ClCompile Include="CParam.cpp" /> |
| | | <ClCompile Include="CCjPage1.cpp" /> |
| | | <ClCompile Include="CProcessDataListDlg.cpp" /> |
| | | <ClCompile Include="CReport.cpp" /> |
| | | <ClCompile Include="CRobotCmdContainerDlg.cpp" /> |
| | |
| | | <ClCompile Include="GridControl\TitleTip.cpp" /> |
| | | <ClCompile Include="CRobotTask.cpp" /> |
| | | <ClCompile Include="CSlot.cpp" /> |
| | | <ClCompile Include="GroupLabel.cpp" /> |
| | | <ClCompile Include="HorizontalLine.cpp" /> |
| | | <ClCompile Include="InputDialog.cpp" /> |
| | | <ClCompile Include="JobSlotGrid.cpp" /> |
| | |
| | | <ClCompile Include="GlassLogDb.cpp" /> |
| | | <ClCompile Include="sqlite3.c" /> |
| | | <ClCompile Include="CProcessDataListDlg.cpp" /> |
| | | <ClCompile Include="GroupLabel.cpp" /> |
| | | <ClCompile Include="CControlJobManagerDlg.cpp" /> |
| | | <ClCompile Include="CCjPage1.cpp" /> |
| | | <ClCompile Include="CCjPage2.cpp" /> |
| | | <ClCompile Include="CCjPage3.cpp" /> |
| | | <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="sqlite3.h" /> |
| | | <ClInclude Include="sqlite3ext.h" /> |
| | | <ClInclude Include="CProcessDataListDlg.h" /> |
| | | <ClInclude Include="GroupLabel.h" /> |
| | | <ClInclude Include="CControlJobManagerDlg.h" /> |
| | | <ClInclude Include="CCjPage1.h" /> |
| | | <ClInclude Include="CCjPage2.h" /> |
| | | <ClInclude Include="CCjPage3.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> |
| | |
| | | <RemoteDebuggerCommand>\\DESKTOP-IODBVIQ\Servo\Debug\Servo.exe</RemoteDebuggerCommand> |
| | | <RemoteDebuggerWorkingDirectory>\\DESKTOP-IODBVIQ\Servo\Debug\</RemoteDebuggerWorkingDirectory> |
| | | <RemoteDebuggerServerName>DESKTOP-IODBVIQ</RemoteDebuggerServerName> |
| | | <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> |
| | | <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor> |
| | | </PropertyGroup> |
| | | </Project> |
| | |
| | | |
| | | // ServoDlg.cpp : å®ç°æä»¶ |
| | |  |
| | | // ServoDlg.cpp : å®ç°æä»¶ |
| | | // |
| | | |
| | | #include "stdafx.h" |
| | |
| | | #include "CPageCollectionEvent.h" |
| | | #include "CControlJobDlg.h" |
| | | #include "InputDialog.h" |
| | | #include "ClientListDlg.h" |
| | | #include "CControlJobManagerDlg.h" |
| | | |
| | | |
| | | #ifdef _DEBUG |
| | |
| | | #endif |
| | | |
| | | |
| | | /* å建ç»ç«¯ç宿¶å¨ */ |
| | | /* å建ç»ç«¯ç宿¶å¨ */ |
| | | #define TIMER_ID_CREATE_TERMINAL 1 |
| | | |
| | | /* è¿è¡æ¶é´å®æ¶å¨ */ |
| | | /* è¿è¡æ¶é´å®æ¶å¨ */ |
| | | #define TIMER_ID_UPDATE_RUMTIME 2 |
| | | |
| | | /* Test */ |
| | | #define TIMER_ID_TEST 3 |
| | | |
| | | |
| | | // ç¨äºåºç¨ç¨åºâå
³äºâèå项ç CAboutDlg å¯¹è¯æ¡ |
| | | // ç¨äºåºç¨ç¨åºâå
³äºâèå项ç CAboutDlg å¯¹è¯æ¡ |
| | | |
| | | class CAboutDlg : public CDialogEx |
| | | { |
| | | public: |
| | | CAboutDlg(); |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_ABOUTBOX }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | // å®ç° |
| | | // å®ç° |
| | | protected: |
| | | DECLARE_MESSAGE_MAP() |
| | | }; |
| | |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CServoDlg å¯¹è¯æ¡ |
| | | // CServoDlg å¯¹è¯æ¡ |
| | | |
| | | |
| | | CServoDlg::CServoDlg(CWnd* pParent /*=NULL*/) |
| | |
| | | ON_UPDATE_COMMAND_UI(ID_MENU_TEST_MESSAGE_SET, &CServoDlg::OnUpdateMenuTestMessageSet) |
| | | ON_COMMAND(ID_MENU_TEST_MESSAGE_CLEAR, &CServoDlg::OnMenuTestMessageClear) |
| | | ON_UPDATE_COMMAND_UI(ID_MENU_TEST_MESSAGE_CLEAR, &CServoDlg::OnUpdateMenuTestMessageClear) |
| | | ON_COMMAND(ID_MENU_TOOLS_CLIENT_LIST, &CServoDlg::OnMenuToolsClientList) |
| | | ON_UPDATE_COMMAND_UI(ID_MENU_TOOLS_CLIENT_LIST, &CServoDlg::OnUpdateMenuToolsClientList) |
| | | ON_COMMAND(ID_MENU_HELP_ABOUT, &CServoDlg::OnMenuHelpAbout) |
| | | ON_WM_INITMENUPOPUP() |
| | | ON_WM_TIMER() |
| | |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CServoDlg æ¶æ¯å¤çç¨åº |
| | | // CServoDlg æ¶æ¯å¤çç¨åº |
| | | |
| | | void CServoDlg::InitRxWindows() |
| | | { |
| | | /* code */ |
| | | // 订é
æ°æ® |
| | | // 订é
æ°æ® |
| | | IRxWindows* pRxWindows = RX_GetRxWindows(); |
| | | pRxWindows->enableLog(5); |
| | | if (m_pObserver == NULL) { |
| | |
| | | else if (state == SERVO::MASTERSTATE::STARTING) { |
| | | m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_STARTING); |
| | | m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0)); |
| | | m_pMyStatusbar->setRunTimeText("æ£å¨å¯å¨..."); |
| | | m_pMyStatusbar->setRunTimeText("æ£å¨å¯å¨..."); |
| | | } |
| | | else if (state == SERVO::MASTERSTATE::MSERROR) { |
| | | m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE); |
| | |
| | | m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE); |
| | | m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM); |
| | | m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0)); |
| | | m_pMyStatusbar->setRunTimeText("å¯å¨å¤±è´¥."); |
| | | m_pMyStatusbar->setRunTimeText("å¯å¨å¤±è´¥."); |
| | | m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(TRUE); |
| | | KillTimer(TIMER_ID_UPDATE_RUMTIME); |
| | | } |
| | |
| | | m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0)); |
| | | m_pMyStatusbar->setRunTimeText(theApp.m_model.getMaster().getLastErrorText().c_str()); |
| | | if (theApp.m_model.getMaster().getLastError() == ER_CODE_AOI_NG) { |
| | | AfxMessageBox(_T("AOIæ£æµå¤±è´¥ï¼è¯·æä½åä»å
¥è§£å³é®é¢ï¼")); |
| | | AfxMessageBox(_T("AOIæ£æµå¤±è´¥ï¼è¯·æä½åä»å
¥è§£å³é®é¢ï¼")); |
| | | } |
| | | m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(TRUE); |
| | | KillTimer(TIMER_ID_UPDATE_RUMTIME); |
| | |
| | | } |
| | | } |
| | | else if (exCode == ROBOT_EVENT_FINISH) { |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | } |
| | | else if (exCode == ROBOT_EVENT_ABORT) { |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | } |
| | | else if (exCode == ROBOT_EVENT_RESTORE) { |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | m_pMyStatusbar->setCurTaskBtnText("æ "); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | |
| | | // å°âå
³äº...âèå项添å å°ç³»ç»èåä¸ã |
| | | // å°âå
³äº...âèå项添å å°ç³»ç»èåä¸ã |
| | | |
| | | // IDM_ABOUTBOX å¿
é¡»å¨ç³»ç»å½ä»¤èå´å
ã |
| | | // IDM_ABOUTBOX å¿
é¡»å¨ç³»ç»å½ä»¤èå´å
ã |
| | | ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); |
| | | ASSERT(IDM_ABOUTBOX < 0xF000); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 设置æ¤å¯¹è¯æ¡ç徿 ã å½åºç¨ç¨åºä¸»çªå£ä¸æ¯å¯¹è¯æ¡æ¶ï¼æ¡æ¶å°èªå¨ |
| | | // æ§è¡æ¤æä½ |
| | | SetIcon(m_hIcon, TRUE); // è®¾ç½®å¤§å¾æ |
| | | SetIcon(m_hIcon, FALSE); // 设置å°å¾æ |
| | | // 设置æ¤å¯¹è¯æ¡ç徿 ã å½åºç¨ç¨åºä¸»çªå£ä¸æ¯å¯¹è¯æ¡æ¶ï¼æ¡æ¶å°èªå¨ |
| | | // æ§è¡æ¤æä½ |
| | | SetIcon(m_hIcon, TRUE); // è®¾ç½®å¤§å¾æ |
| | | SetIcon(m_hIcon, FALSE); // 设置å°å¾æ |
| | | |
| | | |
| | | // model init |
| | | theApp.m_model.init(); |
| | | SetTimer(TIMER_ID_TEST, 1000, nullptr); |
| | | |
| | | // èå |
| | | // èå |
| | | CMenu menu; |
| | | menu.LoadMenu(IDR_MENU_APP); |
| | | SetMenu(&menu); |
| | |
| | | CHmTab* m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd); |
| | | m_pTab->SetPaddingLeft(20); |
| | | m_pTab->SetItemMarginLeft(18); |
| | | m_pTab->AddItem("״̬ͼ", FALSE); |
| | | m_pTab->AddItem("è¿æ¥å¾", TRUE); |
| | | m_pTab->AddItem("ç¶æå¾", FALSE); |
| | | m_pTab->AddItem("è¿æ¥å¾", TRUE); |
| | | m_pTab->AddItem("Glass", TRUE); |
| | | m_pTab->AddItem("é
æ¹", TRUE); |
| | | m_pTab->AddItem("æ¥è¦", TRUE); |
| | | m_pTab->AddItem("æ¥å¿", TRUE); |
| | | m_pTab->AddItem("æ¬è¿ä»»å¡", TRUE); |
| | | m_pTab->AddItem("é
æ¹", TRUE); |
| | | m_pTab->AddItem("æ¥è¦", TRUE); |
| | | m_pTab->AddItem("æ¥å¿", TRUE); |
| | | m_pTab->AddItem("æ¬è¿ä»»å¡", TRUE); |
| | | m_pTab->SetCurSel(0); |
| | | m_pTab->SetBkgndColor(RGB(222, 222, 222)); |
| | | ShowChildPage(0); |
| | |
| | | |
| | | |
| | | |
| | | // è°æ´åå§çªå£ä½ç½® |
| | | // è°æ´åå§çªå£ä½ç½® |
| | | CRect rcWnd; |
| | | GetWindowRect(&rcWnd); |
| | | int width = GetSystemMetrics(SM_CXSCREEN); |
| | |
| | | Resize(); |
| | | |
| | | |
| | | // ç¸å½äºå»¶æ¶è°ç¨masterçåå§å |
| | | // ç¸å½äºå»¶æ¶è°ç¨masterçåå§å |
| | | theApp.m_model.m_master.init(); |
| | | theApp.m_model.loadPortParams(); |
| | | |
| | | |
| | | // åå§åmaster以åéè¦æ§ä»¶ç»å®æ°æ® |
| | | // åå§åmaster以åéè¦æ§ä»¶ç»å®æ°æ® |
| | | m_pPageGraph1->BindEquipmentToGraph(); |
| | | |
| | | |
| | | // æ´æ°ç»å½ç¶æ |
| | | // æ´æ°ç»å½ç¶æ |
| | | UpdateLoginStatus(); |
| | | //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEqå¯å¨...")); |
| | | //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEqå¯å¨...")); |
| | | //SystemLogManager::getInstance. |
| | | |
| | | |
| | | return TRUE; // é¤éå°ç¦ç¹è®¾ç½®å°æ§ä»¶ï¼å¦åè¿å TRUE |
| | | return TRUE; // é¤éå°ç¦ç¹è®¾ç½®å°æ§ä»¶ï¼å¦åè¿å TRUE |
| | | } |
| | | |
| | | void CServoDlg::OnSysCommand(UINT nID, LPARAM lParam) |
| | |
| | | } |
| | | } |
| | | |
| | | // 妿åå¯¹è¯æ¡æ·»å æå°åæé®ï¼åéè¦ä¸é¢ç代ç |
| | | // æ¥ç»å¶è¯¥å¾æ ã 对äºä½¿ç¨ææ¡£/è§å¾æ¨¡åç MFC åºç¨ç¨åºï¼ |
| | | // è¿å°ç±æ¡æ¶èªå¨å®æã |
| | | // 妿åå¯¹è¯æ¡æ·»å æå°åæé®ï¼åéè¦ä¸é¢ç代ç |
| | | // æ¥ç»å¶è¯¥å¾æ ã 对äºä½¿ç¨ææ¡£/è§å¾æ¨¡åç MFC åºç¨ç¨åºï¼ |
| | | // è¿å°ç±æ¡æ¶èªå¨å®æã |
| | | |
| | | void CServoDlg::OnPaint() |
| | | { |
| | | if (IsIconic()) |
| | | { |
| | | CPaintDC dc(this); // ç¨äºç»å¶ç设å¤ä¸ä¸æ |
| | | CPaintDC dc(this); // ç¨äºç»å¶ç设å¤ä¸ä¸æ |
| | | |
| | | SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); |
| | | |
| | | // ä½¿å¾æ å¨å·¥ä½åºç©å½¢ä¸å±
ä¸ |
| | | // ä½¿å¾æ å¨å·¥ä½åºç©å½¢ä¸å±
ä¸ |
| | | int cxIcon = GetSystemMetrics(SM_CXICON); |
| | | int cyIcon = GetSystemMetrics(SM_CYICON); |
| | | CRect rect; |
| | |
| | | int x = (rect.Width() - cxIcon + 1) / 2; |
| | | int y = (rect.Height() - cyIcon + 1) / 2; |
| | | |
| | | // ç»å¶å¾æ |
| | | // ç»å¶å¾æ |
| | | dc.DrawIcon(x, y, m_hIcon); |
| | | } |
| | | else |
| | |
| | | } |
| | | } |
| | | |
| | | //å½ç¨æ·æå¨æå°åçªå£æ¶ç³»ç»è°ç¨æ¤å½æ°åå¾å
æ |
| | | //æ¾ç¤ºã |
| | | //å½ç¨æ·æå¨æå°åçªå£æ¶ç³»ç»è°ç¨æ¤å½æ°åå¾å
æ |
| | | //æ¾ç¤ºã |
| | | HCURSOR CServoDlg::OnQueryDragIcon() |
| | | { |
| | | return static_cast<HCURSOR>(m_hIcon); |
| | |
| | | pCmdUI->Enable(TRUE); |
| | | } |
| | | |
| | | void CServoDlg::OnMenuToolsClientList() |
| | | { |
| | | CClientListDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | |
| | | void CServoDlg::OnUpdateMenuToolsClientList(CCmdUI* pCmdUI) |
| | | { |
| | | pCmdUI->Enable(TRUE); |
| | | } |
| | | |
| | | void CServoDlg::OnMenuHelpAbout() |
| | | { |
| | | theApp.m_model.getMaster().test(); |
| | |
| | | |
| | | void CServoDlg::OnBnClickedOk() |
| | | { |
| | | // TODO: 卿¤æ·»å æ§ä»¶éç¥å¤çç¨åºä»£ç |
| | | // TODO: 卿¤æ·»å æ§ä»¶éç¥å¤çç¨åºä»£ç |
| | | CDialogEx::OnOK(); |
| | | } |
| | | |
| | | |
| | | void CServoDlg::OnBnClickedCancel() |
| | | { |
| | | // TODO: 卿¤æ·»å æ§ä»¶éç¥å¤çç¨åºä»£ç |
| | | // TODO: 卿¤æ·»å æ§ä»¶éç¥å¤çç¨åºä»£ç |
| | | CDialogEx::OnCancel(); |
| | | } |
| | | |
| | |
| | | |
| | | void CServoDlg::OnClose() |
| | | { |
| | | // TODO: 卿¤æ·»å æ¶æ¯å¤çç¨åºä»£ç å/æè°ç¨é»è®¤å¼ |
| | | // TODO: 卿¤æ·»å æ¶æ¯å¤çç¨åºä»£ç å/æè°ç¨é»è®¤å¼ |
| | | |
| | | CDialogEx::OnClose(); |
| | | } |
| | |
| | | void CServoDlg::OnTimer(UINT_PTR nIDEvent) |
| | | { |
| | | if (TIMER_ID_CREATE_TERMINAL == nIDEvent) { |
| | | // é¢å
å建ç»ç«¯çªå£ |
| | | // é¢å
å建ç»ç«¯çªå£ |
| | | KillTimer(TIMER_ID_CREATE_TERMINAL); |
| | | char szBuffer[MAX_PATH]; |
| | | sprintf_s(szBuffer, MAX_PATH, "%s\\RES\\TeminalMsg.html", (LPTSTR)(LPCTSTR)theApp.m_strAppDir); |
| | |
| | | ::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); |
| | | ::EnableMenuItem(hMenu, ID_OPERATOR_LOGOUT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); |
| | | |
| | | m_pTopToolbar->SetOperatorBtnText(_T("æªç»å½")); |
| | | m_pTopToolbar->SetOperatorBtnText(_T("æªç»å½")); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | int id = (int)lParam; |
| | | if (id == IDC_BUTTON_RUN || id == IDC_BUTTON_STOP) { |
| | | //CInputDialog inputDialog(_T("éªè¯ç¨æ·"), _T("请è¾å
¥ç¨æ·å¯ç ï¼")); |
| | | //if (inputDialog.DoModal() != IDOK) { |
| | | // AfxMessageBox(_T("åæ¶éªè¯ï¼")); |
| | | // return 0; |
| | | //} |
| | | |
| | | //CString inputText = inputDialog.GetInputText(); |
| | | //std::string strPass = UserManager::getInstance().getCurrentPass(); |
| | | //if (inputText.Compare(strPass.c_str()) != 0) { |
| | | // AfxMessageBox(_T("å¯ç é误ï¼")); |
| | | // SystemLogManager::getInstance().log(SystemLogManager::LogType::Info, _T("éªè¯æ¶ï¼å¯ç é误ï¼")); |
| | | // return 0; |
| | | //} |
| | | |
| | | UserRole emRole = UserManager::getInstance().getCurrentUserRole(); |
| | | if (emRole != UserRole::SuperAdmin) { |
| | | AfxMessageBox(_T("å½åç¨æ·å¹¶é管çåï¼ï¼ï¼")); |
| | | AfxMessageBox(_T("å½åç¨æ·å¹¶é管çåï¼ï¼ï¼")); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | if (id == IDC_BUTTON_RUN) { |
| | | if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) { |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | } |
| | | else { |
| | | if (theApp.m_model.getMaster().start() == 0) { |
| | |
| | | } |
| | | else if (id == IDC_BUTTON_RUN_BATCH) { |
| | | if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) { |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | } |
| | | else { |
| | | if (theApp.m_model.getMaster().startBatch() == 0) { |
| | |
| | | } |
| | | else if (id == IDC_BUTTON_RUN_CT) { |
| | | if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) { |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | AfxMessageBox("å½åææºå°åçé误ï¼ä¸è½å¯å¨ï¼è¯·ç¡®è®¤è§£å³é®é¢ååå°è¯éæ°å¯å¨ï¼"); |
| | | } |
| | | else { |
| | | if (theApp.m_model.getMaster().startContinuousTransfer() == 0) { |
| | |
| | | } |
| | | else if (id == IDC_BUTTON_JOBS) { |
| | | CControlJobDlg dlg; |
| | | dlg.SetControlJob(theApp.m_model.m_master.getControlJob()); |
| | | 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) { |
| | |
| | | else if (2 == menuId) { |
| | | CUserManagerDlg dlg; |
| | | if (dlg.DoModal() != IDOK) { |
| | | logManager.log(SystemLogManager::LogType::Operation, _T("ç¨æ·ç®¡çç颿ä½è¢«åæ¶ï¼")); |
| | | logManager.log(SystemLogManager::LogType::Operation, _T("ç¨æ·ç®¡çç颿ä½è¢«åæ¶ï¼")); |
| | | } |
| | | } |
| | | else if (3 == menuId) { |
| | |
| | | dlg.DoModal(); |
| | | } |
| | | else if (4 == menuId) { |
| | | int ret = AfxMessageBox(_T("æ¯å¦åæ¢ç¨æ·ï¼åæ¢ç¨æ·ä¼éåºå½åè´¦å·ï¼"), MB_OKCANCEL | MB_ICONEXCLAMATION); |
| | | int ret = AfxMessageBox(_T("æ¯å¦åæ¢ç¨æ·ï¼åæ¢ç¨æ·ä¼éåºå½åè´¦å·ï¼"), MB_OKCANCEL | MB_ICONEXCLAMATION); |
| | | if (ret != IDOK) { |
| | | return 0; |
| | | } |
| | | |
| | | logManager.log(SystemLogManager::LogType::Operation, _T("ç¡®è®¤åæ¢è§è²ï¼")); |
| | | logManager.log(SystemLogManager::LogType::Operation, _T("ç¡®è®¤åæ¢è§è²ï¼")); |
| | | if (userManager.isLoggedIn()) { |
| | | logManager.log(SystemLogManager::LogType::Info, _T("éåºç»å½ï¼")); |
| | | logManager.log(SystemLogManager::LogType::Info, _T("éåºç»å½ï¼")); |
| | | userManager.logout(); |
| | | } |
| | | |
| | |
| | | } |
| | | else { |
| | | CString cstrMessage; |
| | | cstrMessage.Format(_T("æ¯å¦éåºç¨æ· [%s]ï¼"), userManager.getCurrentUser().c_str()); |
| | | cstrMessage.Format(_T("æ¯å¦éåºç¨æ· [%s]ï¼"), userManager.getCurrentUser().c_str()); |
| | | int ret = AfxMessageBox(_T(cstrMessage), MB_OKCANCEL | MB_ICONEXCLAMATION); |
| | | if (ret != IDOK) { |
| | | return 0; |
| | | } |
| | | |
| | | logManager.log(SystemLogManager::LogType::Info, _T("éåºç»å½ï¼")); |
| | | logManager.log(SystemLogManager::LogType::Info, _T("éåºç»å½ï¼")); |
| | | userManager.logout(); |
| | | } |
| | | |
| | |
| | | |
| | | SERVO::MASTERSTATE state = theApp.m_model.getMaster().getState(); |
| | | if (state == SERVO::MASTERSTATE::RUNNING) { |
| | | strText.Format(_T("æ£å¨è¿è¡ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | strText.Format(_T("æ£å¨è¿è¡ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | } |
| | | else if (state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) { |
| | | strText.Format(_T("åä¼ æ¨¡å¼ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | strText.Format(_T("åä¼ æ¨¡å¼ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | } |
| | | else if (state == SERVO::MASTERSTATE::RUNNING_BATCH) { |
| | | strText.Format(_T("JOB模å¼ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | strText.Format(_T("JOB模å¼ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | } |
| | | else { |
| | | strText.Format(_T("å·²è¿è¡ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | strText.Format(_T("å·²è¿è¡ï¼%02d:%02d:%02d %s"), h, m, s, pszSuffix); |
| | | } |
| | | |
| | | return strText; |
| | |
| | | |
| | | // ServoDlg.h : 头æä»¶ |
| | |  |
| | | // ServoDlg.h : 头æä»¶ |
| | | // |
| | | |
| | | #pragma once |
| | |
| | | #include "CPageGlassList.h" |
| | | |
| | | |
| | | // CServoDlg å¯¹è¯æ¡ |
| | | // CServoDlg å¯¹è¯æ¡ |
| | | class CServoDlg : public CDialogEx |
| | | { |
| | | // æé |
| | | // æé |
| | | public: |
| | | CServoDlg(CWnd* pParent = NULL); // æ åæé 彿° |
| | | CServoDlg(CWnd* pParent = NULL); // æ åæé 彿° |
| | | |
| | | |
| | | public: |
| | |
| | | CPageLog* m_pPageLog; |
| | | CPageTransferLog* m_pPageTransferLog; |
| | | |
| | | // å¯¹è¯æ¡æ°æ® |
| | | // å¯¹è¯æ¡æ°æ® |
| | | #ifdef AFX_DESIGN_TIME |
| | | enum { IDD = IDD_SERVO_DIALOG }; |
| | | #endif |
| | | |
| | | protected: |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV æ¯æ |
| | | |
| | | |
| | | // å®ç° |
| | | // å®ç° |
| | | protected: |
| | | HICON m_hIcon; |
| | | COLORREF m_crBkgnd; |
| | |
| | | CPanelAttributes* m_pPanelAttributes; |
| | | CMyStatusbar* m_pMyStatusbar; |
| | | |
| | | // çæçæ¶æ¯æ å°å½æ° |
| | | // çæçæ¶æ¯æ å°å½æ° |
| | | virtual BOOL OnInitDialog(); |
| | | afx_msg void OnSysCommand(UINT nID, LPARAM lParam); |
| | | afx_msg void OnPaint(); |
| | |
| | | afx_msg void OnUpdateMenuTestMessageSet(CCmdUI* pCmdUI); |
| | | afx_msg void OnMenuTestMessageClear(); |
| | | afx_msg void OnUpdateMenuTestMessageClear(CCmdUI* pCmdUI); |
| | | afx_msg void OnMenuToolsClientList(); |
| | | afx_msg void OnUpdateMenuToolsClientList(CCmdUI* pCmdUI); |
| | | afx_msg void OnMenuHelpAbout(); |
| | | afx_msg void OnTimer(UINT_PTR nIDEvent); |
| | | afx_msg LRESULT OnPanelResize(WPARAM wParam, LPARAM lParam); |
| | |
| | | |
| | | void CTerminalDisplayDlg::Resize() |
| | | { |
| | | CWnd* pItem; |
| | | CRect rcClient, rcItem; |
| | | GetClientRect(&rcClient); |
| | | rcClient.top += 38; |
| | |
| | | #include <memory> |
| | | #include <sstream> |
| | | #include <algorithm> |
| | | |
| | | #include <ctime> |
| | | #include <iomanip> |
| | | #include <sstream> |
| | | |
| | | CToolUnits::CToolUnits() |
| | | { |
| | |
| | | std::snprintf(out, sizeof(out), "%s.%03d", date, ms); |
| | | return out; |
| | | } |
| | | |
| | | std::string CToolUnits::NowStrSec() |
| | | { |
| | | using namespace std::chrono; |
| | | auto now = system_clock::now(); |
| | | std::time_t t = system_clock::to_time_t(now); |
| | | std::tm tm{}; |
| | | #ifdef _WIN32 |
| | | localtime_s(&tm, &t); // æ¬å°æ¶é´ï¼Windows 线ç¨å®å
¨ï¼ |
| | | #else |
| | | localtime_r(&t, &tm); // æ¬å°æ¶é´ï¼POSIX 线ç¨å®å
¨ï¼ |
| | | #endif |
| | | std::ostringstream oss; |
| | | oss << std::put_time(&tm, "%Y%m%d%H%M%S"); // ä¾ï¼2025-09-15 08:23:07 |
| | | return oss.str(); |
| | | } |
| | |
| | | static std::string TimePointToUtcString(const std::optional<TP>& tp, |
| | | const char* fmt = "%Y-%m-%d %H:%M:%S"); |
| | | static std::string TimePointToLocalStringMs(const std::optional<TP>& tp); |
| | | static std::string NowStrSec(); |
| | | }; |
| | | |
| | |
| | | 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 |