You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

707 lines
23 KiB

  1. #include "ModbusBackend.h"
  2. #include "QBuffer"
  3. CModbusBackend::CModbusBackend(CModbusRepository *Repo)
  4. {
  5. mModbusTCPSocketHandle = 0;
  6. mDataLinkValid = false;
  7. mModbusRepo = Repo;
  8. mModbusMode = MODBUS_INVALID_MODE;
  9. mTransactionIDCounter = 0;
  10. mDeviceID = 1;//0xFF;
  11. mModbusMaxRetry = MODBUS_RETRY_MAX_COUNT;
  12. mModbusRequestTimeout = MODBUS_RETRY_DELAY;
  13. }
  14. CModbusBackend::~CModbusBackend()
  15. {
  16. }
  17. void CModbusBackend::ModbusDataReady()
  18. {
  19. CModbusTransaction Transaction;
  20. QByteArray InData = mModbusTCPSocketHandle->readAll();
  21. QBuffer FileBuffer(&InData);
  22. FileBuffer.open(QIODevice::ReadOnly);
  23. FileBuffer.seek(0);
  24. QDataStream *TransactionDataStrm = new QDataStream(&FileBuffer);
  25. *TransactionDataStrm >> Transaction.mHeader;
  26. *TransactionDataStrm >> Transaction.mPDU.mFunctionCode;
  27. Transaction.mPDU.mData = InData.right(Transaction.mHeader.mMessageLength - 2); //-2 to remove Device ID and Function Code.
  28. // qDebug("modbus data received %s",InData.toHex().data());
  29. // qDebug("Transaction ID 0x%X",Transaction.mHeader.mTransactionID);
  30. // qDebug("Message Length %d",Transaction.mHeader.mMessageLength);
  31. // qDebug("Protocol ID 0x%X",Transaction.mHeader.mProtocolID);
  32. // qDebug("Unit ID 0x%X",Transaction.mHeader.mUnitID);
  33. // qDebug("Function Code 0x%X",Transaction.mPDU.mFunctionCode);
  34. // qDebug("Data %s",Transaction.mPDU.mData.toHex().data());
  35. if(mModbusMode == MODBUS_MASTER_MODE)
  36. {
  37. AnalyzeModbusResponse(Transaction);
  38. }
  39. else if( mModbusMode == MODBUS_SLAVE_MODE)
  40. {
  41. AnalyzeModbusRequest(Transaction);
  42. }
  43. else
  44. {
  45. qDebug("Illegal modbus backend mode...");
  46. }
  47. emit ModbusRX();
  48. }
  49. void CModbusBackend::ModbusLinkDisconnected()
  50. {
  51. qDebug("Modbus link disconnected");
  52. mDataLinkValid = false;
  53. }
  54. //In client mode. This is the request from the master.
  55. int CModbusBackend::AnalyzeModbusRequest(CModbusTransaction Transaction)
  56. {
  57. if(Transaction.mHeader.mProtocolID != 0)
  58. {
  59. //Invalid protocol... what can we do?
  60. return 0;
  61. }
  62. switch(Transaction.mPDU.mFunctionCode)
  63. {
  64. case MODBUS_FCT_READ_HOLDING_REGISTERS:
  65. {
  66. bool ok = true;
  67. unsigned short StartAdress = 0;
  68. StartAdress = Transaction.mPDU.mData[0]&0xFF;
  69. StartAdress <<= 8;
  70. StartAdress += Transaction.mPDU.mData[1]&0xFF;
  71. unsigned short NbRegisters = 0;
  72. NbRegisters = Transaction.mPDU.mData[2]&0xFF;
  73. NbRegisters <<= 8;
  74. NbRegisters += Transaction.mPDU.mData[3]&0xFF;
  75. //Validate nb of registers
  76. if(NbRegisters < 1 || NbRegisters > MODBUS_MAX_NB_REGISTERS)
  77. {
  78. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
  79. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
  80. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
  81. return 0;
  82. }
  83. //Validate data range
  84. if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters))
  85. {
  86. qDebug("Reg invalid");
  87. //Send negative response
  88. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
  89. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_READ_HOLDING_REGISTERS);
  90. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_READ_HOLDING_REGISTERS);
  91. return 0;
  92. }
  93. QByteArray data = mModbusRepo->GetHRData(StartAdress,NbRegisters,&ok);
  94. // qDebug("Slave Rx Read Holding Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
  95. // qDebug("Data: %s",data.toHex().data());
  96. //The response to a HR reading needs the byte count before the data.
  97. quint8 ByteCount = data.size();
  98. data.prepend(ByteCount);
  99. SendModbusResponse(Transaction, data);
  100. //All OK
  101. break;
  102. }
  103. case MODBUS_WRITE_SINGLE_REGISTER:
  104. {
  105. unsigned short StartAdress = 0;
  106. StartAdress = Transaction.mPDU.mData[0]&0xFF;
  107. StartAdress <<= 8;
  108. StartAdress += Transaction.mPDU.mData[1]&0xFF;
  109. //Validate data range
  110. if(!mModbusRepo->IsHRValid(StartAdress,1))
  111. {
  112. qDebug("Reg invalid");
  113. //Send negative response
  114. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
  115. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_WRITE_SINGLE_REGISTER);
  116. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_WRITE_SINGLE_REGISTER);
  117. return 0;
  118. }
  119. //Extract data.
  120. QByteArray data = Transaction.mPDU.mData.right(2);
  121. //Write register data
  122. mModbusRepo->WriteHRData(StartAdress,1,data);
  123. // qDebug("Slave Rx Write Single Register. Address: %d, Value: 0x%s",StartAdress, data.toHex().data());
  124. // qDebug("Data: %s",data.toHex().data());
  125. data = Transaction.mPDU.mData.left(4); //The response corresponds to the Reg. Address & the value. Which is the first 4 bytes of the initial request.
  126. SendModbusResponse(Transaction, data);
  127. // emit RegistersDatabaseUpdated(StartAdress,1);
  128. RegistersDatabaseUpdated(StartAdress,1);
  129. break;
  130. }
  131. case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS:
  132. {
  133. unsigned short StartAdress = 0;
  134. StartAdress = Transaction.mPDU.mData[0]&0xFF;
  135. StartAdress <<= 8;
  136. StartAdress += Transaction.mPDU.mData[1]&0xFF;
  137. unsigned short NbRegisters = 0;
  138. NbRegisters = Transaction.mPDU.mData[2]&0xFF;
  139. NbRegisters <<= 8;
  140. NbRegisters += Transaction.mPDU.mData[3]&0xFF;
  141. quint8 ByteCount = Transaction.mPDU.mData[4];
  142. //Validate nb of registers
  143. if(NbRegisters < 1 || NbRegisters > 0x7D || ByteCount != (NbRegisters*2))
  144. {
  145. qDebug("Invalid register number or byte count ");
  146. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
  147. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  148. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  149. return 0;
  150. }
  151. //Validate data range
  152. if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters))
  153. {
  154. qDebug("Reg invalid");
  155. //Send negative response
  156. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
  157. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  158. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  159. return 0;
  160. }
  161. //Extract data.
  162. QByteArray data = Transaction.mPDU.mData.right(ByteCount);
  163. //Write register data
  164. mModbusRepo->WriteHRData(StartAdress,NbRegisters,data);
  165. // qDebug("Slave Rx Write Multiple Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
  166. // qDebug("Data: %s",data.toHex().data());
  167. data = Transaction.mPDU.mData.left(4); //The response corresponds to the Start Adress and Nb of Regs. Which is the first 4 bytes of the initial request.
  168. SendModbusResponse(Transaction, data);
  169. // emit RegistersDatabaseUpdated(StartAdress,NbRegisters);
  170. RegistersDatabaseUpdated(StartAdress,NbRegisters);
  171. break;
  172. }
  173. default:
  174. {
  175. //Received "Illegal function code". Send the exception code to master
  176. //TODO: Log this.
  177. qDebug("Slave received illegal function code from master: 0x%x",Transaction.mPDU.mFunctionCode);
  178. SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_FCT);
  179. // emit ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_FCT,Transaction.mPDU.mFunctionCode);
  180. ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_FCT,Transaction.mPDU.mFunctionCode);
  181. break;
  182. }
  183. }
  184. return 1;
  185. }
  186. int CModbusBackend::SendModbusResponse(CModbusTransaction RequestTransaction, QByteArray Data)
  187. {
  188. QByteArray ModbusPacket;
  189. QBuffer Buffer(&ModbusPacket);
  190. Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
  191. Buffer.seek(0);
  192. QDataStream *PacketDataStrm = new QDataStream(&Buffer);
  193. //For a response, the header will be the same as the original request, except for the msg. length.
  194. //Set the appropriate msg length.
  195. RequestTransaction.mHeader.mMessageLength = Data.size() + 2; //+2 to add function code & Unit ID.
  196. RequestTransaction.mPDU.mData = Data;
  197. *PacketDataStrm << RequestTransaction.mHeader;
  198. *PacketDataStrm << RequestTransaction.mPDU.mFunctionCode;
  199. Buffer.close();
  200. ModbusPacket.append(Data);
  201. qDebug("Response packet: %s",ModbusPacket.toHex().data());
  202. mModbusTCPSocketHandle->write(ModbusPacket);
  203. delete PacketDataStrm;
  204. return RET_OK;
  205. }
  206. //In Master mode. This is the response from slave to a previously sent request.
  207. int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction)
  208. {
  209. if(Transaction.mHeader.mProtocolID != 0)
  210. {
  211. //Invalid protocol... what can we do?
  212. return RET_ERROR;
  213. }
  214. //Find matching request and remove it from the queue...
  215. CModbusRequest *Request;
  216. bool Found = false;
  217. for(int i = 0; i < mRequestsList.size(); i++)
  218. {
  219. if(mRequestsList.at(i)->mHeader.mTransactionID == Transaction.mHeader.mTransactionID)
  220. {
  221. Request = mRequestsList.takeAt(i); //Remove from queue and keep a copy
  222. Request->mRequestTimer->stop(); //Stop the resend timer
  223. Found = true;
  224. }
  225. }
  226. if(Found == false)
  227. {
  228. //Invalid request number. This should happen only if a very long delay exists in the comm.
  229. //TODO: Log this...
  230. qDebug("Master received response to a non existent request!!!");
  231. return RET_ERROR;
  232. }
  233. //check if we have an exception response
  234. if((Transaction.mPDU.mFunctionCode & MODBUS_EXCEPTION_FCT_MASK) != 0)
  235. {
  236. //we have an exception response... something went wrong.
  237. quint8 ExceptionCode = Transaction.mPDU.mData[0];
  238. //TODO: Manage this!
  239. qDebug("Master Rx exception code %d to request %d",ExceptionCode,Request->mPDU.mFunctionCode);
  240. emit ModbusResponseException(ExceptionCode,Request->mPDU.mFunctionCode);
  241. delete Request;
  242. return RET_ERROR;
  243. }
  244. switch(Transaction.mPDU.mFunctionCode)
  245. {
  246. case MODBUS_FCT_READ_HOLDING_REGISTERS:
  247. {
  248. quint8 ByteCount = 0;
  249. ByteCount = Transaction.mPDU.mData.at(0);
  250. if((Request->mNbRegisters*2) != ByteCount)
  251. {
  252. //Inconsistency between the data range and the data count.
  253. //TODO: Log the error.
  254. qDebug("Master eceived a wrong data size in response for a MODBUS_FCT_READ_HOLDING_REGISTERS request");
  255. emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS);
  256. delete Request;
  257. return RET_ERROR;
  258. }
  259. QByteArray RegisterValues = Transaction.mPDU.mData.right(ByteCount);
  260. // qDebug("Master Rx Read Holding Registers Response.");
  261. // qDebug("Data: %s",RegisterValues.toHex().data());
  262. mModbusRepo->WriteHRData(Request->mStartAddress,Request->mNbRegisters,RegisterValues);
  263. RegistersDatabaseUpdated(Request->mStartAddress, Request->mNbRegisters);
  264. break;
  265. }
  266. case MODBUS_WRITE_SINGLE_REGISTER:
  267. {
  268. quint16 RegAddress = 0;
  269. RegAddress = Transaction.mPDU.mData[0]&0xFF;
  270. RegAddress <<= 8;
  271. RegAddress += Transaction.mPDU.mData[1]&0xFF;
  272. if(Request->mStartAddress != RegAddress)
  273. {
  274. //Inconsistency between the request Adress and response Adress.
  275. //TODO: Log the error.
  276. qDebug("Master received a wrong Register Adress in response for a MODBUS_WRITE_SINGLE_REGISTER request. Expected [%d], Rx[%d]",Request->mStartAddress, RegAddress);
  277. emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_WRITE_SINGLE_REGISTER);
  278. delete Request;
  279. return RET_ERROR;
  280. }
  281. // qDebug("Master Rx Write Single Register response. Address: %d,",RegAddress);
  282. // qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
  283. //Everything seems good.
  284. break;
  285. }
  286. case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS:
  287. {
  288. unsigned short StartAdress = 0;
  289. StartAdress = Transaction.mPDU.mData[0]&0xFF;
  290. StartAdress <<= 8;
  291. StartAdress += Transaction.mPDU.mData[1]&0xFF;
  292. unsigned short NbRegisters = 0;
  293. NbRegisters = Transaction.mPDU.mData[2]&0xFF;
  294. NbRegisters <<= 8;
  295. NbRegisters += Transaction.mPDU.mData[3]&0xFF;
  296. if(StartAdress != Request->mStartAddress || NbRegisters != Request->mNbRegisters)
  297. {
  298. //Inconsistency between the request Adress or NbRegisters and response.
  299. //TODO: Log the error.
  300. qDebug("Master Received a wrong Register Adress or NbRegisters in response for a MODBUS_FCT_WRITE_MULTIPLE_REGISTERS request");
  301. emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  302. delete Request;
  303. return RET_ERROR;
  304. }
  305. // qDebug("Master Rx Write Multiple Registers response. Address: %d, Nb Reg: %d",StartAdress, NbRegisters);
  306. // qDebug("Data: %s",Transaction.mPDU.mData.toHex().data());
  307. //All is good.
  308. break;
  309. }
  310. default:
  311. {
  312. //Received "Illegal function code" response
  313. //TODO: Log this.
  314. qDebug("Master received illegal function code 0x%x",Transaction.mPDU.mFunctionCode);
  315. emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_FCT,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS);
  316. break;
  317. }
  318. }
  319. delete Request;
  320. return 1;
  321. }
  322. int CModbusBackend::SendModbusRequest(CModbusRequest *Request)
  323. {
  324. QByteArray ModbusPacket;
  325. QBuffer Buffer(&ModbusPacket);
  326. Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
  327. Buffer.seek(0);
  328. QDataStream *PacketDataStrm = new QDataStream(&Buffer);
  329. *PacketDataStrm << Request->mHeader;
  330. *PacketDataStrm << Request->mPDU.mFunctionCode;
  331. Buffer.close();
  332. ModbusPacket.append(Request->mPDU.mData);
  333. qDebug("Request packet: %s",ModbusPacket.toHex().data());
  334. mModbusTCPSocketHandle->write(ModbusPacket);
  335. mModbusTCPSocketHandle->flush();
  336. return RET_OK;
  337. }
  338. int CModbusBackend::SendErrorResponse(CModbusTransaction RequestTransaction, quint8 ErrorCode)
  339. {
  340. QByteArray ModbusPacket;
  341. QBuffer Buffer(&ModbusPacket);
  342. Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered);
  343. Buffer.seek(0);
  344. QDataStream *PacketDataStrm = new QDataStream(&Buffer);
  345. //For a response, the header will be the same as the original request, except for the msg. length.
  346. //Set the appropriate msg length.
  347. RequestTransaction.mHeader.mMessageLength = 3; //Unit ID, function code & Exception code.
  348. *PacketDataStrm << RequestTransaction.mHeader;
  349. Buffer.close();
  350. ModbusPacket.append(RequestTransaction.mPDU.mFunctionCode + 0x80);
  351. ModbusPacket.append(ErrorCode);
  352. qDebug("Sending error code %d. Error packet: %s",ErrorCode,ModbusPacket.toHex().data());
  353. mModbusTCPSocketHandle->write(ModbusPacket);
  354. delete PacketDataStrm;
  355. return RET_OK;
  356. }
  357. int CModbusBackend::SendReadHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount)
  358. {
  359. //First, validate that the reading range is within our repo
  360. if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false)
  361. {
  362. qDebug("Trying to send a read HR in an invalid range");
  363. return RET_ERROR;
  364. }
  365. //Create a request.
  366. CModbusRequest *NewRequest = new CModbusRequest;
  367. NewRequest->mStartAddress = StartAddress;
  368. NewRequest->mNbRegisters = RegisterCount;
  369. connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
  370. NewRequest->mPDU.mData.clear();
  371. NewRequest->mPDU.mFunctionCode = MODBUS_FCT_READ_HOLDING_REGISTERS;
  372. quint8 HighByte, LowByte;
  373. LowByte = StartAddress & 0x00FF;
  374. HighByte = (StartAddress >> 8) & 0x00FF;
  375. NewRequest->mPDU.mData.append(HighByte);
  376. NewRequest->mPDU.mData.append(LowByte);
  377. LowByte = RegisterCount & 0x00FF;
  378. HighByte = (RegisterCount >> 8) & 0x00FF;
  379. NewRequest->mPDU.mData.append(HighByte);
  380. NewRequest->mPDU.mData.append(LowByte);
  381. NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
  382. NewRequest->mHeader.mProtocolID = 0;
  383. NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
  384. NewRequest->mHeader.mUnitID = mDeviceID;
  385. mRequestsList.append(NewRequest);
  386. SendModbusRequest(NewRequest);
  387. NewRequest->mRequestTimer->start(mModbusRequestTimeout);
  388. return RET_OK;
  389. }
  390. int CModbusBackend::SendWriteHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount)
  391. {
  392. //First, validate that the reading range is within our repo
  393. if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false)
  394. {
  395. qDebug("Trying to send a read HR in an invalid range");
  396. return RET_ERROR;
  397. }
  398. if(RegisterCount > MODBUS_MAX_NB_REGISTERS)
  399. {
  400. return RET_ERROR;
  401. }
  402. //Get data.
  403. bool OK;
  404. QByteArray RegData = mModbusRepo->GetHRData(StartAddress,RegisterCount,&OK);
  405. if(OK == false)
  406. {
  407. return RET_ERROR;
  408. }
  409. //Create a request.
  410. CModbusRequest *NewRequest = new CModbusRequest;
  411. NewRequest->mStartAddress = StartAddress;
  412. NewRequest->mNbRegisters = RegisterCount;
  413. connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
  414. NewRequest->mPDU.mData.clear();
  415. NewRequest->mPDU.mFunctionCode = MODBUS_FCT_WRITE_MULTIPLE_REGISTERS;
  416. //Start address
  417. quint8 HighByte, LowByte;
  418. LowByte = StartAddress & 0x00FF;
  419. HighByte = (StartAddress >> 8) & 0x00FF;
  420. NewRequest->mPDU.mData.append(HighByte);
  421. NewRequest->mPDU.mData.append(LowByte);
  422. //Nb registers
  423. LowByte = RegisterCount & 0x00FF;
  424. HighByte = (RegisterCount >> 8) & 0x00FF;
  425. NewRequest->mPDU.mData.append(HighByte);
  426. NewRequest->mPDU.mData.append(LowByte);
  427. //Byte Count
  428. NewRequest->mPDU.mData.append(RegData.size());
  429. //Datal
  430. NewRequest->mPDU.mData.append(RegData);
  431. NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
  432. NewRequest->mHeader.mProtocolID = 0;
  433. NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
  434. NewRequest->mHeader.mUnitID = mDeviceID;
  435. mRequestsList.append(NewRequest);
  436. SendModbusRequest(NewRequest);
  437. NewRequest->mRequestTimer->start(mModbusRequestTimeout);
  438. return RET_OK;
  439. }
  440. int CModbusBackend::SendWriteSingleRegisterRequest(quint16 Address)
  441. {
  442. if(Address == 2000)
  443. {
  444. qDebug("Write single reg 2000");
  445. }
  446. //First, validate that the reading range is within our repo
  447. if(mModbusRepo->IsHRValid(Address,1) == false)
  448. {
  449. qDebug("Trying to send a read HR in an invalid range");
  450. return RET_ERROR;
  451. }
  452. //Get data.
  453. bool OK;
  454. QByteArray RegData = mModbusRepo->GetHRData(Address,1,&OK);
  455. if(OK == false)
  456. {
  457. return RET_ERROR;
  458. }
  459. //Create a request.
  460. CModbusRequest *NewRequest = new CModbusRequest;
  461. NewRequest->mStartAddress = Address;
  462. NewRequest->mNbRegisters = 1;
  463. connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired()));
  464. NewRequest->mPDU.mData.clear();
  465. NewRequest->mPDU.mFunctionCode = MODBUS_WRITE_SINGLE_REGISTER;
  466. quint8 HighByte, LowByte;
  467. LowByte = Address & 0x00FF;
  468. HighByte = (Address >> 8) & 0x00FF;
  469. NewRequest->mPDU.mData.append(HighByte);
  470. NewRequest->mPDU.mData.append(LowByte);
  471. // LowByte = RegData & 0x00FF;
  472. // HighByte = (RegData >> 8) & 0x00FF;
  473. // NewRequest->mPDU.mData.append(HighByte);
  474. // NewRequest->mPDU.mData.append(LowByte);
  475. NewRequest->mPDU.mData.append(RegData);
  476. NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2;
  477. NewRequest->mHeader.mProtocolID = 0;
  478. NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID();
  479. NewRequest->mHeader.mUnitID = mDeviceID;
  480. mRequestsList.append(NewRequest);
  481. SendModbusRequest(NewRequest);
  482. NewRequest->mRequestTimer->start(mModbusRequestTimeout);
  483. return RET_OK;
  484. }
  485. void CModbusBackend::RequestTimerExpired()
  486. {
  487. //find the expired request
  488. for(int i = 0; i < mRequestsList.size(); i++)
  489. {
  490. if(mRequestsList.at(i)->mRequestTimer->isActive() == false)
  491. {
  492. if(mRequestsList.at(i)->mRetries >= mModbusMaxRetry)
  493. {
  494. //The max number of retry has been reached. The device is probably offline.
  495. qDebug("Modbus Master: Request sent to slave without response");
  496. delete mRequestsList[i];
  497. mRequestsList.removeAt(i);
  498. //TODO: Manage this situation (log?)
  499. return;
  500. }
  501. else
  502. {
  503. SendModbusRequest(mRequestsList[i]);
  504. mRequestsList.at(i)->mRequestTimer->start(mModbusRequestTimeout);
  505. mRequestsList[i]->mRetries++;
  506. }
  507. }
  508. }
  509. }
  510. quint16 CModbusBackend::GetNewTransactionID()
  511. {
  512. quint16 ID = mTransactionIDCounter++;
  513. if(mTransactionIDCounter == 0xFFFF - 10)
  514. {
  515. mTransactionIDCounter = 0;
  516. }
  517. return ID;
  518. }
  519. CModbusRequest::CModbusRequest():
  520. mRetries(0)
  521. {
  522. mRequestTimer = new QTimer;
  523. mRequestTimer->setSingleShot(true);
  524. }
  525. CModbusRequest::~CModbusRequest()
  526. {
  527. delete mRequestTimer;
  528. }
  529. QDataStream &operator<<(QDataStream &out, const CModbusHeader &source)
  530. {
  531. out << source.mTransactionID
  532. << source.mProtocolID
  533. << source.mMessageLength
  534. << source.mUnitID
  535. ;
  536. return out;
  537. }
  538. QDataStream &operator>>(QDataStream &in, CModbusHeader &dest)
  539. {
  540. in >> dest.mTransactionID
  541. >> dest.mProtocolID
  542. >> dest.mMessageLength
  543. >> dest.mUnitID
  544. ;
  545. return in;
  546. }
  547. //Virtual function that should not even get called...
  548. void CModbusBackend::ModbusResponseException(quint8 ExceptionCode, quint8 FctCode)
  549. {
  550. qDebug("ModbusResponseException called from within slave object... weird stuff!");
  551. }
  552. //Virtual function that should not even get called...
  553. void CModbusBackend::ModbusRequestException(quint8 ExceptionCode, quint8 FctCode)
  554. {
  555. qDebug("ModbusResponseException called from within master object... weird stuff!");
  556. }