slave_example.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * slave_example.c
  3. *
  4. * Example CS101 slave
  5. *
  6. */
  7. #include <stdlib.h>
  8. #include <stdbool.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <signal.h>
  12. #include "iec_include.h"
  13. static bool running = true;
  14. static void
  15. printCP56Time2a(CP56Time2a time)
  16. {
  17. printf("%02i:%02i:%02i %02i/%02i/%04i", CP56Time2a_getHour(time),
  18. CP56Time2a_getMinute(time),
  19. CP56Time2a_getSecond(time),
  20. CP56Time2a_getDayOfMonth(time),
  21. CP56Time2a_getMonth(time),
  22. CP56Time2a_getYear(time) + 2000);
  23. }
  24. /* Callback handler to log sent or received messages (optional) */
  25. static void
  26. rawMessageHandlerClient (void* parameter, uint8_t* msg, int msgSize, bool sent)
  27. {
  28. if (sent) {
  29. printf("SEND: ");
  30. }
  31. else {
  32. printf("RCVD: ");
  33. }
  34. int i;
  35. for (i = 0; i < msgSize; i++) {
  36. printf("%02x ", msg[i]);
  37. }
  38. printf("\n");
  39. }
  40. /* Callback handler that is called when a clock synchronization command is received */
  41. static bool
  42. clockSyncHandler (void* parameter, IMasterConnection connection, CS101_ASDU asdu, CP56Time2a newTime)
  43. {
  44. printf("Process time sync command with time "); printCP56Time2a(newTime); printf("\n");
  45. return true;
  46. }
  47. /* Callback handler that is called when an interrogation command is received */
  48. static bool
  49. interrogationHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu, uint8_t qoi)
  50. {
  51. printf("Received interrogation for group %i\n", qoi);
  52. if (qoi == 20) { /* only handle station interrogation */
  53. CS101_AppLayerParameters alParams = IMasterConnection_getApplicationLayerParameters(connection);
  54. IMasterConnection_sendACT_CON(connection, asdu, false);
  55. /* The CS101 specification only allows information objects without timestamp in GI responses */
  56. CS101_ASDU newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_INTERROGATED_BY_STATION,
  57. 0, 1, false, false);
  58. InformationObject io = (InformationObject) MeasuredValueScaled_create(NULL, 100, -1, IEC60870_QUALITY_GOOD);
  59. CS101_ASDU_addInformationObject(newAsdu, io);
  60. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  61. MeasuredValueScaled_create((MeasuredValueScaled) io, 101, 23, IEC60870_QUALITY_GOOD));
  62. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  63. MeasuredValueScaled_create((MeasuredValueScaled) io, 102, 2300, IEC60870_QUALITY_GOOD));
  64. InformationObject_destroy(io);
  65. IMasterConnection_sendASDU(connection, newAsdu);
  66. CS101_ASDU_destroy(newAsdu);
  67. newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_INTERROGATED_BY_STATION,
  68. 0, 1, false, false);
  69. io = (InformationObject) SinglePointInformation_create(NULL, 104, true, IEC60870_QUALITY_GOOD);
  70. CS101_ASDU_addInformationObject(newAsdu, io);
  71. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  72. SinglePointInformation_create((SinglePointInformation) io, 105, false, IEC60870_QUALITY_GOOD));
  73. InformationObject_destroy(io);
  74. IMasterConnection_sendASDU(connection, newAsdu);
  75. CS101_ASDU_destroy(newAsdu);
  76. newAsdu = CS101_ASDU_create(alParams, true, CS101_COT_INTERROGATED_BY_STATION,
  77. 0, 1, false, false);
  78. CS101_ASDU_addInformationObject(newAsdu, io = (InformationObject) SinglePointInformation_create(NULL, 300, true, IEC60870_QUALITY_GOOD));
  79. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 301, false, IEC60870_QUALITY_GOOD));
  80. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 302, true, IEC60870_QUALITY_GOOD));
  81. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 303, false, IEC60870_QUALITY_GOOD));
  82. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 304, true, IEC60870_QUALITY_GOOD));
  83. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 305, false, IEC60870_QUALITY_GOOD));
  84. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 306, true, IEC60870_QUALITY_GOOD));
  85. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 307, false, IEC60870_QUALITY_GOOD));
  86. InformationObject_destroy(io);
  87. IMasterConnection_sendASDU(connection, newAsdu);
  88. CS101_ASDU_destroy(newAsdu);
  89. IMasterConnection_sendACT_TERM(connection, asdu);
  90. }
  91. else {
  92. IMasterConnection_sendACT_CON(connection, asdu, true);
  93. }
  94. return true;
  95. }
  96. static bool
  97. asduHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu)
  98. {
  99. if (CS101_ASDU_getTypeID(asdu) == C_SC_NA_1) {
  100. printf("received single command\n");
  101. if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION) {
  102. InformationObject io = CS101_ASDU_getElement(asdu, 0);
  103. if (io) {
  104. if (InformationObject_getObjectAddress(io) == 5000) {
  105. SingleCommand sc = (SingleCommand) io;
  106. printf("IOA: %i switch to %i\n", InformationObject_getObjectAddress(io),
  107. SingleCommand_getState(sc));
  108. CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
  109. }
  110. else
  111. CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_IOA);
  112. InformationObject_destroy(io);
  113. }
  114. else {
  115. printf("ERROR: ASDU contains no information object!\n");
  116. return true;
  117. }
  118. }
  119. else
  120. CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);
  121. IMasterConnection_sendASDU(connection, asdu);
  122. return true;
  123. }
  124. return false;
  125. }
  126. static void
  127. resetCUHandler(void* parameter)
  128. {
  129. printf("Received reset CU\n");
  130. CS101_Slave_flushQueues((CS101_Slave) parameter);
  131. }
  132. static void
  133. linkLayerStateChangedClinet(void* parameter, int address, LinkLayerState state)
  134. {
  135. printf("Link layer state: ");
  136. switch (state) {
  137. case LL_STATE_IDLE:
  138. printf("IDLE\n");
  139. break;
  140. case LL_STATE_ERROR:
  141. printf("ERROR\n");
  142. break;
  143. case LL_STATE_BUSY:
  144. printf("BUSY\n");
  145. break;
  146. case LL_STATE_AVAILABLE:
  147. printf("AVAILABLE\n");
  148. break;
  149. }
  150. }
  151. void iec_client_test(void const* arg)
  152. {
  153. const char* serialPort = "/dev/ttyUSB0";
  154. SerialPort port = SerialPort_create(serialPort, 9600, 8, 'E', 1);
  155. /* create a new slave/server instance with default link layer and application layer parameters */
  156. //CS101_Slave slave = CS101_Slave_create(port, NULL, NULL, IEC60870_LINK_LAYER_BALANCED);
  157. CS101_Slave slave = CS101_Slave_create(port, NULL, NULL, IEC60870_LINK_LAYER_UNBALANCED);
  158. CS101_Slave_setLinkLayerAddress(slave, 1);
  159. CS101_Slave_setLinkLayerAddressOtherStation(slave, 1);
  160. /* get the application layer parameters - we need them to create correct ASDUs */
  161. CS101_AppLayerParameters alParameters = CS101_Slave_getAppLayerParameters(slave);
  162. /* change default application layer parameters (optional) */
  163. alParameters->sizeOfCA = 2;
  164. alParameters->sizeOfIOA = 3;
  165. alParameters->sizeOfCOT = 2;
  166. LinkLayerParameters llParameters = CS101_Slave_getLinkLayerParameters(slave);
  167. llParameters->timeoutForAck = 500;
  168. llParameters->addressLength = 1;
  169. /* set the callback handler for the clock synchronization command */
  170. CS101_Slave_setClockSyncHandler(slave, clockSyncHandler, NULL);
  171. /* set the callback handler for the interrogation command */
  172. CS101_Slave_setInterrogationHandler(slave, interrogationHandler, NULL);
  173. /* set handler for other message types */
  174. CS101_Slave_setASDUHandler(slave, asduHandler, NULL);
  175. /* set handler for reset CU (reset communication unit) message */
  176. CS101_Slave_setResetCUHandler(slave, resetCUHandler, (void*) slave);
  177. /* set timeout for detecting connection loss */
  178. CS101_Slave_setIdleTimeout(slave, 1500);
  179. /* set handler for link layer state changes */
  180. CS101_Slave_setLinkLayerStateChanged(slave, linkLayerStateChangedClinet, NULL);
  181. /* log messages */
  182. CS101_Slave_setRawMessageHandler(slave, rawMessageHandlerClient, NULL);
  183. int16_t scaledValue = 0;
  184. uint32_t lastMessageSent = 0;
  185. while (running) {
  186. /* has to be called periodically */
  187. CS101_Slave_run(slave);
  188. /* Enqueue a measurement every second */
  189. if (lastMessageSent > 1000) {
  190. CS101_ASDU newAsdu = CS101_ASDU_create(alParameters, false, CS101_COT_PERIODIC, 0, 1, false, false);
  191. InformationObject io = (InformationObject) MeasuredValueScaled_create(NULL, 110, scaledValue, IEC60870_QUALITY_GOOD);
  192. scaledValue++;
  193. CS101_ASDU_addInformationObject(newAsdu, io);
  194. InformationObject_destroy(io);
  195. CS101_Slave_enqueueUserDataClass1(slave, newAsdu);
  196. CS101_ASDU_destroy(newAsdu);
  197. lastMessageSent = 0;
  198. }
  199. lastMessageSent++;
  200. recv_232_done = 0;
  201. memset(rx_232_Buffer, 0, sizeof(rx_232_Buffer));
  202. delay_ms(100);
  203. }
  204. goto exit_program;
  205. exit_program:
  206. CS101_Slave_destroy(slave);
  207. }