|
|
|
@ -70,20 +70,20 @@ struct sSVSubscriber {
|
|
|
|
|
struct sSVSubscriber_ASDU {
|
|
|
|
|
|
|
|
|
|
char* svId;
|
|
|
|
|
char* datSet;
|
|
|
|
|
|
|
|
|
|
uint8_t* smpCnt;
|
|
|
|
|
uint8_t* confRev;
|
|
|
|
|
uint8_t* refrTm;
|
|
|
|
|
uint8_t* smpSynch;
|
|
|
|
|
|
|
|
|
|
uint8_t* smpMod;
|
|
|
|
|
uint8_t* smpRate;
|
|
|
|
|
|
|
|
|
|
int dataBufferLength;
|
|
|
|
|
uint8_t* dataBuffer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SVReceiver
|
|
|
|
|
SVReceiver_create(void)
|
|
|
|
|
{
|
|
|
|
@ -208,7 +208,7 @@ SVReceiver_destroy(SVReceiver self)
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
EthernetSocket
|
|
|
|
|
SVReceiver_startThreadless(SVReceiver self)
|
|
|
|
|
{
|
|
|
|
|
if (self->interfaceId == NULL)
|
|
|
|
@ -219,6 +219,8 @@ SVReceiver_startThreadless(SVReceiver self)
|
|
|
|
|
Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV);
|
|
|
|
|
|
|
|
|
|
self->running = true;
|
|
|
|
|
|
|
|
|
|
return self->ethSocket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -229,29 +231,26 @@ SVReceiver_stopThreadless(SVReceiver self)
|
|
|
|
|
self->running = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SVReceiver_addHandleSet(SVReceiver self, EthernetHandleSet handles)
|
|
|
|
|
{
|
|
|
|
|
return EthernetHandleSet_addSocket(handles, self->ethSocket);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length)
|
|
|
|
|
{
|
|
|
|
|
int bufPos = 0;
|
|
|
|
|
int svIdLength = 0;
|
|
|
|
|
int datSetLength = 0;
|
|
|
|
|
|
|
|
|
|
struct sSVSubscriber_ASDU asdu;
|
|
|
|
|
memset(&asdu, 0, sizeof(struct sSVSubscriber_ASDU));
|
|
|
|
|
|
|
|
|
|
int svIdLength = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (bufPos < length) {
|
|
|
|
|
int elementLength;
|
|
|
|
|
|
|
|
|
|
uint8_t tag = buffer[bufPos++];
|
|
|
|
|
|
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, length);
|
|
|
|
|
if (bufPos < 0) {
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
|
|
|
|
|
@ -260,6 +259,11 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length)
|
|
|
|
|
svIdLength = elementLength;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x81:
|
|
|
|
|
asdu.datSet = (char*) (buffer + bufPos);
|
|
|
|
|
datSetLength = elementLength;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x82:
|
|
|
|
|
asdu.smpCnt = buffer + bufPos;
|
|
|
|
|
break;
|
|
|
|
@ -276,12 +280,21 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length)
|
|
|
|
|
asdu.smpSynch = buffer + bufPos;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x86:
|
|
|
|
|
asdu.smpRate = buffer + bufPos;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x87:
|
|
|
|
|
asdu.dataBuffer = buffer + bufPos;
|
|
|
|
|
asdu.dataBufferLength = elementLength;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x88:
|
|
|
|
|
asdu.smpMod = buffer + bufPos;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* ignore unknown tag */
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -290,6 +303,25 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length)
|
|
|
|
|
|
|
|
|
|
if (asdu.svId != NULL)
|
|
|
|
|
asdu.svId[svIdLength] = 0;
|
|
|
|
|
if (asdu.datSet != NULL)
|
|
|
|
|
asdu.datSet[datSetLength] = 0;
|
|
|
|
|
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) {
|
|
|
|
|
printf("SV_SUBSCRIBER: SV ASDU: ----------------\n");
|
|
|
|
|
printf("SV_SUBSCRIBER: DataLength: %d\n", asdu.dataBufferLength);
|
|
|
|
|
printf("SV_SUBSCRIBER: SvId: %s\n", asdu.svId);
|
|
|
|
|
printf("SV_SUBSCRIBER: SmpCnt: %d\n", SVSubscriber_ASDU_getSmpCnt(&asdu));
|
|
|
|
|
printf("SV_SUBSCRIBER: ConfRev: %d\n", SVSubscriber_ASDU_getConfRev(&asdu));
|
|
|
|
|
|
|
|
|
|
if (SVSubscriber_ASDU_hasDatSet(&asdu))
|
|
|
|
|
printf("SV_SUBSCRIBER: DatSet: %s\n", asdu.datSet);
|
|
|
|
|
if (SVSubscriber_ASDU_hasRefrTm(&asdu))
|
|
|
|
|
printf("SV_SUBSCRIBER: RefrTm: %lu\n", SVSubscriber_ASDU_getRefrTmAsMs(&asdu));
|
|
|
|
|
if (SVSubscriber_ASDU_hasSmpMod(&asdu))
|
|
|
|
|
printf("SV_SUBSCRIBER: SmpMod: %d\n", SVSubscriber_ASDU_getSmpMod(&asdu));
|
|
|
|
|
if (SVSubscriber_ASDU_hasSmpRate(&asdu))
|
|
|
|
|
printf("SV_SUBSCRIBER: SmpRate: %d\n", SVSubscriber_ASDU_getSmpRate(&asdu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call callback handler */
|
|
|
|
|
if (subscriber->listener != NULL)
|
|
|
|
@ -307,6 +339,10 @@ parseSequenceOfASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, i
|
|
|
|
|
uint8_t tag = buffer[bufPos++];
|
|
|
|
|
|
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, length);
|
|
|
|
|
if (bufPos < 0) {
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
|
case 0x30:
|
|
|
|
@ -314,6 +350,7 @@ parseSequenceOfASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, i
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* ignore unknown tag */
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -330,6 +367,10 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap
|
|
|
|
|
int elementLength;
|
|
|
|
|
|
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength);
|
|
|
|
|
if (bufPos < 0) {
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int svEnd = bufPos + elementLength;
|
|
|
|
|
|
|
|
|
@ -337,6 +378,10 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap
|
|
|
|
|
uint8_t tag = buffer[bufPos++];
|
|
|
|
|
|
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, svEnd);
|
|
|
|
|
if (bufPos < 0) {
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bufPos + elementLength > apduLength) {
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER)
|
|
|
|
@ -358,6 +403,7 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* ignore unknown tag */
|
|
|
|
|
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -585,6 +631,23 @@ SVSubscriber_ASDU_hasRefrTm(SVSubscriber_ASDU self)
|
|
|
|
|
return (self->refrTm != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
SVSubscriber_ASDU_hasDatSet(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
return (self->datSet != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
SVSubscriber_ASDU_hasSmpRate(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
return (self->smpRate != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
SVSubscriber_ASDU_hasSmpMod(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
return (self->smpMod != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self)
|
|
|
|
@ -592,6 +655,12 @@ SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self)
|
|
|
|
|
return self->svId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
SVSubscriber_ASDU_getDatSet(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
return self->datSet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
|
SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
@ -606,6 +675,28 @@ SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self)
|
|
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
SVSubscriber_ASDU_getSmpMod(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
uint8_t retVal = *((uint8_t*) (self->smpMod));
|
|
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
|
SVSubscriber_ASDU_getSmpRate(SVSubscriber_ASDU self)
|
|
|
|
|
{
|
|
|
|
|
uint16_t retVal = *((uint16_t*) (self->smpRate));
|
|
|
|
|
|
|
|
|
|
#if (ORDER_LITTLE_ENDIAN == 1)
|
|
|
|
|
uint8_t* buf = (uint8_t*) (&retVal);
|
|
|
|
|
|
|
|
|
|
BerEncoder_revertByteOrder(buf, 2);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int8_t
|
|
|
|
|
SVSubscriber_ASDU_getINT8(SVSubscriber_ASDU self, int index)
|
|
|
|
|
{
|
|
|
|
|