123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701 |
- #include "iec_include.h"
- struct sCS101_Slave
- {
- CS101_InterrogationHandler interrogationHandler;
- void* interrogationHandlerParameter;
- CS101_CounterInterrogationHandler counterInterrogationHandler;
- void* counterInterrogationHandlerParameter;
- CS101_ReadHandler readHandler;
- void* readHandlerParameter;
- CS101_ClockSynchronizationHandler clockSyncHandler;
- void* clockSyncHandlerParameter;
- CS101_ResetProcessHandler resetProcessHandler;
- void* resetProcessHandlerParameter;
- CS101_DelayAcquisitionHandler delayAcquisitionHandler;
- void* delayAcquisitionHandlerParameter;
- CS101_ASDUHandler asduHandler;
- void* asduHandlerParameter;
- CS101_ResetCUHandler resetCUHandler;
- void* resetCUHandlerParameter;
- SerialTransceiverFT12 transceiver;
- LinkLayerSecondaryUnbalanced unbalancedLinkLayer;
- LinkLayerBalanced balancedLinkLayer;
- struct sLinkLayerParameters linkLayerParameters;
- struct sCS101_AppLayerParameters alParameters;
- struct sCS101_Queue userDataClass1Queue;
- struct sCS101_Queue userDataClass2Queue;
- struct sIMasterConnection iMasterConnection;
- IEC60870_LinkLayerMode linkLayerMode;
- #if (CONFIG_USE_THREADS == 1)
- bool isRunning;
- platform_thread_t* workerThread;
- #endif
- LinkedList plugins;
- };
- static void
- handleASDU(CS101_Slave self, CS101_ASDU asdu);
- /********************************************
- * ISecondaryApplicationLayer
- ********************************************/
- static bool
- IsClass1DataAvailable(void* parameter)
- {
- CS101_Slave self = (CS101_Slave) parameter;
- return (CS101_Queue_isEmpty(&(self->userDataClass1Queue)) == false);
- }
- static Frame
- GetClass1Data(void* parameter, Frame frame)
- {
- CS101_Slave self = (CS101_Slave) parameter;
- CS101_Queue_lock(&(self->userDataClass1Queue));
- Frame userData = CS101_Queue_dequeue(&(self->userDataClass1Queue), frame);
- CS101_Queue_unlock(&(self->userDataClass1Queue));
- return userData;
- }
- static Frame
- GetClass2Data(void* parameter, Frame frame)
- {
- CS101_Slave self = (CS101_Slave) parameter;
- CS101_Queue_lock(&(self->userDataClass2Queue));
- Frame userData = CS101_Queue_dequeue(&(self->userDataClass2Queue), frame);
- CS101_Queue_unlock(&(self->userDataClass2Queue));
- return userData;
- }static bool
- HandleReceivedData(void* parameter, uint8_t* msg, bool isBroadcast, int userDataStart, int userDataLength)
- {
- UNUSED_PARAMETER(isBroadcast);
- CS101_Slave self = (CS101_Slave) parameter;
- CS101_ASDU asdu = CS101_ASDU_createFromBuffer(&(self->alParameters), msg + userDataStart, userDataLength);
- if (asdu) {
- handleASDU(self, asdu);
- CS101_ASDU_destroy(asdu);
- }
- else {
- printf("CS101 slave: Failed to parse ASDU\n");
- }
- return true;
- }
- static void
- ResetCUReceived(void* parameter, bool onlyFCB)
- {
- CS101_Slave self = (CS101_Slave) parameter;
- if (onlyFCB) {
- printf("CS101 slave: Reset FCB received\n");
- }
- else {
- printf("CS101 slave: Reset CU received\n");
- if (self->resetCUHandler)
- self->resetCUHandler(self->resetCUHandlerParameter);
- }
- }
- static struct sISecondaryApplicationLayer cs101UnbalancedAppLayerInterface = {
- IsClass1DataAvailable,
- GetClass1Data,
- GetClass2Data,
- HandleReceivedData,
- ResetCUReceived
- };
- /********************************************
- * IMasterConnection
- *******************************************/
- bool
- CS101_Slave_isClass1QueueFull(CS101_Slave self)
- {
- return CS101_Queue_isFull(&(self->userDataClass1Queue));
- }
- static bool
- isReady(IMasterConnection self)
- {
- CS101_Slave slave = (CS101_Slave) self->object;
- if (CS101_Slave_isClass1QueueFull(slave))
- return false;
- else
- return true;
- }
- void
- CS101_Slave_enqueueUserDataClass1(CS101_Slave self, CS101_ASDU asdu)
- {
- CS101_Queue_enqueue(&(self->userDataClass1Queue), asdu);
- }
- void
- CS101_Slave_enqueueUserDataClass2(CS101_Slave self, CS101_ASDU asdu)
- {
- CS101_Queue_enqueue(&(self->userDataClass2Queue), asdu);
- }
- CS101_AppLayerParameters
- CS101_Slave_getAppLayerParameters(CS101_Slave self)
- {
- return &(self->alParameters);
- }
- LinkLayerParameters
- CS101_Slave_getLinkLayerParameters(CS101_Slave self)
- {
- return &(self->linkLayerParameters);
- }
- void
- CS101_Slave_flushQueues(CS101_Slave self)
- {
- CS101_Queue_flush(&(self->userDataClass1Queue));
- CS101_Queue_flush(&(self->userDataClass2Queue));
- }
- static bool
- sendASDU(IMasterConnection self, CS101_ASDU asdu)
- {
- CS101_Slave slave = (CS101_Slave) self->object;
- CS101_Slave_enqueueUserDataClass1(slave, asdu);
- return true;
- }
- static bool
- sendACT_CON(IMasterConnection self, CS101_ASDU asdu, bool negative)
- {
- CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
- CS101_ASDU_setNegative(asdu, negative);
- return sendASDU(self, asdu);
- }
- static bool
- sendACT_TERM(IMasterConnection self, CS101_ASDU asdu)
- {
- CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_TERMINATION);
- CS101_ASDU_setNegative(asdu, false);
- return sendASDU(self, asdu);
- }
- static CS101_AppLayerParameters
- getApplicationLayerParameters(IMasterConnection self)
- {
- CS101_Slave slave = (CS101_Slave) self->object;
- return &(slave->alParameters);
- }
- void
- CS101_Slave_setASDUHandler(CS101_Slave self, CS101_ASDUHandler handler, void* parameter)
- {
- self->asduHandler = handler;
- self->asduHandlerParameter = parameter;
- }
- void
- CS101_Slave_setClockSyncHandler(CS101_Slave self, CS101_ClockSynchronizationHandler handler, void* parameter)
- {
- self->clockSyncHandler = handler;
- self->clockSyncHandlerParameter = parameter;
- }
- void
- CS101_Slave_setInterrogationHandler(CS101_Slave self, CS101_InterrogationHandler handler, void* parameter)
- {
- self->interrogationHandler = handler;
- self->interrogationHandlerParameter = parameter;
- }
- void
- CS101_Slave_setResetCUHandler(CS101_Slave self, CS101_ResetCUHandler handler, void* parameter)
- {
- self->resetCUHandler = handler;
- self->resetCUHandlerParameter = parameter;
- }
- void
- CS101_Slave_setRawMessageHandler(CS101_Slave self, IEC60870_RawMessageHandler handler, void* parameter)
- {
- SerialTransceiverFT12_setRawMessageHandler(self->transceiver, handler, parameter);
- }
- void
- CS101_Slave_setLinkLayerStateChanged(CS101_Slave self, IEC60870_LinkLayerStateChangedHandler handler, void* parameter)
- {
- if (self->linkLayerMode == IEC60870_LINK_LAYER_UNBALANCED) {
- LinkLayerSecondaryUnbalanced_setStateChangeHandler(self->unbalancedLinkLayer, handler, parameter);
- }
- else {
- LinkLayerBalanced_setStateChangeHandler(self->balancedLinkLayer, handler, parameter);
- }
- }
- void
- CS101_Slave_setLinkLayerAddressOtherStation(CS101_Slave self, int address)
- {
- if (self->balancedLinkLayer)
- LinkLayerBalanced_setOtherStationAddress(self->balancedLinkLayer, address);
- }
- void
- CS101_Slave_setLinkLayerAddress(CS101_Slave self, int address)
- {
- if (self->linkLayerMode == IEC60870_LINK_LAYER_UNBALANCED)
- LinkLayerSecondaryUnbalanced_setAddress(self->unbalancedLinkLayer, address);
- else
- LinkLayerBalanced_setAddress(self->balancedLinkLayer, address);
- }
- void
- CS101_Slave_setIdleTimeout(CS101_Slave self, int timeoutInMs)
- {
- if (self->linkLayerMode == IEC60870_LINK_LAYER_UNBALANCED)
- LinkLayerSecondaryUnbalanced_setIdleTimeout(self->unbalancedLinkLayer, timeoutInMs);
- else
- LinkLayerBalanced_setIdleTimeout(self->balancedLinkLayer, timeoutInMs);
- }
- static struct sCS101_AppLayerParameters defaultAppLayerParameters = {
- /* .sizeOfTypeId = */ 1,
- /* .sizeOfVSQ = */ 1,
- /* .sizeOfCOT = */ 2,
- /* .originatorAddress = */ 0,
- /* .sizeOfCA = */ 2,
- /* .sizeOfIOA = */ 3,
- /* .maxSizeOfASDU = */ 249
- };
- static bool
- IsClass2DataAvailable(void* parameter)
- {
- CS101_Slave self = (CS101_Slave) parameter;
- return (CS101_Queue_isEmpty(&(self->userDataClass2Queue)) == false);
- }
- static Frame
- IBalancedApplicationLayer_GetUserData(void* parameter, Frame frame)
- {
- if (IsClass1DataAvailable(parameter))
- return GetClass1Data(parameter, frame);
- else if (IsClass2DataAvailable(parameter))
- return GetClass2Data(parameter, frame);
- else
- return NULL;
- }
- static bool
- IBalancedApplicationLayer_HandleReceivedData(void* parameter, uint8_t* msg, bool isBroadcast, int userDataStart, int userDataLength)
- {
- return HandleReceivedData(parameter, msg, isBroadcast, userDataStart, userDataLength);
- }
- static struct sIBalancedApplicationLayer cs101BalancedAppLayerInterface = {
- IBalancedApplicationLayer_GetUserData,
- IBalancedApplicationLayer_HandleReceivedData
- };
- CS101_Slave
- CS101_Slave_createEx(SerialPort serialPort, const LinkLayerParameters llParameters, const CS101_AppLayerParameters alParameters, IEC60870_LinkLayerMode linkLayerMode,
- int class1QueueSize, int class2QueueSize)
- {
- CS101_Slave self = (CS101_Slave) GLOBAL_MALLOC(sizeof(struct sCS101_Slave));
- if (self != NULL) {
- self->asduHandler = NULL;
- self->interrogationHandler = NULL;
- self->counterInterrogationHandler = NULL;
- self->readHandler = NULL;
- self->clockSyncHandler = NULL;
- self->resetProcessHandler = NULL;
- self->delayAcquisitionHandler = NULL;
- self->resetCUHandler = NULL;
- #if (CONFIG_USE_THREADS == 1)
- self->isRunning = false;
- self->workerThread = NULL;
- #endif
- if (llParameters)
- self->linkLayerParameters = *llParameters;
- else {
- self->linkLayerParameters.addressLength = 1;
- self->linkLayerParameters.timeoutForAck = 200;
- self->linkLayerParameters.timeoutRepeat = 1000;
- self->linkLayerParameters.useSingleCharACK = true;
- }
- if (alParameters)
- self->alParameters = *alParameters;
- else {
- self->alParameters = defaultAppLayerParameters;
- }
- self->transceiver = SerialTransceiverFT12_create(serialPort, &(self->linkLayerParameters));
- self->linkLayerMode = linkLayerMode;
- if (linkLayerMode == IEC60870_LINK_LAYER_UNBALANCED) {
- self->balancedLinkLayer = NULL;
- self->unbalancedLinkLayer = LinkLayerSecondaryUnbalanced_create(0, self->transceiver,
- &(self->linkLayerParameters),
- &cs101UnbalancedAppLayerInterface, self);
- }
- else {
- self->unbalancedLinkLayer = NULL;
- self->balancedLinkLayer = LinkLayerBalanced_create(0, self->transceiver,
- &(self->linkLayerParameters),
- &cs101BalancedAppLayerInterface, self);
- }
- self->iMasterConnection.isReady = isReady;
- self->iMasterConnection.sendASDU = sendASDU;
- self->iMasterConnection.sendACT_CON = sendACT_CON;
- self->iMasterConnection.sendACT_TERM = sendACT_TERM;
- self->iMasterConnection.getApplicationLayerParameters = getApplicationLayerParameters;
- self->iMasterConnection.close = NULL;
- self->iMasterConnection.getPeerAddress = NULL;
- self->iMasterConnection.object = self;
- CS101_Queue_initialize(&(self->userDataClass1Queue), class1QueueSize);
- CS101_Queue_initialize(&(self->userDataClass2Queue), class2QueueSize);
- self->plugins = NULL;
- }
- return self;
- }
- CS101_Slave
- CS101_Slave_create(SerialPort serialPort, const LinkLayerParameters llParameters, const CS101_AppLayerParameters alParameters, IEC60870_LinkLayerMode linkLayerMode)
- {
- return CS101_Slave_createEx(serialPort, llParameters, alParameters, linkLayerMode, CS101_MAX_QUEUE_SIZE, CS101_MAX_QUEUE_SIZE);
- }
- static void
- responseCOTUnknown(CS101_ASDU asdu, IMasterConnection self)
- {
- printf(" with unknown COT\n");
- CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);
- CS101_ASDU_setNegative(asdu, true);
- sendASDU(self, asdu);
- }
- /*
- * Handle received ASDUs
- *
- * Call the appropriate callbacks according to ASDU type and CoT
- */
- static void
- handleASDU(CS101_Slave self, CS101_ASDU asdu)
- {
- bool messageHandled = false;
- /* call plugins */
- if (self->plugins) {
- LinkedList pluginElem = LinkedList_getNext(self->plugins);
- while (pluginElem) {
- CS101_SlavePlugin plugin = (CS101_SlavePlugin) LinkedList_getData(pluginElem);
- CS101_SlavePlugin_Result result = plugin->handleAsdu(plugin->parameter, &(self->iMasterConnection), asdu);
- if (result == CS101_PLUGIN_RESULT_HANDLED) {
- return;
- }
- else if (result == CS101_PLUGIN_RESULT_INVALID_ASDU) {
- printf("Invalid message");
- }
- pluginElem = LinkedList_getNext(pluginElem);
- }
- }
- uint8_t cot = CS101_ASDU_getCOT(asdu);
- switch (CS101_ASDU_getTypeID(asdu)) {
- case C_IC_NA_1: /* 100 - interrogation command */
- printf("Rcvd interrogation command C_IC_NA_1\n");
- if ((cot == CS101_COT_ACTIVATION) || (cot == CS101_COT_DEACTIVATION)) {
- if (self->interrogationHandler != NULL) {
- union uInformationObject _io;
- InterrogationCommand irc = (InterrogationCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (irc) {
- if (self->interrogationHandler(self->interrogationHandlerParameter,
- &(self->iMasterConnection), asdu, InterrogationCommand_getQOI(irc)))
- messageHandled = true;
- }
- else {
- printf("Invalid message");
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- case C_CI_NA_1: /* 101 - counter interrogation command */
- printf("Rcvd counter interrogation command C_CI_NA_1\n");
- if ((cot == CS101_COT_ACTIVATION) || (cot == CS101_COT_DEACTIVATION)) {
- if (self->counterInterrogationHandler != NULL) {
- union uInformationObject _io;
- CounterInterrogationCommand cic = (CounterInterrogationCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (cic) {
- if (self->counterInterrogationHandler(self->counterInterrogationHandlerParameter,
- &(self->iMasterConnection), asdu, CounterInterrogationCommand_getQCC(cic)))
- messageHandled = true;
- }
- else {
- printf("Invalid message");
- return;
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- case C_RD_NA_1: /* 102 - read command */
- printf("Rcvd read command C_RD_NA_1\n");
- if (cot == CS101_COT_REQUEST) {
- if (self->readHandler != NULL) {
- union uInformationObject _io;
- ReadCommand rc = (ReadCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (rc) {
- if (self->readHandler(self->readHandlerParameter,
- &(self->iMasterConnection), asdu, InformationObject_getObjectAddress((InformationObject) rc)))
- messageHandled = true;
- }
- else {
- printf("Invalid message");
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- case C_CS_NA_1: /* 103 - Clock synchronization command */
- printf("Rcvd clock sync command C_CS_NA_1\n");
- if (cot == CS101_COT_ACTIVATION) {
- if (self->clockSyncHandler != NULL) {
- union uInformationObject _io;
- ClockSynchronizationCommand csc = (ClockSynchronizationCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (csc) {
- if (self->clockSyncHandler(self->clockSyncHandlerParameter,
- &(self->iMasterConnection), asdu, ClockSynchronizationCommand_getTime(csc)))
- messageHandled = true;
- if (messageHandled) {
- /* send ACT-CON message */
- CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
- CS101_Slave_enqueueUserDataClass1(self, asdu);
- }
- }
- else {
- printf("Invalid message");
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- case C_TS_NA_1: /* 104 - test command */
- printf("Rcvd test command C_TS_NA_1\n");
- if (cot != CS101_COT_ACTIVATION) {
- CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);
- CS101_ASDU_setNegative(asdu, true);
- }
- else
- CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
- CS101_Slave_enqueueUserDataClass1(self, asdu);
- messageHandled = true;
- break;
- case C_RP_NA_1: /* 105 - Reset process command */
- printf("Rcvd reset process command C_RP_NA_1\n");
- if (cot == CS101_COT_ACTIVATION) {
- if (self->resetProcessHandler != NULL) {
- union uInformationObject _io;
- ResetProcessCommand rpc = (ResetProcessCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (rpc) {
- if (self->resetProcessHandler(self->resetProcessHandlerParameter,
- &(self->iMasterConnection), asdu, ResetProcessCommand_getQRP(rpc)))
- messageHandled = true;
- }
- else {
- printf("Invalid reset-process-command message");
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- case C_CD_NA_1: /* 106 - Delay acquisition command */
- printf("Rcvd delay acquisition command C_CD_NA_1\n");
- if ((cot == CS101_COT_ACTIVATION) || (cot == CS101_COT_SPONTANEOUS)) {
- if (self->delayAcquisitionHandler != NULL) {
- union uInformationObject _io;
- DelayAcquisitionCommand dac = (DelayAcquisitionCommand) CS101_ASDU_getElementEx(asdu, (InformationObject) &_io, 0);
- if (dac) {
- if (self->delayAcquisitionHandler(self->delayAcquisitionHandlerParameter,
- &(self->iMasterConnection), asdu, DelayAcquisitionCommand_getDelay(dac)))
- messageHandled = true;
- }
- else {
- printf("Invalid message");
- }
- }
- }
- else
- responseCOTUnknown(asdu, &(self->iMasterConnection));
- break;
- default: /* no special handler available -> use default handler */
- break;
- }
- if ((messageHandled == false) && (self->asduHandler != NULL))
- if (self->asduHandler(self->asduHandlerParameter, &(self->iMasterConnection), asdu))
- messageHandled = true;
- if (messageHandled == false) {
- /* send error response */
- CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_TYPE_ID);
- CS101_ASDU_setNegative(asdu, true);
- CS101_Slave_enqueueUserDataClass1(self, asdu);
- }
- }
- void
- CS101_Slave_destroy(CS101_Slave self)
- {
- if (self != NULL) {
- if (self->unbalancedLinkLayer)
- LinkLayerSecondaryUnbalanced_destroy(self->unbalancedLinkLayer);
- if (self->balancedLinkLayer)
- LinkLayerBalanced_destroy(self->balancedLinkLayer);
- SerialTransceiverFT12_destroy(self->transceiver);
- CS101_Queue_dispose(&(self->userDataClass1Queue));
- CS101_Queue_dispose(&(self->userDataClass2Queue));
- if (self->plugins) {
- LinkedList_destroyStatic(self->plugins);
- }
- GLOBAL_FREEMEM(self);
- }
- }
- void
- CS101_Slave_run(CS101_Slave self)
- {
- if (self->unbalancedLinkLayer)
- LinkLayerSecondaryUnbalanced_run(self->unbalancedLinkLayer);
- else
- LinkLayerBalanced_run(self->balancedLinkLayer);
- /* call plugins */
- if (self->plugins) {
- LinkedList pluginElem = LinkedList_getNext(self->plugins);
- while (pluginElem) {
- CS101_SlavePlugin plugin = (CS101_SlavePlugin) LinkedList_getData(pluginElem);
- plugin->runTask(plugin->parameter, &(self->iMasterConnection));
- pluginElem = LinkedList_getNext(pluginElem);
- }
- }
- }
|