simple_server.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include "iec_include.h"
  2. #include "simple_server.h"
  3. static bool running = true;
  4. static void printCP56Time2a(CP56Time2a time)
  5. {
  6. printf("%02i:%02i:%02i %02i/%02i/%04i", CP56Time2a_getHour(time),
  7. CP56Time2a_getMinute(time),
  8. CP56Time2a_getSecond(time),
  9. CP56Time2a_getDayOfMonth(time),
  10. CP56Time2a_getMonth(time),
  11. CP56Time2a_getYear(time) + 2000);
  12. }
  13. /* Callback handler to log sent or received messages (optional) */
  14. static void
  15. rawMessageHandler(void* parameter, IMasterConnection conneciton, uint8_t* msg, int msgSize, bool sent)
  16. {
  17. if (sent)
  18. printf("SEND: ");
  19. else
  20. printf("RCVD: ");
  21. int i;
  22. for (i = 0; i < msgSize; i++) {
  23. printf("%02x ", msg[i]);
  24. }
  25. printf("\n");
  26. }
  27. static bool
  28. cs104ClockSyncHandler (void* parameter, IMasterConnection connection, CS101_ASDU asdu, CP56Time2a newTime)
  29. {
  30. printf("Process time sync command with time "); printCP56Time2a(newTime); printf("\n");
  31. uint64_t newSystemTimeInMs = CP56Time2a_toMsTimestamp(newTime);
  32. /* Set time for ACT_CON message */
  33. CP56Time2a_setFromMsTimestamp(newTime, Hal_getTimeInMs());
  34. /* update system time here */
  35. return true;
  36. }
  37. static bool
  38. cs104InterrogationHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu, uint8_t qoi)
  39. {
  40. printf("Received interrogation for group %i\n", qoi);
  41. if (qoi == 20) { /* only handle station interrogation */
  42. CS101_AppLayerParameters alParams = IMasterConnection_getApplicationLayerParameters(connection);
  43. IMasterConnection_sendACT_CON(connection, asdu, false);
  44. /* The CS101 specification only allows information objects without timestamp in GI responses */
  45. CS101_ASDU newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_INTERROGATED_BY_STATION,
  46. 0, 1, false, false);
  47. InformationObject io = (InformationObject) MeasuredValueScaled_create(NULL, 100, -1, IEC60870_QUALITY_GOOD);
  48. CS101_ASDU_addInformationObject(newAsdu, io);
  49. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  50. MeasuredValueScaled_create((MeasuredValueScaled) io, 101, 23, IEC60870_QUALITY_GOOD));
  51. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  52. MeasuredValueScaled_create((MeasuredValueScaled) io, 102, 2300, IEC60870_QUALITY_GOOD));
  53. InformationObject_destroy(io);
  54. IMasterConnection_sendASDU(connection, newAsdu);
  55. CS101_ASDU_destroy(newAsdu);
  56. newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_INTERROGATED_BY_STATION,
  57. 0, 1, false, false);
  58. io = (InformationObject) SinglePointInformation_create(NULL, 104, true, IEC60870_QUALITY_GOOD);
  59. CS101_ASDU_addInformationObject(newAsdu, io);
  60. CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
  61. SinglePointInformation_create((SinglePointInformation) io, 105, false, IEC60870_QUALITY_GOOD));
  62. InformationObject_destroy(io);
  63. IMasterConnection_sendASDU(connection, newAsdu);
  64. CS101_ASDU_destroy(newAsdu);
  65. newAsdu = CS101_ASDU_create(alParams, true, CS101_COT_INTERROGATED_BY_STATION,
  66. 0, 1, false, false);
  67. CS101_ASDU_addInformationObject(newAsdu, io = (InformationObject) SinglePointInformation_create(NULL, 300, true, IEC60870_QUALITY_GOOD));
  68. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 301, false, IEC60870_QUALITY_GOOD));
  69. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 302, true, IEC60870_QUALITY_GOOD));
  70. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 303, false, IEC60870_QUALITY_GOOD));
  71. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 304, true, IEC60870_QUALITY_GOOD));
  72. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 305, false, IEC60870_QUALITY_GOOD));
  73. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 306, true, IEC60870_QUALITY_GOOD));
  74. CS101_ASDU_addInformationObject(newAsdu, (InformationObject) SinglePointInformation_create((SinglePointInformation) io, 307, false, IEC60870_QUALITY_GOOD));
  75. InformationObject_destroy(io);
  76. IMasterConnection_sendASDU(connection, newAsdu);
  77. CS101_ASDU_destroy(newAsdu);
  78. newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_INTERROGATED_BY_STATION,
  79. 0, 1, false, false);
  80. io = (InformationObject) BitString32_create(NULL, 500, 0xaaaa);
  81. CS101_ASDU_addInformationObject(newAsdu, io);
  82. InformationObject_destroy(io);
  83. IMasterConnection_sendASDU(connection, newAsdu);
  84. CS101_ASDU_destroy(newAsdu);
  85. IMasterConnection_sendACT_TERM(connection, asdu);
  86. }
  87. else {
  88. IMasterConnection_sendACT_CON(connection, asdu, true);
  89. }
  90. return true;
  91. }
  92. static bool
  93. cs104AsduHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu)
  94. {
  95. if (CS101_ASDU_getTypeID(asdu) == C_SC_NA_1) {
  96. printf("received single command\n");
  97. if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION) {
  98. InformationObject io = CS101_ASDU_getElement(asdu, 0);
  99. if (io) {
  100. if (InformationObject_getObjectAddress(io) == 5000) {
  101. SingleCommand sc = (SingleCommand) io;
  102. printf("IOA: %i switch to %i\n", InformationObject_getObjectAddress(io),
  103. SingleCommand_getState(sc));
  104. CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
  105. }
  106. else
  107. CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_IOA);
  108. InformationObject_destroy(io);
  109. }
  110. else {
  111. printf("ERROR: message has no valid information object\n");
  112. return true;
  113. }
  114. }
  115. else
  116. CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);
  117. IMasterConnection_sendASDU(connection, asdu);
  118. return true;
  119. }
  120. return false;
  121. }
  122. static bool
  123. cs104ConnectionRequestHandler(void* parameter, const char* ipAddress)
  124. {
  125. printf("New connection request from %s\n", ipAddress);
  126. #if 0
  127. if (strcmp(ipAddress, "127.0.0.1") == 0) {
  128. printf("Accept connection\n");
  129. return true;
  130. }
  131. else {
  132. printf("Deny connection\n");
  133. return false;
  134. }
  135. #else
  136. return true;
  137. #endif
  138. }
  139. static void
  140. cs104ConnectionEventHandler(void* parameter, IMasterConnection con, CS104_PeerConnectionEvent event)
  141. {
  142. if (event == CS104_CON_EVENT_CONNECTION_OPENED) {
  143. printf("Connection opened (%p)\n", con);
  144. }
  145. else if (event == CS104_CON_EVENT_CONNECTION_CLOSED) {
  146. printf("Connection closed (%p)\n", con);
  147. }
  148. else if (event == CS104_CON_EVENT_ACTIVATED) {
  149. printf("Connection activated (%p)\n", con);
  150. }
  151. else if (event == CS104_CON_EVENT_DEACTIVATED) {
  152. printf("Connection deactivated (%p)\n", con);
  153. }
  154. }
  155. void cs104_server(void const* arg)
  156. {
  157. /* create a new slave/server instance with default connection parameters and
  158. * default message queue size */
  159. CS104_Slave slave = CS104_Slave_create(10, 10);
  160. CS104_Slave_setLocalAddress(slave, "0.0.0.0");
  161. /* Set mode to a single redundancy group
  162. * NOTE: library has to be compiled with CONFIG_CS104_SUPPORT_SERVER_MODE_SINGLE_REDUNDANCY_GROUP enabled (=1)
  163. */
  164. CS104_Slave_setServerMode(slave, CS104_MODE_SINGLE_REDUNDANCY_GROUP);
  165. /* get the connection parameters - we need them to create correct ASDUs -
  166. * you can also modify the parameters here when default parameters are not to be used */
  167. CS101_AppLayerParameters alParams = CS104_Slave_getAppLayerParameters(slave);
  168. /* when you have to tweak the APCI parameters (t0-t3, k, w) you can access them here */
  169. CS104_APCIParameters apciParams = CS104_Slave_getConnectionParameters(slave);
  170. printf("APCI parameters:\n");
  171. printf(" t0: %i\n", apciParams->t0);
  172. printf(" t1: %i\n", apciParams->t1);
  173. printf(" t2: %i\n", apciParams->t2);
  174. printf(" t3: %i\n", apciParams->t3);
  175. printf(" k: %i\n", apciParams->k);
  176. printf(" w: %i\n", apciParams->w);
  177. /* set the callback handler for the clock synchronization command */
  178. CS104_Slave_setClockSyncHandler(slave, cs104ClockSyncHandler, NULL);
  179. /* set the callback handler for the interrogation command */
  180. CS104_Slave_setInterrogationHandler(slave, cs104InterrogationHandler, NULL);
  181. /* set handler for other message types */
  182. CS104_Slave_setASDUHandler(slave, cs104AsduHandler, NULL);
  183. /* set handler to handle connection requests (optional) */
  184. CS104_Slave_setConnectionRequestHandler(slave, cs104ConnectionRequestHandler, NULL);
  185. /* set handler to track connection events (optional) */
  186. CS104_Slave_setConnectionEventHandler(slave, cs104ConnectionEventHandler, NULL);
  187. /* uncomment to log messages */
  188. //CS104_Slave_setRawMessageHandler(slave, rawMessageHandler, NULL);
  189. CS104_Slave_start(slave);
  190. if (CS104_Slave_isRunning(slave) == false) {
  191. printf("Starting server failed!\n");
  192. goto exit_program;
  193. }
  194. int16_t scaledValue = 0;
  195. while (running) {
  196. delay_ms(1000);
  197. CS101_ASDU newAsdu = CS101_ASDU_create(alParams, false, CS101_COT_PERIODIC, 0, 1, false, false);
  198. InformationObject io = (InformationObject) MeasuredValueScaled_create(NULL, 110, scaledValue, IEC60870_QUALITY_GOOD);
  199. scaledValue++;
  200. CS101_ASDU_addInformationObject(newAsdu, io);
  201. InformationObject_destroy(io);
  202. /* Add ASDU to slave event queue */
  203. CS104_Slave_enqueueASDU(slave, newAsdu);
  204. CS101_ASDU_destroy(newAsdu);
  205. }
  206. CS104_Slave_stop(slave);
  207. exit_program:
  208. CS104_Slave_destroy(slave);
  209. delay_ms(500);
  210. }