void gseDecodePDU(unsigned char *buf) { unsigned char tag = 0; CTYPE_INT16U lengthFieldSize = 0; CTYPE_INT16U lengthValue = 0; CTYPE_INT16U offsetForSequence = 0; CTYPE_INT16U offsetForNonSequence = 0; unsigned char *gocbRef = NULL; CTYPE_INT16U gocbRefLength = 0; CTYPE_INT32U timeAllowedToLive = 0; CTYPE_TIMESTAMP T = 0; CTYPE_INT32U sqNum = 0; CTYPE_INT32U stNum = 0; while (1) { tag = (unsigned char) buf[0]; // assumes only one byte is used lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]); lengthValue = decodeLength((unsigned char *) &buf[1]); offsetForSequence = 1 + lengthFieldSize; offsetForNonSequence = 1 + lengthFieldSize + lengthValue; switch (tag) { case GSE_TAG_GOCBREF: // save pointer to gocbRef name gocbRef = &buf[offsetForSequence]; gocbRefLength = lengthValue; buf = &buf[offsetForNonSequence]; break; case GSE_TAG_TIME_ALLOWED_TO_LIVE: ber_decode_integer(&buf[offsetForSequence], lengthValue, &timeAllowedToLive, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case ASN1_TAG_SEQUENCE: buf = &buf[offsetForSequence]; break; case GSE_TAG_DATSET: buf = &buf[offsetForNonSequence]; break; case GSE_TAG_T: memcpy(&T, &buf[offsetForSequence], BER_GET_LENGTH_CTYPE_TIMESTAMP(&T)); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_STNUM: ber_decode_integer(&buf[offsetForSequence], lengthValue, &stNum, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_SQNUM: ber_decode_integer(&buf[offsetForSequence], lengthValue, &sqNum, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_ALLDATA: gseDecodeDataset(&buf[offsetForSequence], lengthValue, gocbRef, gocbRefLength, timeAllowedToLive, T, stNum, sqNum); return; default: buf = &buf[offsetForNonSequence]; break; } } }
int ber_decode_myHealth(unsigned char *buf, struct myHealth *myHealth) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myHealth->stVal); } return offset; }
int ber_decode_myAnalogValue(unsigned char *buf, struct myAnalogValue *myAnalogValue) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &myAnalogValue->f); } return offset; }
int ber_decode_myINS(unsigned char *buf, struct myINS *myINS) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &myINS->stVal); } return offset; }
int ber_decode_ScaledValueConfig(unsigned char *buf, struct ScaledValueConfig *ScaledValueConfig) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &ScaledValueConfig->scaleFactor); offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &ScaledValueConfig->offset); } return offset; }
int ber_decode_myDPL(unsigned char *buf, struct myDPL *myDPL) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myDPL->vendor); offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myDPL->hwRev); } return offset; }
int ber_decode_simpleVector(unsigned char *buf, struct simpleVector *simpleVector) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_myAnalogValue(&buf[offset], &simpleVector->mag); offset += ber_decode_myAnalogValue(&buf[offset], &simpleVector->ang); } return offset; }
int ber_decode_simpleSAV(unsigned char *buf, struct simpleSAV *simpleSAV) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_myAnalogValue(&buf[offset], &simpleSAV->instMag); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleSAV->q); } return offset; }
int ber_decode_myCMV(unsigned char *buf, struct myCMV *myCMV) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_myVector(&buf[offset], &myCMV->cVal); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myCMV->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myCMV->t); } return offset; }
int ber_decode_simpleWYE(unsigned char *buf, struct simpleWYE *simpleWYE) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsA); offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsB); offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsC); } return offset; }
int BER_DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == ASN1_TAG_UNSIGNED) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); } return offset + len; }
int ber_decode_mySPS(unsigned char *buf, struct mySPS *mySPS) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &mySPS->stVal); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &mySPS->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &mySPS->t); } return offset; }
int BER_DECODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == 0x89) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); netmemcpy(value, &buf[offset], len); } return offset + len; }
int BER_DECODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == ASN1_TAG_BOOLEAN) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); netmemcpy(value, &buf[offset], len); } return offset + len; }
int ber_decode_mySEQ(unsigned char *buf, struct mySEQ *mySEQ) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_myCMV(&buf[offset], &mySEQ->c1); offset += ber_decode_myCMV(&buf[offset], &mySEQ->c2); offset += ber_decode_myCMV(&buf[offset], &mySEQ->c3); offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &mySEQ->seqT); } return offset; }
int ber_decode_myPos(unsigned char *buf, struct myPos *myPos) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_DBPOS(&buf[offset], &myPos->stVal); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myPos->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myPos->t); offset += BER_DECODE_CTYPE_BOOLEAN(&buf[offset], &myPos->ctlVal); } return offset; }
int BER_DECODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset] == ASN1_TAG_BIT_STRING) { offset++; len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); netmemcpy(value, &buf[offset + 1], len - 1); // skip over one byte (which contains number of unused bits) } return offset + len; }
int ber_decode_simpleMV(unsigned char *buf, struct simpleMV *simpleMV) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &simpleMV->mag); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleMV->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &simpleMV->t); offset += ber_decode_ScaledValueConfig(&buf[offset], &simpleMV->sVC); } return offset; }
int ber_decode_myMod(unsigned char *buf, struct myMod *myMod) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myMod->ctlVal); offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myMod->stVal); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myMod->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myMod->t); } return offset; }
int ber_decode_simpleCMV(unsigned char *buf, struct simpleCMV *simpleCMV) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_simpleVector(&buf[offset], &simpleCMV->cVal); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleCMV->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &simpleCMV->t); offset += ber_decode_mySPS(&buf[offset], &simpleCMV->testSecondLayerSDO); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &simpleCMV->testInteger); offset += BER_DECODE_CTYPE_BOOLEAN(&buf[offset], &simpleCMV->testBoolean); } return offset; }
int ber_decode_myMV(unsigned char *buf, struct myMV *myMV) { int offset = 0; if (buf[offset++] == 0xA2) { offset += getLengthFieldSize(buf[offset]); offset += ber_decode_myAnalogValue(&buf[offset], &myMV->mag); offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myMV->q); offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myMV->t); offset += ber_decode_ScaledValueConfig(&buf[offset], &myMV->sVC); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &myMV->int1); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &myMV->int2); offset += BER_DECODE_CTYPE_INT32(&buf[offset], &myMV->int3); } return offset; }
int BER_DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { // assuming enum is an int - allows any enum type to be used CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == ASN1_TAG_UNSIGNED) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); #if GOOSE_FIXED_SIZE == 1 ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT8); #else ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); #endif } return offset + len; }
int BER_DECODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == 0x87) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); // check for fixed-length GOOSE. If not, check for 11 bits for exponent if (len == 9 && buf[offset] == 0x0B) { netmemcpy(value, &buf[offset + 1], len - 1); } else if (len == 8) { netmemcpy(value, &buf[offset], len); } } return offset + len - 1; }