综合平台编程器项目的远程存储
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

395 linhas
13 KiB

  1. #include "register_monitor_service.h"
  2. #include "domain/virtual_register_repository.h"
  3. #include <algorithm>
  4. #include <cmath>
  5. #include <optional>
  6. #include <utility>
  7. namespace {
  8. std::string parseErrorMessage(RegisterAddressParseError error)
  9. {
  10. switch (error)
  11. {
  12. case RegisterAddressParseError::Empty:
  13. return "请输入 M0~M4000 或 D0~D4000 地址";
  14. case RegisterAddressParseError::UnsupportedArea:
  15. return "自由监控只支持 M 区和 D 区地址";
  16. case RegisterAddressParseError::OutOfRange:
  17. return "监控地址必须位于 M0~M4000 或 D0~D4000";
  18. case RegisterAddressParseError::InvalidFormat:
  19. case RegisterAddressParseError::None:
  20. default:
  21. return "监控地址格式无效,请输入例如 M0 或 D100";
  22. }
  23. }
  24. } // namespace
  25. RegisterMonitorService::RegisterMonitorService(RegisterRepository &repository)
  26. : repository_(repository)
  27. {
  28. }
  29. void RegisterMonitorService::setOfflineInitialRepository(
  30. VirtualRegisterRepository &repository)
  31. {
  32. offline_initial_repository_ = &repository;
  33. }
  34. void RegisterMonitorService::setOfflineInitialCaptureEnabled(bool enabled)
  35. {
  36. capture_offline_initial_values_ = enabled;
  37. }
  38. RegisterMonitorResult RegisterMonitorService::addRange(
  39. const std::string &start_address, int count)
  40. {
  41. return addRange(start_address, count, RegisterDataType::Int16);
  42. }
  43. RegisterMonitorResult RegisterMonitorService::addRange(
  44. const std::string &start_address, int count, RegisterDataType data_type)
  45. {
  46. const RegisterAddressParseResult parsed = parseRegisterAddress(start_address);
  47. if (!parsed.succeeded)
  48. {
  49. return {false, RegisterMonitorError::InvalidAddress,
  50. parseErrorMessage(parsed.error), 0};
  51. }
  52. if (parsed.address.area() == RegisterArea::M
  53. && data_type != RegisterDataType::Int16)
  54. {
  55. return {false, RegisterMonitorError::InvalidAddress,
  56. "M 区只支持位监控,Int32、Float32 和 Double 只允许使用 D 区", 0};
  57. }
  58. if (parsed.address.area() == RegisterArea::D
  59. && !registerDataTypeAddressIsValid(data_type, parsed.address))
  60. {
  61. return {false, RegisterMonitorError::InvalidAddress,
  62. data_type == RegisterDataType::Float64
  63. ? "Double 起始地址必须是 D0~D3996 范围内的偶数地址"
  64. : std::string(registerDataTypeDescriptor(data_type).displayName)
  65. + " 起始地址超出可用 D 区范围",
  66. 0};
  67. }
  68. const int step = registerDataTypeWordCount(data_type);
  69. if (count < 1
  70. || parsed.address.index() > RegisterAddress::kMaximumIndex - step * count + 1)
  71. {
  72. return {false, RegisterMonitorError::RangeOverflow,
  73. "连续监控范围不能超过地址 4000", 0};
  74. }
  75. std::vector<MonitorPoint> pending;
  76. pending.reserve(static_cast<std::size_t>(count));
  77. for (int offset = 0; offset < count; ++offset)
  78. {
  79. MonitorPoint point{
  80. RegisterAddress{
  81. parsed.address.area(), parsed.address.index() + offset * step},
  82. data_type};
  83. if (!model_.contains(point))
  84. {
  85. pending.push_back(point);
  86. }
  87. }
  88. if (pending.empty())
  89. {
  90. return {false, RegisterMonitorError::NoChange, "所选地址已经在监控表中", 0};
  91. }
  92. if (model_.addresses().size() + pending.size() > RegisterMonitorModel::kMaximumItemCount)
  93. {
  94. return {false, RegisterMonitorError::LimitExceeded,
  95. "自由监控最多允许 64 个地址", 0};
  96. }
  97. std::vector<MonitorPoint> candidate = model_.points();
  98. candidate.insert(candidate.end(), pending.cbegin(), pending.cend());
  99. if (poll_configuration_validator_)
  100. {
  101. const std::string validation_error = poll_configuration_validator_(
  102. pollAddressesForPoints(candidate), multiWordRangesForPoints(candidate));
  103. if (!validation_error.empty())
  104. {
  105. return {false, RegisterMonitorError::PollConfigurationRejected,
  106. validation_error, 0};
  107. }
  108. }
  109. for (const MonitorPoint &point : pending)
  110. {
  111. model_.add(point);
  112. }
  113. if (addresses_changed_callback_)
  114. {
  115. addresses_changed_callback_();
  116. }
  117. bool overlaps = false;
  118. for (const MonitorPoint &existing : model_.points())
  119. {
  120. const int existing_end = existing.address.index()
  121. + registerDataTypeWordCount(existing.dataType) - 1;
  122. for (const MonitorPoint &pending_point : pending)
  123. {
  124. const RegisterAddress &address = pending_point.address;
  125. const int pending_end = address.index()
  126. + registerDataTypeWordCount(pending_point.dataType) - 1;
  127. if (existing.address.area() == address.area()
  128. && existing.address.index() <= pending_end
  129. && address.index() <= existing_end
  130. && !(existing.address == address
  131. && existing.dataType == pending_point.dataType))
  132. {
  133. overlaps = true;
  134. }
  135. }
  136. }
  137. return {true, RegisterMonitorError::None,
  138. overlaps ? "已添加,但与已有监控点的 D 地址范围重叠" : std::string{},
  139. static_cast<int>(pending.size())};
  140. }
  141. RegisterMonitorResult RegisterMonitorService::remove(
  142. const std::vector<RegisterAddress> &addresses)
  143. {
  144. int removed_count = 0;
  145. for (const RegisterAddress &address : addresses)
  146. {
  147. if (model_.remove(address))
  148. {
  149. ++removed_count;
  150. }
  151. }
  152. if (removed_count == 0)
  153. {
  154. return {false, RegisterMonitorError::NoChange, "请先选择要删除的监控地址", 0};
  155. }
  156. if (addresses_changed_callback_)
  157. {
  158. addresses_changed_callback_();
  159. }
  160. return {true, RegisterMonitorError::None, {}, removed_count};
  161. }
  162. RegisterMonitorResult RegisterMonitorService::remove(
  163. const std::vector<MonitorPoint> &points)
  164. {
  165. int removed_count = 0;
  166. for (const MonitorPoint &point : points)
  167. {
  168. if (model_.remove(point))
  169. {
  170. ++removed_count;
  171. }
  172. }
  173. if (removed_count == 0)
  174. {
  175. return {false, RegisterMonitorError::NoChange, "请先选择要删除的监控点", 0};
  176. }
  177. if (addresses_changed_callback_)
  178. {
  179. addresses_changed_callback_();
  180. }
  181. return {true, RegisterMonitorError::None, {}, removed_count};
  182. }
  183. RegisterMonitorResult RegisterMonitorService::clear()
  184. {
  185. if (model_.addresses().empty())
  186. {
  187. return {false, RegisterMonitorError::NoChange, "监控表已经为空", 0};
  188. }
  189. const int removed_count = static_cast<int>(model_.addresses().size());
  190. model_.clear();
  191. if (addresses_changed_callback_)
  192. {
  193. addresses_changed_callback_();
  194. }
  195. return {true, RegisterMonitorError::None, {}, removed_count};
  196. }
  197. RegisterMonitorWriteResult RegisterMonitorService::writeBit(
  198. const RegisterAddress &address, bool value)
  199. {
  200. const RegisterWriteResult result = repository_.writeBit(address, value);
  201. const RegisterMonitorWriteResult active_result = result.succeeded
  202. ? RegisterMonitorWriteResult{true, RegisterError::None, {}}
  203. : RegisterMonitorWriteResult{false, result.error, result.error == RegisterError::AreaMismatch
  204. ? "位写入只允许访问 M 区"
  205. : result.error == RegisterError::InvalidAddress
  206. ? "写入地址无效"
  207. : result.error == RegisterError::Unavailable
  208. ? "当前寄存器源不可用"
  209. : "寄存器写入请求被拒绝"};
  210. return captureInitialBit(address, value, active_result);
  211. }
  212. RegisterMonitorWriteResult RegisterMonitorService::writeNumeric(
  213. const RegisterAddress &address, RegisterDataType data_type, double value)
  214. {
  215. if (address.isValid() && address.area() != RegisterArea::D)
  216. {
  217. return {false, RegisterError::AreaMismatch,
  218. "数值写入只允许访问 D 区"};
  219. }
  220. if (!registerDataTypeAddressIsValid(data_type, address))
  221. {
  222. return {false, RegisterError::InvalidAddress,
  223. std::string(registerDataTypeDescriptor(data_type).displayName)
  224. + " 写入地址无效"};
  225. }
  226. const std::optional<std::vector<std::int16_t>> encoded =
  227. encodeRegisterNumericValue(data_type, value);
  228. if (!encoded.has_value())
  229. {
  230. return {false, RegisterError::InvalidAddress,
  231. std::string(registerDataTypeDescriptor(data_type).displayName)
  232. + " 写入值无效"};
  233. }
  234. const RegisterWriteResult result = repository_.writeWords(address, *encoded);
  235. const RegisterMonitorWriteResult active_result = result.succeeded
  236. ? RegisterMonitorWriteResult{true, RegisterError::None, {}}
  237. : RegisterMonitorWriteResult{false, result.error,
  238. result.error == RegisterError::AreaMismatch
  239. ? "数值写入只允许访问 D 区"
  240. : result.error == RegisterError::InvalidAddress
  241. ? "写入地址无效"
  242. : result.error == RegisterError::Unavailable
  243. ? "当前寄存器源不可用"
  244. : "寄存器写入请求被拒绝"};
  245. return captureInitialWords(address, *encoded, active_result);
  246. }
  247. RegisterMonitorWriteResult RegisterMonitorService::captureInitialBit(
  248. const RegisterAddress &address, bool value,
  249. const RegisterMonitorWriteResult &active_result)
  250. {
  251. if (!active_result.succeeded || !capture_offline_initial_values_
  252. || offline_initial_repository_ == nullptr)
  253. {
  254. return active_result;
  255. }
  256. offline_initial_repository_->writeBit(address, value);
  257. return active_result;
  258. }
  259. RegisterMonitorWriteResult RegisterMonitorService::captureInitialWords(
  260. const RegisterAddress &address,
  261. const std::vector<std::int16_t> &values,
  262. const RegisterMonitorWriteResult &active_result)
  263. {
  264. if (!active_result.succeeded || !capture_offline_initial_values_
  265. || offline_initial_repository_ == nullptr)
  266. {
  267. return active_result;
  268. }
  269. offline_initial_repository_->writeWords(address, values);
  270. return active_result;
  271. }
  272. const std::vector<RegisterAddress> &RegisterMonitorService::addresses() const
  273. {
  274. return model_.addresses();
  275. }
  276. std::vector<MonitorValue> RegisterMonitorService::values(bool communication_fault) const
  277. {
  278. std::vector<MonitorValue> result;
  279. result.reserve(model_.points().size());
  280. for (const MonitorPoint &point : model_.points())
  281. {
  282. const RegisterAddress &address = point.address;
  283. MonitorValue value;
  284. value.address = address;
  285. value.dataType = point.dataType;
  286. value.endAddress = address.index()
  287. + registerDataTypeWordCount(point.dataType) - 1;
  288. if (address.area() == RegisterArea::M)
  289. {
  290. const BitReadResult read = repository_.readBit(address);
  291. value.bitValue = read.value;
  292. value.state = read.succeeded
  293. ? (communication_fault ? MonitorValueState::CommunicationFault
  294. : MonitorValueState::Valid)
  295. : MonitorValueState::Unavailable;
  296. }
  297. else
  298. {
  299. const WordsReadResult read = repository_.readWords(
  300. address, registerDataTypeWordCount(point.dataType));
  301. const std::optional<RegisterNumericValue> decoded = read.succeeded
  302. ? decodeRegisterNumericValue(point.dataType, read.values)
  303. : std::nullopt;
  304. if (decoded.has_value())
  305. {
  306. value.numericValue = *decoded;
  307. }
  308. value.state = decoded.has_value()
  309. ? (communication_fault ? MonitorValueState::CommunicationFault
  310. : MonitorValueState::Valid)
  311. : MonitorValueState::Unavailable;
  312. }
  313. result.push_back(value);
  314. }
  315. return result;
  316. }
  317. const std::vector<MonitorPoint> &RegisterMonitorService::points() const
  318. {
  319. return model_.points();
  320. }
  321. std::vector<RegisterAddress> RegisterMonitorService::pollAddresses() const
  322. {
  323. return pollAddressesForPoints(model_.points());
  324. }
  325. std::vector<RegisterAddress> RegisterMonitorService::pollAddressesForPoints(
  326. const std::vector<MonitorPoint> &points)
  327. {
  328. std::vector<RegisterAddress> result;
  329. for (const MonitorPoint &point : points)
  330. {
  331. for (int offset = 0; offset < registerDataTypeWordCount(point.dataType); ++offset)
  332. {
  333. result.push_back(RegisterAddress{
  334. point.address.area(), point.address.index() + offset});
  335. }
  336. }
  337. return result;
  338. }
  339. std::vector<RegisterWordRange> RegisterMonitorService::multiWordRanges() const
  340. {
  341. return multiWordRangesForPoints(model_.points());
  342. }
  343. std::vector<RegisterWordRange> RegisterMonitorService::multiWordRangesForPoints(
  344. const std::vector<MonitorPoint> &points)
  345. {
  346. std::vector<RegisterWordRange> result;
  347. for (const MonitorPoint &point : points)
  348. {
  349. const int word_count = registerDataTypeWordCount(point.dataType);
  350. if (point.address.area() == RegisterArea::D && word_count > 1)
  351. {
  352. result.push_back({point.address, word_count});
  353. }
  354. }
  355. return result;
  356. }
  357. void RegisterMonitorService::setAddressesChangedCallback(std::function<void()> callback)
  358. {
  359. addresses_changed_callback_ = std::move(callback);
  360. }
  361. void RegisterMonitorService::setPollConfigurationValidator(
  362. std::function<std::string(
  363. const std::vector<RegisterAddress> &,
  364. const std::vector<RegisterWordRange> &)> validator)
  365. {
  366. poll_configuration_validator_ = std::move(validator);
  367. }