Pārlūkot izejas kodu

为PSG-HD增加MAS模式

lwk 14 stundas atpakaļ
vecāks
revīzija
55b31aba6c

+ 304 - 20
Generator/PSG/CCOS.Dev.Generator.PSG_HD/CCOS.Dev.Generator.PSG_HD.cpp

@@ -3,11 +3,15 @@
 #include <assert.h>
 #include <functional>
 #include <unordered_map>
-#include <fstream>  
+#include <fstream>
+#include <sstream>
+#include <iomanip>
 #include <cmath>
+#include <cfloat>
 #include <climits>
 #include <unordered_set>
 #include <algorithm>
+#include <vector>
 #include "LogicDevice.h"
 using namespace std::placeholders;
 #include "LogLocalHelper.h"       
@@ -81,7 +85,7 @@ static std::list <tFrameMapping> arFrame;
 
 static bool DecodeFrame(const char* data, int len) {
 	if (!data || len < 8) {
-		FINFO("DecodeFrame: Invalid input");
+		FINFO("Invalid input");
 		return false;
 	}
 
@@ -91,7 +95,7 @@ static bool DecodeFrame(const char* data, int len) {
 	while (pos < len) {
 		while (pos < len && (uint8_t)data[pos] != STX) pos++;
 		if (pos >= len) {
-			FINFO("DecodeFrame: No STX found");
+			FINFO("No STX found");
 			break;
 		}
 		int start = pos;
@@ -104,7 +108,16 @@ static bool DecodeFrame(const char* data, int len) {
 			}
 		}
 		if (end == -1) {
-			FINFO("DecodeFrame: Incomplete cmd (no CRLF)");
+			// 打印不完整的命令内容
+			int incompleteLen = len - start;
+			std::string incompleteCmd(data + start, incompleteLen);
+			std::stringstream hexStr;
+			hexStr << "Incomplete cmd (hex): ";
+			for (int i = 0; i < incompleteLen; i++) {
+				hexStr << std::hex << std::setw(2) << std::setfill('0')
+					   << (int)(uint8_t)data[start + i] << " ";
+			}
+			FINFO("Incomplete cmd (no CRLF), content: [{$}], {$}", incompleteCmd, hexStr.str());
 			break;
 		}
 		int cmdLen = end - start + 1;
@@ -130,12 +143,23 @@ static bool DecodeFrame(const char* data, int len) {
 			}
 			if (argEnd > argStart) {
 				it->fun(data + argStart, argEnd - argStart);
-				FINFO("DecodeFrame: Parsed cmd: [{$}], ARG len: {$}", it->strHead, argEnd - argStart);
+				FINFO("Parsed cmd: [{$}], ARG len: {$}", it->strHead, argEnd - argStart);
 				hasValid = true;
 			}
-			else FINFO("DecodeFrame: Cmd missing ';'");
+			else FINFO("Cmd missing ';'");
+		}
+		else {
+			// 打印不符合协议的字段内容
+			std::string unknownCmd(data + start, cmdLen);
+			// 将不可打印字符转换为十六进制显示
+			std::stringstream hexStr;
+			hexStr << "Unknown field (hex): ";
+			for (int i = 0; i < cmdLen; i++) {
+				hexStr << std::hex << std::setw(2) << std::setfill('0')
+					   << (int)(uint8_t)data[start + i] << " ";
+			}
+			FINFO("No matching header, content: [{$}], {$}", unknownCmd, hexStr.str());
 		}
-		else FINFO("DecodeFrame: No matching header");
 
 		pos = end + 1; // Next cmd start
 	}
@@ -273,21 +297,25 @@ void nsGEN::PSGHDDevice::Register()
 
 RET_STATUS nsGEN::PSGHDDevice::IncKV()
 {
-	FINFO("Enter PSGHDDevice::IncKV()\n");
+	FINFO("IncKV called, current value: {$}", m_DoseUnit.m_KV->Get());
 	if (!m_DoseUnit.m_KV->CanInc())  return RET_STATUS::RET_SUCCEED;
 	m_DoseUnit.m_KV->Inc();
+	FINFO("IncKV: new value: {$}", m_DoseUnit.m_KV->Get());
 	return SetKV(m_DoseUnit.m_KV->Get());
 }
 
 RET_STATUS nsGEN::PSGHDDevice::DecKV()
 {
+	FINFO("DecKV called, current value: {$}", m_DoseUnit.m_KV->Get());
 	if (!m_DoseUnit.m_KV->CanDec())  return RET_STATUS::RET_SUCCEED;
 	m_DoseUnit.m_KV->Dec();
+	FINFO("DecKV: new value: {$}", m_DoseUnit.m_KV->Get());
 	return SetKV(m_DoseUnit.m_KV->Get());
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetKV(float value)
 {
+	FINFO("SetKV called with value: {$}", value);
 	if (!m_DoseUnit.m_KV->Verify(value)) return RET_STATUS::RET_SUCCEED;
 
 	char temp[50] = { 0 };
@@ -300,6 +328,7 @@ RET_STATUS nsGEN::PSGHDDevice::SetKV(float value)
 RET_STATUS nsGEN::PSGHDDevice::IncMA()
 {
 	float currentMA = m_DoseUnit.m_MA->Get();
+	FINFO("IncMA called, current value: {$}", currentMA);
 
 	// 查找当前值在档位中的位置
 	size_t currentIndex = maStepCount;
@@ -311,15 +340,18 @@ RET_STATUS nsGEN::PSGHDDevice::IncMA()
 	}
 
 	if (currentIndex >= maStepCount - 1) {
+		FINFO("IncMA: already at maximum");
 		return RET_STATUS::RET_SUCCEED;  // 已经是最大值
 	}
 
+	FINFO("IncMA: new value: {$}", maSteps[currentIndex + 1]);
 	return SetMA(maSteps[currentIndex + 1]);
 }
 
 RET_STATUS nsGEN::PSGHDDevice::DecMA()
 {
 	float currentMA = m_DoseUnit.m_MA->Get();
+	FINFO("DecMA called, current value: {$}", currentMA);
 
 	// 查找当前值在档位中的位置
 	size_t currentIndex = maStepCount;
@@ -331,14 +363,17 @@ RET_STATUS nsGEN::PSGHDDevice::DecMA()
 	}
 
 	if (currentIndex == 0 || currentIndex >= maStepCount) {
+		FINFO("DecMA: already at minimum or invalid");
 		return RET_STATUS::RET_SUCCEED;  // 已经是最小值或无效值
 	}
 
+	FINFO("DecMA: new value: {$}", maSteps[currentIndex - 1]);
 	return SetMA(maSteps[currentIndex - 1]);
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetMA(float value)
 {
+	FINFO("SetMA called with value: {$}", value);
 	// 找到最接近的合法档位值
 	size_t closestIndex = 0;
 	float minDiff = fabsf(maSteps[0] - value);
@@ -354,12 +389,14 @@ RET_STATUS nsGEN::PSGHDDevice::SetMA(float value)
 	// 转换为协议单位并发送命令
 	char command[50] = { 0 };
 	snprintf(command, sizeof(command), "IREF %04d", (int)(maSteps[closestIndex] * 100));
+	FINFO("SetMA: closest valid value: {$}", maSteps[closestIndex]);
 	return HWSend(command, strlen(command));
 }
 
 RET_STATUS nsGEN::PSGHDDevice::IncMS()
 {
 	float currentMS = m_DoseUnit.m_MS->Get();
+	FINFO("IncMS called, current value: {$}", currentMS);
 
 	// 查找当前值在档位中的位置
 	size_t currentIndex = msStepCount;
@@ -371,15 +408,18 @@ RET_STATUS nsGEN::PSGHDDevice::IncMS()
 	}
 
 	if (currentIndex >= msStepCount - 1) {
+		FINFO("IncMS: already at maximum");
 		return RET_STATUS::RET_SUCCEED;  // 已经是最大值
 	}
 
+	FINFO("IncMS: new value: {$}", msSteps[currentIndex + 1]);
 	return SetMS(msSteps[currentIndex + 1]);
 }
 
 RET_STATUS nsGEN::PSGHDDevice::DecMS()
 {
 	float currentMS = m_DoseUnit.m_MS->Get();
+	FINFO("DecMS called, current value: {$}", currentMS);
 
 	// 查找当前值在档位中的位置
 	size_t currentIndex = msStepCount;
@@ -391,14 +431,17 @@ RET_STATUS nsGEN::PSGHDDevice::DecMS()
 	}
 
 	if (currentIndex == 0 || currentIndex >= msStepCount) {
+		FINFO("DecMS: already at minimum or invalid");
 		return RET_STATUS::RET_SUCCEED;  // 已经是最小值或无效值
 	}
 
+	FINFO("DecMS: new value: {$}", msSteps[currentIndex - 1]);
 	return SetMS(msSteps[currentIndex - 1]);
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetMS(float value)
 {
+	FINFO("SetMS called with value: {$}", value);
 	// 找到最接近的合法档位值
 	size_t closestIndex = 0;
 	float minDiff = fabsf(msSteps[0] - value);
@@ -414,31 +457,170 @@ RET_STATUS nsGEN::PSGHDDevice::SetMS(float value)
 	// 发送命令
 	char command[50] = { 0 };
 	snprintf(command, sizeof(command), "SMS %07d", static_cast<int>(msSteps[closestIndex] * 100));
+	FINFO("SetMS: closest valid value: {$}", msSteps[closestIndex]);
 	return HWSend(command, strlen(command));
 }
 
 RET_STATUS nsGEN::PSGHDDevice::IncMAS()
 {
-	return RET_STATUS::RET_SUCCEED;
+	// 获取当前MA和MS值,计算当前MAS
+	float currentMA = m_DoseUnit.m_MA->Get();
+	float currentMS = m_DoseUnit.m_MS->Get();
+	float currentMAS = currentMA * currentMS / 1000.0f;
+	FINFO("IncMAS called, current MAS: {$} (MA={$}, MS={$})", currentMAS, currentMA, currentMS);
+
+	// 生成所有可能的MAS值并排序
+	std::vector<float> possibleMAS;
+	for (size_t i = 0; i < maStepCount; ++i) {
+		for (size_t j = 0; j < msStepCount; ++j) {
+			float mas = maSteps[i] * msSteps[j] / 1000.0f;
+			possibleMAS.push_back(mas);
+		}
+	}
+
+	// 排序并去重
+	std::sort(possibleMAS.begin(), possibleMAS.end());
+	possibleMAS.erase(std::unique(possibleMAS.begin(), possibleMAS.end(),
+		[](float a, float b) { return fabsf(a - b) < 1e-6f; }), possibleMAS.end());
+
+	// 找到比当前值大的最小MAS值
+	for (size_t i = 0; i < possibleMAS.size(); ++i) {
+		if (possibleMAS[i] > currentMAS + 1e-6f) {
+			FINFO("IncMAS: new MAS: {$}", possibleMAS[i]);
+			return SetMAS(possibleMAS[i]);
+		}
+	}
+
+	FINFO("IncMAS: already at maximum");
+	return RET_STATUS::RET_SUCCEED;  // 已经是最大值
 }
 
 RET_STATUS nsGEN::PSGHDDevice::DecMAS()
 {
-	return RET_STATUS::RET_SUCCEED;
+	// 获取当前MA和MS值,计算当前MAS
+	float currentMA = m_DoseUnit.m_MA->Get();
+	float currentMS = m_DoseUnit.m_MS->Get();
+	float currentMAS = currentMA * currentMS / 1000.0f;
+	FINFO("DecMAS called, current MAS: {$} (MA={$}, MS={$})", currentMAS, currentMA, currentMS);
+
+	// 生成所有可能的MAS值并排序
+	std::vector<float> possibleMAS;
+	for (size_t i = 0; i < maStepCount; ++i) {
+		for (size_t j = 0; j < msStepCount; ++j) {
+			float mas = maSteps[i] * msSteps[j] / 1000.0f;
+			possibleMAS.push_back(mas);
+		}
+	}
+
+	// 排序并去重
+	std::sort(possibleMAS.begin(), possibleMAS.end());
+	possibleMAS.erase(std::unique(possibleMAS.begin(), possibleMAS.end(),
+		[](float a, float b) { return fabsf(a - b) < 1e-6f; }), possibleMAS.end());
+
+	// 找到比当前值小的最大MAS值(从后往前找)
+	for (int i = possibleMAS.size() - 1; i >= 0; --i) {
+		if (possibleMAS[i] < currentMAS - 1e-6f) {
+			FINFO("DecMAS: new MAS: {$}", possibleMAS[i]);
+			return SetMAS(possibleMAS[i]);
+		}
+	}
+
+	FINFO("DecMAS: already at minimum");
+	return RET_STATUS::RET_SUCCEED;  // 已经是最小值
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetMAS(float value)
 {
+	FINFO("SetMAS called with value: {$}", value);
+	// MAS = MA * MS / 1000.0
+	// 需要找到最合适的MA和MS组合来达到目标MAS值
+	if (m_DoseUnit.m_Techmode->Get() == AttrKey::TECHMODE_TYPE::TECHMODE_NOAEC_3P ||
+		m_DoseUnit.m_Techmode->Get() == AttrKey::TECHMODE_TYPE::TECHMODE_AEC_3P)
+	{
+		FINFO("Techmode is 3Point, Cannot set MAS \n");
+		return RET_STATUS::RET_FAILED;
+	}
+	float targetMAS = value;
+	float bestMA = maSteps[0];
+	float bestMS = msSteps[0];
+	float minError = FLT_MAX;
+
+	// 遍历所有可能的MA和MS组合,找到最接近目标MAS的组合
+	for (size_t i = 0; i < maStepCount; ++i) {
+		for (size_t j = 0; j < msStepCount; ++j) {
+			float calculatedMAS = maSteps[i] * msSteps[j] / 1000.0f;
+			float error = fabsf(calculatedMAS - targetMAS);
+
+			if (error < minError) {
+				minError = error;
+				bestMA = maSteps[i];
+				bestMS = msSteps[j];
+			}
+		}
+	}
+
+	FINFO("SetMAS: calculated best MA={$}, MS={$}, actual MAS={$}", bestMA, bestMS, bestMA * bestMS / 1000.0f);
+
+	// 依次设置MA和MS
+	RET_STATUS ret = SetMA(bestMA);
+	if (ret != RET_STATUS::RET_SUCCEED) {
+		return ret;
+	}
+
+	ret = SetMS(bestMS);
+	if (ret != RET_STATUS::RET_SUCCEED) {
+		return ret;
+	}
+
+	//// 更新MAS值
+	//float actualMAS = bestMA * bestMS / 1000.0f;
+	//m_DoseUnit.m_MAS->Update(actualMAS);
+
 	return RET_STATUS::RET_SUCCEED;
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetTechmode(int value)
 {
+	FINFO("SetTechmode called with value: {$}", value);
+	if (!m_DoseUnit.m_Techmode->Verify(value))  return RET_STATUS::RET_SUCCEED;
+	m_DoseUnit.m_Techmode->Update(value);
+	FireNotify(m_DoseUnit.m_Techmode->GetKey(), m_DoseUnit.m_Techmode->JSGet());
+	switch (value)
+	{
+	case AttrKey::TECHMODE_TYPE::TECHMODE_NOAEC_3P:
+	{
+		FireNotify(m_DoseUnit.m_MA->GetKey(), m_DoseUnit.m_MA->JSGet());
+		FireNotify(m_DoseUnit.m_MS->GetKey(), m_DoseUnit.m_MS->JSGet());
+	}
+	break;
+	case AttrKey::TECHMODE_TYPE::TECHMODE_NOAEC_2P:
+	{
+		FireNotify(m_DoseUnit.m_MA->GetKey(), "0");
+		FireNotify(m_DoseUnit.m_MS->GetKey(), "0");
+		FireNotify(m_DoseUnit.m_MAS->GetKey(), m_DoseUnit.m_MAS->JSGet());
+	}
+	break;
+	case AttrKey::TECHMODE_TYPE::TECHMODE_AEC_3P:
+	{
+		FireNotify(m_DoseUnit.m_MA->GetKey(), m_DoseUnit.m_MA->JSGet());
+		FireNotify(m_DoseUnit.m_MS->GetKey(), m_DoseUnit.m_MS->JSGet());
+	}
+	break;
+	case AttrKey::TECHMODE_TYPE::TECHMODE_AEC_2P:
+	{
+		FireNotify(m_DoseUnit.m_MA->GetKey(), "0");
+		FireNotify(m_DoseUnit.m_MS->GetKey(), "0");
+		FireNotify(m_DoseUnit.m_MAS->GetKey(), m_DoseUnit.m_MAS->JSGet());
+	}
+	break;
+
+	}
 	return RET_STATUS::RET_SUCCEED;
 }
 
 RET_STATUS nsGEN::PSGHDDevice::SetEXAMMode(std::string value)
 {
+	FINFO("SetEXAMMode called with value: {$}", value);
 	return RET_STATUS::RET_SUCCEED;
 }
 
@@ -449,9 +631,44 @@ RET_STATUS nsGEN::PSGHDDevice::SetAPR(const _tAPRArgs& t)
 
 	SetKV(t.fKV);
 	Sleep(50);
-	SetMA(t.fMA);
-	Sleep(80);
-	SetMS(t.fMS);
+	if (t.nTechmode == AttrKey::TECHMODE_V2TYPE::ET_AEC)
+	{
+		// aec 
+		m_DoseUnit.m_Techmode->Update(t.nTechmode);
+		FireNotify(m_DoseUnit.m_Techmode->GetKey(), m_DoseUnit.m_Techmode->JSGet());
+		Sleep(50);
+		SetMA(t.fMA);
+		Sleep(50);
+		SetMS(t.fMS);
+	}
+	else if (t.nTechmode == AttrKey::TECHMODE_V2TYPE::ET_MAS)
+	{
+		// mas
+		m_DoseUnit.m_Techmode->Update(t.nTechmode);
+		FireNotify(m_DoseUnit.m_Techmode->GetKey(), m_DoseUnit.m_Techmode->JSGet());
+		Sleep(50);
+
+		const float EPSINON = 0.000001;
+
+		if ((t.fMAS >= -EPSINON) && (t.fMAS <= EPSINON))
+		{
+			SetMAS(t.fMA * t.fMS / 1000);
+		}
+		else
+		{
+			SetMAS(t.fMAS);
+		}
+	}
+	else if (t.nTechmode == AttrKey::TECHMODE_V2TYPE::ET_TIME)
+	{
+		// time
+		m_DoseUnit.m_Techmode->Update(t.nTechmode);
+		FireNotify(m_DoseUnit.m_Techmode->GetKey(), m_DoseUnit.m_Techmode->JSGet());
+		Sleep(50);
+		SetMA(t.fMA);
+		Sleep(80);
+		SetMS(t.fMS);
+	}
 
 	m_bGenBusy = false;
 	return RET_STATUS::RET_SUCCEED;
@@ -467,6 +684,7 @@ RET_STATUS nsGEN::PSGHDDevice::RefreshData()
 
 RET_STATUS nsGEN::PSGHDDevice::SetFocus(int value)
 {
+	FINFO("SetFocus called with value: {$}", value);
 	if (!m_DoseUnit.m_Focus->Verify(value)) return RET_STATUS::RET_SUCCEED;
 
 	return RET_STATUS::RET_SUCCEED;
@@ -501,6 +719,7 @@ RET_STATUS nsGEN::PSGHDDevice::SetCollimatorLight(unsigned short value)
 
 RET_STATUS nsGEN::PSGHDDevice::SetDeviceSleepState(const int value)
 {
+	FINFO("SetDeviceSleepState called with value: {$}", value);
 	m_bSleepState = (bool)value;
 	FINFO("Attempting to set device sleep state: {$}({$})",
 		value, m_bSleepState ? "sleeping" : "awake");
@@ -518,8 +737,9 @@ void nsGEN::PSGHDDevice::SubscribeSelf(ccos_mqtt_connection* conn)
 		//SubscribeTopic(conn, "CCOS/DEVICE/Generator/Action/#"); Moduld层默认订阅了这个Action,如果这边也订阅的话就会执行两遍Action,可能会出问题
 }
 
-RET_STATUS nsGEN::PSGHDDevice::SetAECDensity(int value) 
+RET_STATUS nsGEN::PSGHDDevice::SetAECDensity(int value)
 {
+	FINFO("SetAECDensity called with value: {$}", value);
 	if (!m_DoseUnit.m_AECDensity->Verify(value)) return RET_STATUS::RET_SUCCEED;
 	if (m_DoseUnit.m_Techmode->Get() == AttrKey::TECHMODE_V2TYPE::ET_AEC) return RET_STATUS::RET_FAILED;
 
@@ -561,8 +781,9 @@ RET_STATUS nsGEN::PSGHDDevice::SetAECDensity(int value)
 
 	return HWSend(temp, strlen(temp));
 }
-RET_STATUS nsGEN::PSGHDDevice::SetAECField(int value) 
+RET_STATUS nsGEN::PSGHDDevice::SetAECField(int value)
 {
+	FINFO("SetAECField called with value: {$}", value);
 	if (!m_DoseUnit.m_AECField->Verify(value))  return RET_STATUS::RET_SUCCEED;
 	if (m_DoseUnit.m_Techmode->Get() == AttrKey::TECHMODE_V2TYPE::ET_MAS)	return RET_STATUS::RET_FAILED;
 	m_DoseUnit.m_AECField->Update(value);
@@ -572,6 +793,7 @@ RET_STATUS nsGEN::PSGHDDevice::SetAECField(int value)
 }
 RET_STATUS nsGEN::PSGHDDevice::SetAECFilm(int value)
 {
+	FINFO("SetAECFilm called with value: {$}", value);
 	if (!m_DoseUnit.m_AECFilm->Verify(value))  return RET_STATUS::RET_SUCCEED;
 
 	if (m_DoseUnit.m_Techmode->Get() == AttrKey::TECHMODE_V2TYPE::ET_MAS)	return RET_STATUS::RET_FAILED;
@@ -581,7 +803,7 @@ RET_STATUS nsGEN::PSGHDDevice::SetAECFilm(int value)
 
 	return HWSend(temp, strlen(temp));
 }
-RET_STATUS  nsGEN::PSGHDDevice::SetWS(const string value) 
+RET_STATUS nsGEN::PSGHDDevice::SetWS(const string value) 
 {
 	FINFO("Enter SetWS {$}", value);
 	int tempws = 0;
@@ -652,17 +874,18 @@ RET_STATUS nsGEN::PSGHDDevice::SetExpMode(std::string value)
 }
 RET_STATUS nsGEN::PSGHDDevice::SetFrameRate(float frameRate)
 {
+	FINFO("SetFrameRate called with value: {$}", frameRate);
 	return RET_STATUS::RET_SUCCEED;
 }
 RET_STATUS nsGEN::PSGHDDevice::SetExpEnable() 
 {
 	FINFO("SetExpEnable in\n");
-	return HWSend("DSW 1", 5);
+	return HWSend("DSW 0", 5);
 }
 RET_STATUS nsGEN::PSGHDDevice::SetExpDisable() 
 {
 	FINFO("SetExpDisable in\n");
-	return HWSend("DSW 0", 5);
+	return HWSend("DSW 1", 5);
 }
 
 RET_STATUS nsGEN::PSGHDDevice::PrepareAcquisition()
@@ -685,12 +908,22 @@ RET_STATUS nsGEN::PSGHDDevice::HWSend(const char* strCommand, int length, bool r
 {
 	if (!m_SCF) {
 		FINFO("Failed - Serial communication interface not initialized");
+		if (m_DoseUnit.m_GenState->Update(nsGEN::AttrKey::GENERATOR_STATUS_SHUTDOWN))
+		{
+			FireNotify(AttrKey::GENSTATE, m_DoseUnit.m_GenState->JSGet());
+			FINFO("Generator status updated to {$}", static_cast<int>(nsGEN::AttrKey::GENERATOR_STATUS_SHUTDOWN));
+		}
 		return RET_STATUS::RET_FAILED;
 	}
 
 	if (!m_SCF->IsConnected())
 	{
-		FINFO("Failed - Device not connected");
+		FERROR("Failed - Device not connected");
+		if (m_DoseUnit.m_GenState->Update(nsGEN::AttrKey::GENERATOR_STATUS_SHUTDOWN))
+		{
+			FireNotify(AttrKey::GENSTATE, m_DoseUnit.m_GenState->JSGet());
+			FINFO("Generator status updated to {$}", static_cast<int>(nsGEN::AttrKey::GENERATOR_STATUS_SHUTDOWN));
+		}
 		return RET_STATUS::RET_FAILED;
 	}
 	// 构造协议格式:<STX>CMD<SP>ARG;<CS><CR><LF>
@@ -855,6 +1088,16 @@ void nsGEN::PSGHDDevice::OnCallBack()
 
 			m_DoseUnit.m_MA->Update(actualMA);
 			FireNotify(AttrKey::MA, m_DoseUnit.m_MA->JSGet());
+
+			float tempMa = m_DoseUnit.m_MA->Get();
+			float tempMs = m_DoseUnit.m_MS->Get();
+			float tempMAS = tempMa * tempMs / 1000.0f;
+			if (tempMAS > 0)
+			{
+				m_DoseUnit.m_MAS->Update(tempMAS);
+				FireNotify(AttrKey::MAS, m_DoseUnit.m_MAS->JSGet());
+			}
+
 			FINFO("HWIREF: Parsed actual MA = {$} mA", actualMA);
 		};
 
@@ -921,6 +1164,15 @@ void nsGEN::PSGHDDevice::OnCallBack()
 
 			m_DoseUnit.m_MS->Update(exposureTime);
 			FireNotify(AttrKey::MS, m_DoseUnit.m_MS->JSGet());
+			float tempMa = m_DoseUnit.m_MA->Get();
+			float tempMs = m_DoseUnit.m_MS->Get();
+			float tempMAS = tempMa * tempMs / 1000.0f;
+			if (tempMAS > 0)
+			{
+				m_DoseUnit.m_MAS->Update(tempMAS);
+				FireNotify(AttrKey::MAS, m_DoseUnit.m_MAS->JSGet());
+			}
+
 			FINFO("HWSMS: Parsed exposure time = {$} ms", exposureTime);
 		};
 
@@ -1191,6 +1443,37 @@ void nsGEN::PSGHDDevice::OnCallBack()
 			}
 		};
 
+	auto HWFLP = [this](const char* data, int length) -> void
+		{
+			if (length < 1) { // 需1字节(X)
+				FINFO("HWFLP: Invalid data length ({$} < 1), skip", length);
+				return;
+			}
+
+			char flxStr[2] = { 0 };
+			strncpy(flxStr, data, 1);
+			int nValue = atoi(flxStr);
+			FINFO("HWFLP: Fluorescence mode detected = {$}", nValue);
+
+			if (nValue == 2)
+			{
+				FINFO("HWFLP: Received value 2 - No action");
+			}
+			else if (nValue == 1)
+			{
+				m_DoseUnit.m_GenSynState->Update(AttrKey::GENERATOR_RAD_PREPARE);
+				FINFO("HWFLP: Radiography prepare state - {$}", m_DoseUnit.m_GenSynState->JSGet().c_str());
+				FireNotify(m_DoseUnit.m_GenSynState->GetKey(), m_DoseUnit.m_GenSynState->JSGet());
+			}
+			else if (nValue == 0)
+			{
+				m_DoseUnit.m_GenSynState->Update(AttrKey::GENERATOR_RAD_OFF);
+				FINFO("HWFLP: Radiography off state - {$}", m_DoseUnit.m_GenSynState->JSGet().c_str());
+				FireNotify(m_DoseUnit.m_GenSynState->GetKey(), m_DoseUnit.m_GenSynState->JSGet());
+				m_bGenBusy = false;
+			}
+		};
+
 	auto HWVER = [this](const char* data, int length) -> void
 		{
 			if (length < 6) { // 需6字节(XXXXXX)
@@ -1703,7 +1986,8 @@ bool nsGEN::PSGHDDriver::isConnected() const
 
 	// 1. 连接中/实际已连接:返回true(无需重连)
 	if (state == ConnectionState::Connecting || (m_scfWrapper && m_scfWrapper->IsConnected())) {
-		FINFO(state == ConnectionState::Connecting ? "Connecting in progress" : "Already connected");
+		//FINFO(state == ConnectionState::Connecting ? "Connecting in progress" : "Al
+		// ready connected");
 		return true;
 	}
 

+ 64 - 64
Generator/PSG/CCOS.Dev.Generator.PSG_HD/CCOS.Dev.Generator.PSG_HD.h

@@ -16,29 +16,29 @@
 
 #define _CCOSDEVGENPSGHD_API __attribute__((visibility("default")))
 
-// Linux 兼容的类型定义
+// Linux 鍏煎�鐨勭被鍨嬪畾涔�
 using DWORD = unsigned long;
 using LPVOID = void*;
 using BOOL = int;
 #define TRUE 1
 #define FALSE 0
 
-// 睡眠函数(毫秒)
+// 鐫$湢鍑芥暟锛堟�绉掞級
 inline void Sleep(unsigned int milliseconds) {
 	std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
 }
 
-// 创建线程函数
+// 鍒涘缓绾跨▼鍑芥暟
 template<typename Function, typename... Args>
 std::thread CreateThread(void*, int, Function&& f, Args&&... args) {
 	return std::thread(std::forward<Function>(f), std::forward<Args>(args)...);
 }
 
-enum PSG_HD_REGULATION_LEVEL { //故障等级
+enum PSG_HD_REGULATION_LEVEL { //鏁呴殰绛夌骇
 	REG_ERRO,
 	REG_WARN
 };
-enum PSG_HD_CHARGE_STATE { //电池状态
+enum PSG_HD_CHARGE_STATE { //鐢垫睜鐘舵€�
 	POWER_LOW,
 	POWER_NOR
 };
@@ -60,7 +60,7 @@ namespace CCOS::Dev::Detail::Generator
 	public:
 		PSGHDDevice (std::shared_ptr <IOEventCenter> center, std::shared_ptr<SCFWrapper> SCF, string configfile);
 		~PSGHDDevice ();
-		//发生器支持的通用命令
+		//鍙戠敓鍣ㄦ敮鎸佺殑閫氱敤鍛戒护
 		virtual std::string GetGUID() const override;
 		virtual RET_STATUS IncKV() override;
 		virtual RET_STATUS DecKV() override;
@@ -91,7 +91,7 @@ namespace CCOS::Dev::Detail::Generator
 		virtual RET_STATUS SetCollimatorLight(unsigned short value) override;
 		virtual RET_STATUS SetDeviceSleepState(const int value) override;
 		RET_STATUS RefreshData();
-		RET_STATUS SetRPS(int rps);//设置连续点片帧率,暂不使用
+		RET_STATUS SetRPS(int rps);//璁剧疆杩炵画鐐圭墖甯х巼,鏆備笉浣跨敤
 
 
 		virtual RET_STATUS SetAECDensity(int value) override;
@@ -110,16 +110,16 @@ namespace CCOS::Dev::Detail::Generator
 		RET_STATUS StartMove();
 		RET_STATUS EndMove();
 
-		//V3新方法
+		//V3鏂版柟娉�
 		virtual void SubscribeSelf(ccos_mqtt_connection* conn) override;
 		RET_STATUS SetVibrationGrid(int value);
 		RET_STATUS GetVibrationGridMS(int &value);
 
-		void SetSmartAEC(int value); //智能AEC
-		bool ReConnect(); //重连
-		int  GridMSMargin(); //返回震动栅MS的余量
-		bool CalculateAppropriateMA(float& inoutMAS, float& inoutMA, float& inoutMS); //计算震动栅模式下恰当的MA
-		void ReSendFailedAction(string &cmdNum); //重发失败后返回消息
+		void SetSmartAEC(int value); //鏅鸿兘AEC
+		bool ReConnect(); //閲嶈繛
+		int  GridMSMargin(); //杩斿洖闇囧姩鏍匨S鐨勪綑閲�
+		bool CalculateAppropriateMA(float& inoutMAS, float& inoutMA, float& inoutMS); //璁$畻闇囧姩鏍呮ā寮忎笅鎭板綋鐨凪A
+		void ReSendFailedAction(string &cmdNum); //閲嶅彂澶辫触鍚庤繑鍥炴秷鎭�
 
 		int GetGenState();
 		int LoadConfig(string configfile);
@@ -128,24 +128,24 @@ namespace CCOS::Dev::Detail::Generator
 		ResDataObject m_GenConfig;  //driver's config file.
 		std::shared_ptr<SCFWrapper> m_SCF;
 		std::shared_ptr<IODeviceDetail> pIODriver;
-		//线程变量互斥锁
-		atomic<int> m_iReSendCMD;	                  //初始命令重发次数
-		static atomic<int>  m_iLoopTime;	          //循环间隔时间(毫秒)
-		atomic<int>         m_iCompPostMAS;	          //计算PostMAS条件统计
-		atomic<int>         m_iHeartBeats;	          //心跳统计
-		atomic<bool>        m_bConnectFlag;	          //连接标记
-		bool                m_bAECCtlSignal;	      //在曝光设置更新期间,AEC控制信号必须处于低状态
-		atomic<bool>        m_iVibrationGridState;	  //震动栅模式(0,1)
-		int                 m_iGridMSRadMargin;       //震动栅ms手动曝光误差(500-2000ms)
-		int                 m_iGridMSAECMargin;       //震动栅ms自动曝光误差(500-2000ms)
-		static atomic<bool> m_bExtraFlag;	          //使用标记
+		//绾跨▼鍙橀噺浜掓枼閿�
+		atomic<int> m_iReSendCMD;	                  //鍒濆�鍛戒护閲嶅彂娆℃暟
+		static atomic<int>  m_iLoopTime;	          //寰�幆闂撮殧鏃堕棿锛堟�绉掞級
+		atomic<int>         m_iCompPostMAS;	          //璁$畻PostMAS鏉′欢缁熻�
+		atomic<int>         m_iHeartBeats;	          //蹇冭烦缁熻�
+		atomic<bool>        m_bConnectFlag;	          //杩炴帴鏍囪�
+		bool                m_bAECCtlSignal;	      //鍦ㄦ洕鍏夎�缃�洿鏂版湡闂�,AEC鎺у埗淇″彿蹇呴』澶勪簬浣庣姸鎬�
+		atomic<bool>        m_iVibrationGridState;	  //闇囧姩鏍呮ā寮�(0,1)
+		int                 m_iGridMSRadMargin;       //闇囧姩鏍卪s鎵嬪姩鏇濆厜璇�樊(500-2000ms)
+		int                 m_iGridMSAECMargin;       //闇囧姩鏍卪s鑷�姩鏇濆厜璇�樊(500-2000ms)
+		static atomic<bool> m_bExtraFlag;	          //浣跨敤鏍囪�
 
 		atomic<bool> m_bSleepState{ false };
 		bool m_bGenBusy;
 		int m_nCtlMode;
 		bool m_bUseCECmd;
 		bool m_bIsConfigLoaded;
-		//串口处理层
+		//涓插彛澶勭悊灞�
 		int m_nCMDType_WaitTime{ 0 };
 		int m_nCMDType_HB{ 0 };
 		int m_nCMDType_WaitACK{ 0 };
@@ -155,17 +155,17 @@ namespace CCOS::Dev::Detail::Generator
 		RET_STATUS HWSendWaitACKCMD(char* strCommand, int lengh, int headLengh = 3);
 
 	private:
-		//std::unique_ptr<DevDAP::DOSEMould> m_DAP;   //暂不使用
-		std::unique_ptr<nsDetail::MSGUnit> m_MSGUnit; //处理消息上报对象指针
-		std::thread m_pHardwareStatusThread;               //轮询线程句柄
-		std::thread m_pHardwareRsSendThread;               //重发线程句柄
+		//std::unique_ptr<DevDAP::DOSEMould> m_DAP;   //鏆備笉浣跨敤
+		std::unique_ptr<nsDetail::MSGUnit> m_MSGUnit; //澶勭悊娑堟伅涓婃姤瀵硅薄鎸囬拡
+		std::thread m_pHardwareStatusThread;               //杞��绾跨▼鍙ユ焺
+		std::thread m_pHardwareRsSendThread;               //閲嶅彂绾跨▼鍙ユ焺
 		std::shared_ptr<LinuxEvent> m_hGenPostEvent;
 		bool m_isFirstHWPhase = true;
-		atomic<bool> m_bExpEnable;	                  //曝光使能
-		atomic<bool> m_bInvalidKVMASSetupFlag;        //写入到设备的曝光设置无效
-		atomic<bool> m_bFaultList[18];	              //记录 主机请求固件报告故障命令 返回的故障记录
-		int          m_iMaxPower;	                  //最大功率:kV*mA
-		int          MaxHeatContent;                  //最阳极热容积:kV*mAs
+		atomic<bool> m_bExpEnable;	                  //鏇濆厜浣胯兘
+		atomic<bool> m_bInvalidKVMASSetupFlag;        //鍐欏叆鍒拌�澶囩殑鏇濆厜璁剧疆鏃犳晥
+		atomic<bool> m_bFaultList[18];	              //璁板綍 涓绘満璇锋眰鍥轰欢鎶ュ憡鏁呴殰鍛戒护 杩斿洖鐨勬晠闅滆�褰�
+		int          m_iMaxPower;	                  //鏈€澶у姛鐜�:kV*mA
+		int          MaxHeatContent;                  //鏈€闃虫瀬鐑��绉�:kV*mAs
 		bool         m_bMAS_MA_AEC;
 		enum MyEnum
 		{
@@ -175,17 +175,17 @@ namespace CCOS::Dev::Detail::Generator
 		};
 
 	private:
-		RET_STATUS  HWSend(const char* strCommand, int lengh, bool reSend = false, int nTimeOut = TIMEOUTVALUE); //指令发送接口
-		void OnCallBack(); //处理指令回调函数
-		void Register(); //注册对外提供的属性、方法
-		bool StartHardwareStatusThread();				//启动轮询线程
-		static void HardwareStatusThread(PSGHDDevice* pParam); //定时查询状态信息
-		static void HardwareReSendThread(PSGHDDevice* pParam); //指令重发
-		void FireNotify(std::string key, int context);//向上层上报消息
+		RET_STATUS  HWSend(const char* strCommand, int lengh, bool reSend = false, int nTimeOut = TIMEOUTVALUE); //鎸囦护鍙戦€佹帴鍙�
+		void OnCallBack(); //澶勭悊鎸囦护鍥炶皟鍑芥暟
+		void Register(); //娉ㄥ唽瀵瑰�鎻愪緵鐨勫睘鎬с€佹柟娉�
+		bool StartHardwareStatusThread();				//鍚�姩杞��绾跨▼
+		static void HardwareStatusThread(PSGHDDevice* pParam); //瀹氭椂鏌ヨ�鐘舵€佷俊鎭�
+		static void HardwareReSendThread(PSGHDDevice* pParam); //鎸囦护閲嶅彂
+		void FireNotify(std::string key, int context);//鍚戜笂灞備笂鎶ユ秷鎭�
 		void FireNotify(std::string key, float context);
 		void FireNotify(std::string key, std::string context);
-		void FireErrorMessage(const bool Act, const int Code, const char* ResInfo = ""); //上报错误消息
-		void FireWarnMessage(const bool Act, const int Code, const char* ResInfo = ""); //上报告警消息
+		void FireErrorMessage(const bool Act, const int Code, const char* ResInfo = ""); //涓婃姤閿欒�娑堟伅
+		void FireWarnMessage(const bool Act, const int Code, const char* ResInfo = ""); //涓婃姤鍛婅�娑堟伅
 		
 	};
 
@@ -206,23 +206,23 @@ namespace CCOS::Dev::Detail::Generator
 		virtual ~PSGHDDriver ();
 
 	public:
-		//virtual bool DriverEntry (std::string CfgFileName); //设置配制文件路径,对外接口最先调用
-		virtual void Prepare () override; //在 DriverEntry 之后执行;选择与物理设备通信方式(串口、TCP)
-		virtual std::string DriverProbe() override; //在 Prepare 之后执行;读取配置文件模块参数,供上层创建驱动work路径
+		//virtual bool DriverEntry (std::string CfgFileName); //璁剧疆閰嶅埗鏂囦欢璺�緞,瀵瑰�鎺ュ彛鏈€鍏堣皟鐢�
+		virtual void Prepare () override; //鍦� DriverEntry 涔嬪悗鎵ц�;閫夋嫨涓庣墿鐞嗚�澶囬€氫俊鏂瑰紡锛堜覆鍙c€乀CP锛�
+		virtual std::string DriverProbe() override; //鍦� Prepare 涔嬪悗鎵ц�;璇诲彇閰嶇疆鏂囦欢妯″潡鍙傛暟锛屼緵涓婂眰鍒涘缓椹卞姩work璺�緞
 
 		bool ReConnection();
-		virtual bool DATA_ACTION Connect () override; //在 DriverProbe 之后执行;根据通信方式与物理设备进行连接
-		virtual auto CreateDevice(int index)->std::unique_ptr <IODevice> override; //在 Connect 之后执行;创建逻辑设备,供上层创建驱动树节点
+		virtual bool DATA_ACTION Connect () override; //鍦� DriverProbe 涔嬪悗鎵ц�;鏍规嵁閫氫俊鏂瑰紡涓庣墿鐞嗚�澶囪繘琛岃繛鎺�
+		virtual auto CreateDevice(int index)->std::unique_ptr <IODevice> override; //鍦� Connect 涔嬪悗鎵ц�;鍒涘缓閫昏緫璁惧�锛屼緵涓婂眰鍒涘缓椹卞姩鏍戣妭鐐�
 		
-		virtual bool isConnected() const override; //检查驱动与物理设备连接状态
-		virtual std::string GetResource() override; //获取配置文件的值
-		virtual std::string DeviceProbe() override; //读取配置文件模块参数,供上层创建设备work路径
+		virtual bool isConnected() const override; //妫€鏌ラ┍鍔ㄤ笌鐗╃悊璁惧�杩炴帴鐘舵€�
+		virtual std::string GetResource() override; //鑾峰彇閰嶇疆鏂囦欢鐨勫€�
+		virtual std::string DeviceProbe() override; //璇诲彇閰嶇疆鏂囦欢妯″潡鍙傛暟锛屼緵涓婂眰鍒涘缓璁惧�work璺�緞
 
-		virtual void Disconnect() override; //断开驱动与物理设备连接状态
+		virtual void Disconnect() override; //鏂�紑椹卞姩涓庣墿鐞嗚�澶囪繛鎺ョ姸鎬�
 
-		virtual void Dequeue (const char * Packet, DWORD Length) ; //在super::Connect中轮询,调用 DecodeFrame:查找指令操作对照表,通过对应操作更新数据并调用FireNotify上报更新
-		virtual void FireNotify (int code, std::string key, std::string content); //向监听者上报事件
-		static PACKET_RET callbackPackageProcess(const char* RecData, uint32_t nLength, uint32_t& PacketLength); //判断从设备读到的数据有没有可用的数据包,有则最终调度到 Dequeue
+		virtual void Dequeue (const char * Packet, DWORD Length) ; //鍦╯uper::Connect涓�疆璇�,璋冪敤 DecodeFrame:鏌ユ壘鎸囦护鎿嶄綔瀵圭収琛�,閫氳繃瀵瑰簲鎿嶄綔鏇存柊鏁版嵁骞惰皟鐢‵ireNotify涓婃姤鏇存柊
+		virtual void FireNotify (int code, std::string key, std::string content); //鍚戠洃鍚�€呬笂鎶ヤ簨浠�
+		static PACKET_RET callbackPackageProcess(const char* RecData, uint32_t nLength, uint32_t& PacketLength); //鍒ゆ柇浠庤�澶囪�鍒扮殑鏁版嵁鏈夋病鏈夊彲鐢ㄧ殑鏁版嵁鍖咃紝鏈夊垯鏈€缁堣皟搴﹀埌 Dequeue
 
 		std::shared_ptr<SCFWrapper> m_scfWrapper;
 	private:
@@ -234,8 +234,8 @@ namespace CCOS::Dev::Detail::Generator
 
 		std::string  m_SCFDllName;
 		ResDataObject m_DeviceConfig;
-		ResDataObject m_ConfigAll; //存储当前的配置,用于修改配置时写回文件
-		ResDataObject m_Configurations; //存储当前配置中“CONFIGURATION”节点的内容
+		ResDataObject m_ConfigAll; //瀛樺偍褰撳墠鐨勯厤缃�紝鐢ㄤ簬淇�敼閰嶇疆鏃跺啓鍥炴枃浠�
+		ResDataObject m_Configurations; //瀛樺偍褰撳墠閰嶇疆涓�€淐ONFIGURATION鈥濊妭鐐圭殑鍐呭�
 
 		enum class ConnectionState {
 			Disconnected,
@@ -245,8 +245,8 @@ namespace CCOS::Dev::Detail::Generator
 		};
 
 		enum class ConnectionType {
-			Serial,       // 串口
-			Ethernet      // 网口
+			Serial,       // 涓插彛
+			Ethernet      // 缃戝彛
 		};
 
 		std::atomic<ConnectionState> m_connectionState{ ConnectionState::Disconnected };
@@ -254,17 +254,17 @@ namespace CCOS::Dev::Detail::Generator
 		std::mutex m_connectionMutex;
 		const std::chrono::seconds RESET_RETRY_AFTER{ 60 };
 
-		// 修改成员变量定义,添加mutable允许const函数修改
-		mutable int m_connectionRetryCount{ 0 };  // 关键:用mutable修饰
+		// 淇�敼鎴愬憳鍙橀噺瀹氫箟锛屾坊鍔爉utable鍏佽�const鍑芥暟淇�敼
+		mutable int m_connectionRetryCount{ 0 };  // 鍏抽敭锛氱敤mutable淇�グ
 		const int MAX_RETRY_COUNT = 3;
 		const std::chrono::seconds RETRY_INTERVAL{ 5 };
 
-		// 串口相关(固定支持的端口,可从配置扩展)
+		// 涓插彛鐩稿叧锛堝浐瀹氭敮鎸佺殑绔�彛锛屽彲浠庨厤缃�墿灞曪級
 		std::vector<std::string> m_serialPorts{ "/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3", "/dev/ttyUSB4" };
-		int m_currentSerialPortIndex{ 0 };  // 当前尝试的串口端口索引
+		int m_currentSerialPortIndex{ 0 };  // 褰撳墠灏濊瘯鐨勪覆鍙g�鍙g储寮�
 		ConnectionType m_currentConnType{ ConnectionType::Serial };
 
-		//webconfig使用
+		//webconfig浣跨敤
 		ResDataObject m_DeviceConfigSend;
 		string g_strAppPath;
 		std::unique_ptr <ResDataObject> m_pAttribute;