#include "pch.h"
|
#include "PLCSignalListener.h"
|
|
// === ÈÕÖ¾´òÓ¡ÀàÐÍ ===
|
#define LOG_TYPE_ERROR -1
|
#define LOG_TYPE_SUCCESS 0
|
#define LOG_TYPE_WARNING 1
|
#define LOG_TYPE_NORMAL 2
|
|
// === PLC ¿ØÖÆÃüÁîÊäÈëλÅäÖà ===
|
#define PLC_CMD_BIT_START 0 // PLCÃüÁîÆðʼλ£¨Í¨³£ÎªB0£©
|
#define PLC_CMD_BIT_COUNT 2 // ×ܹ²¼¸¸öÃüÁî루B0=Start, B1=Stop£©
|
|
// === PLC ÐźżàÌýÆ÷Ïà¹Øºê¶¨Òå ===
|
#define PLC_ACK_MAX_LIFE 5 // PLCÏìÓ¦ÐźÅ×î´ó±£ÁôÖÜÆÚÊý£¨Ã¿ÖÜÆÚΪ m_nIntervalMs ºÁÃ룩
|
#define PLC_ACK_BASE_BIT 10 // PLCÓ¦´ðÆðʼµØÖ·£¨B10±íʾB0µÄÓ¦´ð£»B11±íʾB1£©
|
|
// === PLCÈíÔª¼þÀàÐͺ꣨ÓÃÓÚÓ¦´ð¡¢Êý¾ÝдÈ룩===
|
#define PLC_BIT_DEVICE_TYPE DeviceType::B // λ²Ù×÷É豸ÀàÐÍ£¨ÈçM¡¢B£©
|
#define PLC_WORD_DEVICE_TYPE DeviceType::W // ×Ö²Ù×÷É豸ÀàÐÍ£¨ÈçD¡¢W£©
|
|
#define IS_RISING_EDGE(prev, curr) (!(prev) && (curr))
|
|
CPLCSignalListener::CPLCSignalListener() = default;
|
|
CPLCSignalListener::~CPLCSignalListener() {
|
Stop();
|
}
|
|
bool CPLCSignalListener::Initialize(StationIdentifier station, int nIntervalMs/* = 200*/)
|
{
|
m_pPlc = std::make_unique<CCCLinkIEControl>();
|
if (!m_pPlc) {
|
if (m_cbLog) {
|
m_cbLog(_T("PLC¿ØÖÆÆ÷³õʼ»¯Ê§°Ü£¬ÎÞ·¨´´½¨ CCCLinkIEControl ʵÀý¡£"), LOG_TYPE_ERROR);
|
}
|
return false;
|
}
|
|
int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
|
if (ret != 0) {
|
m_bConnected = false;
|
if (m_cbLog) {
|
CString strError;
|
strError.Format(_T("PLC¿ØÖÆÆ÷Á¬½Óʧ°Ü£¬´íÎóÂ룺%d"), ret);
|
m_cbLog(strError, LOG_TYPE_ERROR);
|
}
|
return false;
|
}
|
|
m_bConnected = true;
|
m_station = station;
|
m_nIntervalMs = nIntervalMs;
|
|
m_vecPrevBits.assign(PLC_CMD_BIT_COUNT, false);
|
|
return true;
|
}
|
|
void CPLCSignalListener::SetStartCallback(Callback cb)
|
{
|
m_cbStart = std::move(cb);
|
}
|
|
void CPLCSignalListener::SetStopCallback(Callback cb)
|
{
|
m_cbStop = std::move(cb);
|
}
|
|
void CPLCSignalListener::SetAnalyzeCallback(AnalyzeCallback cb)
|
{
|
m_cbAnalyze = std::move(cb);
|
}
|
|
void CPLCSignalListener::SetLogCallback(LogCallback cb)
|
{
|
m_cbLog = std::move(cb);
|
}
|
|
bool CPLCSignalListener::Start()
|
{
|
if (m_bRunning || !m_pPlc) {
|
if (m_cbLog) {
|
m_cbLog(_T("PLCÐźżàÌýÆ÷ÒÑÔÚÔËÐлòPLC¿ØÖÆÆ÷δ³õʼ»¯¡£"), LOG_TYPE_ERROR);
|
}
|
return false;
|
}
|
|
m_bRunning = true;
|
m_thread = std::thread(&CPLCSignalListener::ThreadProc, this);
|
return true;
|
}
|
|
void CPLCSignalListener::Stop()
|
{
|
m_bRunning = false;
|
if (m_thread.joinable()) {
|
m_thread.join();
|
}
|
}
|
|
void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, short nBitNo, int nDelayMs/* = 50*/)
|
{
|
m_pPlc->SetBitDevice(m_station, eDevType, nBitNo);
|
::Sleep(nDelayMs);
|
m_pPlc->ResetBitDevice(m_station, eDevType, nBitNo);
|
}
|
|
void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit)
|
{
|
if (m_vecAckSent[i] && !bCurrTriggerBit) {
|
m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
|
m_vecAckSent[i] = false;
|
}
|
|
if (m_vecAckSent[i]) {
|
if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) {
|
m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
|
m_vecAckSent[i] = false;
|
}
|
}
|
}
|
|
void CPLCSignalListener::ThreadProc()
|
{
|
while (m_bRunning) {
|
BitContainer vecBits;
|
int ret = m_pPlc->ReadBitData(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
|
if (ret != 0/*&& vecBits.size() != PLC_CMD_BIT_COUNT*/) {
|
::Sleep(m_nIntervalMs);
|
|
if (m_cbLog) {
|
CString strError;
|
strError.Format(_T("PLC¶ÁȡλÊý¾Ýʧ°Ü£¬´íÎóÂ룺%d"), ret);
|
m_cbLog(strError, LOG_TYPE_ERROR);
|
}
|
|
continue;
|
}
|
|
for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) {
|
if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) {
|
// ÉÏÉýÑØ´¥·¢
|
switch (i) {
|
case 0:
|
if (m_cbStart) {
|
m_cbStart();
|
WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 });
|
if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
|
m_vecAckSent[i] = true;
|
m_vecAckCounter[i] = 0;
|
}
|
}
|
break;
|
|
case 1:
|
if (m_cbStop) {
|
m_cbStop();
|
if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
|
m_vecAckSent[i] = true;
|
m_vecAckCounter[i] = 0;
|
}
|
}
|
|
if (m_cbAnalyze) {
|
auto results = m_cbAnalyze();
|
WriteOutValues(results);
|
}
|
break;
|
}
|
}
|
|
HandleAckLife(i, vecBits[i]);
|
m_vecPrevBits[i] = vecBits[i];
|
}
|
|
::Sleep(m_nIntervalMs);
|
}
|
}
|
|
bool CPLCSignalListener::WriteOutValues(const OutValuesArray& values)
|
{
|
if (!m_pPlc) {
|
if (m_cbLog) {
|
m_cbLog(_T("PLC¿ØÖÆÆ÷δ³õʼ»¯£¬ÎÞ·¨Ð´ÈëÊä³öÖµ¡£"), LOG_TYPE_ERROR);
|
}
|
return false;
|
}
|
|
static const short PLC_RESULT_ADDR[4] = { 100, 102, 104, 106 };
|
|
for (int i = 0; i < 4; ++i) {
|
uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0));
|
WordContainer vec = { nScaled };
|
|
int ret = m_pPlc->WriteWordData(m_station, PLC_WORD_DEVICE_TYPE, PLC_RESULT_ADDR[i], vec);
|
if (ret != 0) {
|
return false;
|
}
|
}
|
|
return true;
|
}
|