commit f0160a5dfb88761f8009b18811c1058c1d341dcf Author: cfif Date: Wed Dec 4 13:10:48 2024 +0300 Init diff --git a/Inc/EgtsTimestamp.h b/Inc/EgtsTimestamp.h new file mode 100644 index 0000000..1b5fe27 --- /dev/null +++ b/Inc/EgtsTimestamp.h @@ -0,0 +1,13 @@ +// +// Created by xemon on 06.07.23. +// + +#ifndef MODULE_EGTSTIMESTAMP_H +#define MODULE_EGTSTIMESTAMP_H + +#include "stdint.h" + +uint32_t Egts_EpochTimestampToEgtsTime(uint32_t ts); +uint32_t Egts_EpochEgtsTimeToTimestamp(uint32_t ts); + +#endif //MODULE_EGTSTIMESTAMP_H diff --git a/Inc/egts.h b/Inc/egts.h new file mode 100644 index 0000000..1198c77 --- /dev/null +++ b/Inc/egts.h @@ -0,0 +1,296 @@ +/* + * egts.h + * + * Created on: Jun 4, 2021 + * Author: zemon + */ + +#ifndef EGTS_INC_EGTS_H_ +#define EGTS_INC_EGTS_H_ + +#include +#include "stdbool.h" + +#define TRANSPORT_HEADER_LENGTH 11 + +#define EGTS_SERVICE_FLAGS_MSD 0x94 +#define EGTS_SERVICE_FLAGS_POS 0x04 +#define EGTS_SERVICE_FLAGS_AUTH 0x9c +#define EGTS_SERVICE_FLAGS_COMMAND 0x9c +#define EGTS_SERVICE_FLAGS_TELEDATA 0x9c +#define EGTS_SERVICE_FLAGS_FIRMWARE 0x9c +#define EGTS_SERVICE_FLAGS_COMMAND 0x9c + +typedef enum { + EGTS_SR_RECORD_RESPONSE = 0x00, + + //EGTS_AUTH_SERVICE + EGTS_SR_TERM_IDENTITY = 0x01, + + EGTS_SR_MODULE_DATA = 0x02, + + //EGTS_COMMANDS_SERVICE + EGTS_SR_COMMAND_DATA = 0x33, + + //EGTS_TELEDATA_SERVICE + EGTS_SR_POS_DATA = 0x10, + + //EGTS_TELEDATA_SERVICE + EGTS_SR_AD_SENSORS_DATA = 0x12, + + //EGTS_ECALL_SERVICE + EGTS_SR_RAW_MSD_DATA = 0x28, + + //EGTS_EUROPROTOCOL_SERVICE + EGTS_SR_EP_MAIN_DATA = 0x01, + EGTS_SR_EP_TRACK_DATA = 0x02, + EGTS_SR_EP_ACCEL_DATA = 0x03, + + EGTS_SR_ABS_DIG_SENS_DATA = 0x17, + EGTS_SR_ABS_AN_SENS_DATA = 0x18, + + EGTS_SR_SERVICE_PART_DATA = 0x21, + + EGTS_SR_RESULT_CODE = 0x09, + +} eEgtsSubRecordId; + +typedef enum { + EGTS_AUTH_SERVICE = 0x01, + EGTS_TELEDATA_SERVICE = 0x02, + EGTS_COMMANDS_SERVICE = 0x04, + EGTS_FIRMWARE_SERVICE = 0x09, + EGTS_ECALL_SERVICE = 0x0A, + EGTS_EUROPROTOCOL_SERVICE = 0x16, + EGTS_NOTIFICATION_SERVICE = 0x28, +} eEgtsServiceId; + +typedef enum { + EGTS_PT_RESPONSE = 0x00,//(подтверждение на пакет транспортного уровня); + EGTS_PT_APPDATA = 0x01, //(пакет, содержащий данные протокола уровня поддержки услуг); + EGTS_PT_SIGNED_APPDATA = 0x02, +} eEgtsPacketTypeId; + +typedef uint16_t(*tEgtsServiceSubRecordGenerator)(uint8_t *out, void *args); + +uint32_t toEgtsTimestamp(uint32_t ts); + + +////TERM_IDENTITY########## +typedef struct { + uint8_t *IMEI; + uint8_t IMEI_len; + uint32_t TerminalID; +// uint32_t epochTimestamp; +} tEgtsTermIdentityArgs; + +#define vEgtsPackTermIdentityGen (tEgtsServiceSubRecordGenerator) vEgtsPackTermIdentity + +uint16_t vEgtsPackTermIdentity(uint8_t *out, tEgtsTermIdentityArgs *args); +////################## + + +////CMD CONFIRMATION DATA ########## +typedef struct { + uint16_t ADR; + uint8_t SZ; + uint8_t ACT; + uint16_t CCD; + uint16_t DT; +} tEgtsSrCmdConfirmationComData; + +////CMD CONFIRMATION ########## +typedef struct { + uint8_t CT; + uint8_t CCT; + uint32_t CID; + uint32_t SID; + uint8_t ACFE; + uint8_t CHSFE; + uint8_t CHS; + uint8_t ACL; + uint16_t AC; + tEgtsSrCmdConfirmationComData CmdData; +} tEgtsSrCmdConfirmation; + +uint16_t vEgtsPacSrCommandDataResponse(uint8_t *out, tEgtsSrCmdConfirmation *args); + +#define vEgtsPacSrCommandDataResponseGen (tEgtsServiceSubRecordGenerator) vEgtsPacSrCommandDataResponse +////################## + + +////RESPONSE ########## +typedef struct { + uint16_t CRN; + uint8_t RST; +} tEgtsRecordResponseData; + +uint16_t vEgtsPackResponse(uint8_t *out, tEgtsRecordResponseData *args); + +#define vEgtsPackResponseGen (tEgtsServiceSubRecordGenerator) vEgtsPackResponse +////################## + + + +////POS DATA########## +typedef struct { + double latitude; + double longitude; + uint16_t velocity; + uint32_t epochTimestamp; +} tEgtsPosDataArgs; + + +#define vEgtsPackPosDataGen (tEgtsServiceSubRecordGenerator) vEgtsPackPosData + +uint16_t vEgtsPackPosData(uint8_t *out, tEgtsPosDataArgs *args); +////################## + +#define SENSOR_NO (0x00) +#define SENSOR_1 (0x01) +#define SENSOR_2 (0x01<<1) +#define SENSOR_3 (0x01<<2) +#define SENSOR_4 (0x01<<3) +#define SENSOR_5 (0x01<<4) +#define SENSOR_6 (0x01<<5) +#define SENSOR_7 (0x01<<6) +#define SENSOR_8 (0x01<<7) + +////SENSORS DATA########## +typedef struct { + uint8_t digitalInPresent; + uint8_t digitalOutPresent; + uint8_t analogInPresent; + uint8_t digitalIn[8]; + uint32_t analogIn[8]; +} tEgtsSensorsDataArgs; + +#define vEgtsPackSensorsDataGen (tEgtsServiceSubRecordGenerator) vEgtsPackSensorsData + +uint16_t vEgtsPackSensorsData(uint8_t *out, tEgtsSensorsDataArgs *args); +////################## + + + +////MSD DATA########## +typedef struct { + uint8_t *msd; + uint8_t msdLength; +} tEgtsMsdDataArgs; + +#define vEgtsPackMsdDataGen (tEgtsServiceSubRecordGenerator) vEgtsPackMsdData + +uint16_t vEgtsPackMsdData(uint8_t *out, tEgtsMsdDataArgs *args); +// +//uint16_t vEgtsPackMsdResp(uint8_t *out, tEgtsRecordResponseData *args); +////################## + + +////MSD DATA########## + +typedef struct { + bool LOHS; + bool LAHS; + uint16_t speed; + bool TrackDataExist; + + uint32_t Latitude; + uint32_t Longitude; + + bool AltitudeDirection; + uint16_t Altitude; + uint16_t Direction; +} tEgtsTrackData; + +typedef struct { + bool DataValid; + uint8_t TimeShift; + bool type; +} tEgtsRelativeTrackData; + +typedef struct { + uint16_t blockNumber; + uint32_t absoluteTime; + + uint8_t relativeAmount; + uint8_t timeShift; + bool CoordinateSystem; + bool RTU; + + tEgtsTrackData originPoint; + +} tEgtsSrEpTrackDataArgs; + +uint16_t vEgtsPackSrEpTrackData(uint8_t *out, tEgtsSrEpTrackDataArgs *args); + +#define vEgtsPackSrEpTrackDataGen (tEgtsServiceSubRecordGenerator) vEgtsPackSrEpTrackData +////################## + + +uint16_t vEgtsPackSrv( + uint8_t *out, + uint8_t flags, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGenerator subRecGen, + void *subRecArgs +); + +uint16_t vEgtsPackTransport( + uint16_t cid, + uint16_t packetId, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGenerator subRecGen, + void *subRecArgs +); + +uint16_t vEgtsPackMsdTransport(uint16_t packetId, uint8_t *out, uint8_t *msd, uint8_t msdLength, uint32_t timestamp); + +uint16_t +vEgtsPackEgtsResponse(uint16_t packetId, uint8_t *out, uint8_t rst, uint16_t crn, uint16_t cid, uint32_t timestamp); + +uint16_t vEgtsPackSrCmdConfirmation( + uint8_t *out, + uint16_t packetId, + uint16_t cmdType, + uint16_t cmdConfirType, + uint16_t cid, + uint16_t sid, + uint16_t acfe, + uint16_t chsfe, + uint16_t adr, + uint8_t sz, + uint8_t act, + uint16_t ccd, + uint32_t dt +); + +uint16_t vEgtsPackTeledataTransport( + uint16_t packetId, + uint8_t *out, + double Latitude, + double Longitude, + uint16_t velocity, + uint32_t timestamp +); + +uint16_t vEgtsPackTermIdentityTransport( + uint16_t packetId, uint8_t *out, uint8_t *IMEI, uint8_t IMEI_len, uint32_t TerminalID, uint32_t timestamp +); + +uint16_t vEgtsPackSensorsTransport( + uint16_t packetId, + uint8_t *out, + uint32_t epochTimestamp, + tEgtsSensorsDataArgs *sensors +); + +#endif /* EGTS_INC_EGTS_H_ */ diff --git a/Inc/egtsWorker.h b/Inc/egtsWorker.h new file mode 100644 index 0000000..d53c824 --- /dev/null +++ b/Inc/egtsWorker.h @@ -0,0 +1,253 @@ +// +// Created by zemon on 05.01.23. +// + +#ifndef UVEOS_ON_NATION_EGTSWORKER_H +#define UVEOS_ON_NATION_EGTSWORKER_H + +#include "stdint.h" +#include "stdbool.h" +#include "stddef.h" +#include "stdbool.h" +#include "egts.h" +#include "BaseTypes/Strings.h" + +#define EGTS_WORKING_BUFFER_LENGTH 512 + +//#define EGTS_SR_COMMAND_DATA 0x04 + +#define EGTS_FLEET_GET_POS_DATA 0x000C + +//CMDS + +// AURUS +#define EGTS_AURUS_SET_TIME 0xFAC4 + +//#define EGTS_RAW_DATA 0x0000 +#define EGTS_ECALL_MSD_REQ 0x0113 +#define EGTS_START_SEND_READY 0x510A +#define EGTS_STOP_SEND_READY 0x510B +#define EGTS_SEND_ACCIDENT_DATA 0x060C +#define EGTS_ECALL_REQ 0x0112 +#define EGTS_ECALL_TEST_NUMBER 0x020d +#define EGTS_ECALL_SMS_FALLBACK_NUMBER 0x0223 +#define EGTS_FLEET_MAX_SPEED_THRESHOLD 0x0266 + +// Command Туре +#define CT_COMCONF 0b0001 +#define CT_MSGCONF 0b0010 +#define CT_MSGFROM 0b0011 +#define CT_MSGTO 0b0100 +#define CT_COM 0b0101 +#define CT_DELCOM 0b0110 +#define CT_SUBREQ 0b0111 +#define CT_DELIV 0b1000 + +// Command Confirmation Type +#define CC_OK 0b0000 +#define CC_ERROR 0b0001 +#define CC_ILL 0b0010 +#define CC_DEL 0b0011 +#define CC_NFOUND 0b0100 +#define CC_NCONF 0b0101 +#define CC_INPROG 0b0110 + +// Command Codes +#define EGTS_RAW_DATA 0b0000 +#define EGTS_TEST_MODE 0b0001 +#define EGTS_CONFIG_RESET 0b0006 +#define EGTS_SET_AUTH_CODE 0b0007 +#define EGTS_RESTART 0b0108 + +//SR +#define EGTS_SR_COMMAND_DATA_CMD_OFFSET 13 + +#define EGTS_SR_NOTIFICATION_DATA 3 +#define EGTS_SR_NOTIFICATION_PART_DATA 4 +#define EGTS_SR_NOTIFICATION_FULL_DATA 5 + +//EGTS_ECALL_REQ_TYPE +#define EGTS_ECALL_REQ_MANUAL 0 +#define EGTS_ECALL_REQ_AUTOMATIC 1 + +//EGTS_ECALL_MSD_REQ_TRANSPORT_TYPE +#define EGTS_ECALL_MSD_REQ_TRANSPORT_ANY 0 +#define EGTS_ECALL_MSD_REQ_TRANSPORT_SMS 2 + +typedef struct { + uint8_t flags; + uint8_t count; + uint16_t notifications[128]; + + uint8_t storeHours; + uint8_t repeatCount; + uint8_t repeatIntervalMin; +} EgtsSrNotificationData; + +typedef struct { + + uint8_t headerLength; + + uint8_t *header; + + uint8_t mandatory; + uint8_t expiration; + + uint8_t storeHours; + uint8_t repeatCount; + uint8_t repeatIntervalMin; + +} EgtsSrNotificationFullData; + +typedef struct { + uint16_t reqType; +} tEgtsEcallReq; + +typedef struct { + int32_t mid; + uint8_t transport; +} tEgtsEcallMsdReq; + +typedef struct { + uint32_t profile; + bool enabled; +} tEgtsNextCmd; + +typedef union { + tEgtsEcallReq ecallReq; + tEgtsEcallMsdReq msdReq; + tEgtsNextCmd next; + tString32 newFallbackNumber; + int32_t arr[5]; +} uEgtsSrCommandData; + +typedef struct { + uint8_t cmdType; + uint8_t cmdConfirmationType; + + uint32_t cmdId; + uint32_t srcId; + + bool hasAuth; + bool hasCharset; + uint8_t charset; + uint8_t authLen; + uint8_t auth[255]; + + uint16_t address; + uint8_t size; + uint8_t act; + uint16_t cmd; + uEgtsSrCommandData data; + + void *dataPointer; + +} EgtsSrCommand; + +typedef struct __attribute__ ((packed)) { + uint8_t MT: 2; + uint8_t OT: 2; + uint8_t Reserve: 4; +} tOA; + +typedef struct { + uint16_t Identity; + uint16_t PartNumber; + uint16_t ExpectedPartsQuantity; + + tOA ObjectAttribute; + uint8_t ComponentOrModuleIdentifier; + uint16_t Version; + uint16_t WholeObjectSignature; + char FileName[65]; + + void *dataPointer; + uint16_t dataLength; + +} EgtsFirmware; + +typedef union { + EgtsFirmware firmware; + EgtsSrCommand cmd; + EgtsSrNotificationData notificationData; +} EgtsSubRecMemAlloc; + +typedef struct { + uint8_t protocol; + uint8_t SecKeyID; + uint8_t flags; + uint8_t headerLength; + uint16_t frameDataLength; + uint16_t packetId; + uint8_t encoding; + uint8_t type; + uint8_t crc; +} EgtsHeader; + +typedef struct { + uint16_t responsePacketId; + uint8_t status; +} EgtsPtResponse; + +typedef struct { + size_t (*readData)(void *env, uint8_t *data, size_t size); + + void *readDataEnv; + + EgtsHeader header; + EgtsPtResponse ptResponse; + uint8_t *workingBuffer; + uint16_t workingBufferLength; + uint32_t workingBufferLimit; + uint8_t headerLength; + uint16_t frameDataLength; + uint8_t frameDataSrcLength; + uint8_t *frameData; + uint8_t *record; + uint16_t recordLength; + uint16_t recordNumber; + uint8_t recordFlags; + + bool recHasTime; + bool recHasEvent; + bool recHasObj; + + eEgtsServiceId recSourceService; + eEgtsServiceId recRecipientService; + + uint8_t *recordData; + uint8_t subRecType; + uint16_t subRecLength; + uint8_t *subRecData; + EgtsSubRecMemAlloc subRecMemAlloc; + + EgtsSrNotificationData *srNotificationData; + EgtsSrCommand *srCommand; + EgtsFirmware *firmware; + +} EgtsWorkerEnvironment; + + +//void EgtsWorkerLoadPreBuffer(EgtsWorkerEnvironment *env, uint8_t *data, uint16_t dataLength); + +//bool EgtsWorkerReadPreBuffer(EgtsWorkerEnvironment *env, uint8_t *data); + +bool EgtsCompleteTransport(EgtsWorkerEnvironment *env); + +bool EgtsIsTransportComplete(EgtsWorkerEnvironment *env); + +void EgtsParseHeader(EgtsWorkerEnvironment *env); + +void EgtsParseFrameData(EgtsWorkerEnvironment *env); + +void EgtsParseSrvRecord(EgtsWorkerEnvironment *env); + +void EgtsResetBuffer(EgtsWorkerEnvironment *env); + +uint16_t EgtsGetTransportFullLength(EgtsWorkerEnvironment *env); + +void EgtsParseSrvNotificationData(uint8_t *rec, EgtsSrNotificationData *notificationData); + +void EgtsParseSrvSubRecord(EgtsWorkerEnvironment *env, uint8_t *subRecRaw); + +#endif //UVEOS_ON_NATION_EGTSWORKER_H diff --git a/Inc/egtsWorkerExt.h b/Inc/egtsWorkerExt.h new file mode 100644 index 0000000..846cb6d --- /dev/null +++ b/Inc/egtsWorkerExt.h @@ -0,0 +1,37 @@ +// +// Created by cfif on 18.05.2024. +// + +#ifndef SMART_COMPONENTS_EGTSWORKEREXT_H +#define SMART_COMPONENTS_EGTSWORKEREXT_H + +#include "egtsWorker.h" + +typedef enum { + EGTS_COMPLETE_OK = 0x00, + EGTS_COMPLETE_WAIT = 0x01, + EGTS_COMPLETE_HEADER_ERR_CRC = 0x02, + EGTS_COMPLETE_BODY_ERR_CRC = 0x03, + EGTS_COMPLETE_ERR_VER = 0x04, + EGTS_COMPLETE_ERR_OVERFLOW = 0x05 +} eEgts_CompleteResult; + +typedef struct { + eEgts_CompleteResult completeResult; + uint8_t calcHeaderCrc; + uint8_t receivedHeaderCrc; + uint16_t calcBodyCrc; + uint16_t receivedBodyCrc; + + uint16_t fullLength; + +} EgtsCompleteResult; + + +bool EgtsParseHeaderExt(EgtsWorkerEnvironment *env); +uint16_t EgtsParseSrvRecordExt(EgtsWorkerEnvironment *env, uint8_t *record); + +EgtsCompleteResult* EgtsCompleteTransportExt(EgtsWorkerEnvironment *env); +eEgts_CompleteResult EgtsIsTransportCompleteExt(EgtsWorkerEnvironment *env); + +#endif //SMART_COMPONENTS_EGTSWORKEREXT_H diff --git a/Inc/egts_commonExt.h b/Inc/egts_commonExt.h new file mode 100644 index 0000000..3a15dd8 --- /dev/null +++ b/Inc/egts_commonExt.h @@ -0,0 +1,92 @@ +// +// Created by cfif on 22.04.2024. +// + +#ifndef SMART_COMPONENTS_EGTS_COMMONEXT_H +#define SMART_COMPONENTS_EGTS_COMMONEXT_H +#include "egts.h" +#include "egts_crc.h" + +typedef uint16_t(*tEgtsServiceSubRecordGeneratorEx)(uint8_t *out, void *args, uint16_t step); + +uint16_t vEgtsPackSrvEx( + uint8_t *out, + uint16_t counter, + uint8_t flags, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t epochTimestamp, + uint16_t subRecordCount, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGeneratorEx subRecGen, + void *subRecArgs +); + +uint16_t vEgtsPackTransportEx1( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + uint16_t subRecordCount, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGeneratorEx subRecGen, + void *subRecArgs +); + +uint16_t vEgtsPackTransportEx2( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + + uint16_t subRecordCount1, + eEgtsSubRecordId subRecordType1, + tEgtsServiceSubRecordGeneratorEx subRecGen1, + void *subRecArgs1, + + uint16_t subRecordCount2, + eEgtsSubRecordId subRecordType2, + tEgtsServiceSubRecordGeneratorEx subRecGen2, + void *subRecArgs2 + +); + +uint16_t vEgtsPackTransportEx3( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + + uint16_t subRecordCount1, + eEgtsSubRecordId subRecordType1, + tEgtsServiceSubRecordGeneratorEx subRecGen1, + void *subRecArgs1, + + uint16_t subRecordCount2, + eEgtsSubRecordId subRecordType2, + tEgtsServiceSubRecordGeneratorEx subRecGen2, + void *subRecArgs2, + + uint16_t subRecordCount3, + eEgtsSubRecordId subRecordType3, + tEgtsServiceSubRecordGeneratorEx subRecGen3, + void *subRecArgs3 + +); + +#endif //SMART_COMPONENTS_EGTS_COMMONEXT_H diff --git a/Inc/egts_crc.h b/Inc/egts_crc.h new file mode 100644 index 0000000..04dfa9c --- /dev/null +++ b/Inc/egts_crc.h @@ -0,0 +1,16 @@ +/* + * egts_crc.h + * + * Created on: Oct 2, 2020 + * Author: FICOM-IT LTD + */ + +#ifndef INC_EGTS_CRC_H_ +#define INC_EGTS_CRC_H_ + +#include + +uint8_t CRC8EGTS(unsigned char *lpBlock, unsigned char len); +uint16_t CRC16EGTS(unsigned char * pcBlock, unsigned int len); + +#endif /* INC_EGTS_CRC_H_ */ diff --git a/Src/EgtsTimestamp.c b/Src/EgtsTimestamp.c new file mode 100644 index 0000000..e919516 --- /dev/null +++ b/Src/EgtsTimestamp.c @@ -0,0 +1,14 @@ +// +// Created by xemon on 06.07.23. +// +#include "EgtsTimestamp.h" + +#define EGTS_TIMESTAMP_EPOCH_OFFSET 1262304000 // epoch timestamp of Fri, 01 Jan 2010 00:00:00 GMT + +uint32_t Egts_EpochTimestampToEgtsTime(uint32_t ts) { + return ts - EGTS_TIMESTAMP_EPOCH_OFFSET; +} + +uint32_t Egts_EpochEgtsTimeToTimestamp(uint32_t ts) { + return ts + EGTS_TIMESTAMP_EPOCH_OFFSET; +} \ No newline at end of file diff --git a/Src/egtsWorker.c b/Src/egtsWorker.c new file mode 100644 index 0000000..89c63d2 --- /dev/null +++ b/Src/egtsWorker.c @@ -0,0 +1,289 @@ +// +// Created by zemon on 23.12.2021. +// + +#include "SystemDelayInterface.h" +#include +#include "egtsWorker.h" +#include "string.h" + + +//bool EgtsWorkerLoadPreBuffer(EgtsWorkerEnvironment *env, uint8_t *data, uint16_t dataLength) { +// +// uint8_t *data_end = data + dataLength; +// uint32_t END = HAL_GetTick() + 10000; +// +// while (data != data_end) { +// xQueueSend(env->xQueueRxData, data, 1); +// ++data; +// +// if(END < HAL_GetTick()){ +// return false; +// } +// } +// +// return true; +// +//} +// +//bool EgtsWorkerReadPreBuffer(EgtsWorkerEnvironment *env, uint8_t *data) { +// return xQueueReceive(env->xQueueRxData, data, 0) != pdTRUE ? false : true; +//} + + +#define EGTS_STATIC_HEADER_LENGTH 10 + +uint8_t EgtsGetTransportHeaderLength(EgtsWorkerEnvironment *env) { + return env->workingBuffer[3]; +} + +void EgtsResetBuffer(EgtsWorkerEnvironment *env) { + memset(env->workingBuffer, 0, env->workingBufferLength); + memset(&env->subRecMemAlloc, 0, sizeof(EgtsSubRecMemAlloc)); + memset(&env->header, 0, sizeof(EgtsHeader)); + memset(&env->ptResponse, 0, sizeof(EgtsPtResponse)); + + env->srNotificationData = NULL; + env->srCommand = NULL; + + + env->workingBufferLength = 0; +} + +uint16_t EgtsGetTransportFrameDataLength(EgtsWorkerEnvironment *env) { + return *((uint16_t *) (env->workingBuffer + 5)); +} + +uint16_t EgtsGetTransportFullLength(EgtsWorkerEnvironment *env) { + env->headerLength = EgtsGetTransportHeaderLength(env); + env->frameDataLength = EgtsGetTransportFrameDataLength(env); + env->frameDataSrcLength = (env->frameDataLength > 0) ? 2 : 0; + return env->headerLength + env->frameDataLength + env->frameDataSrcLength; +} + +bool EgtsCompleteTransport(EgtsWorkerEnvironment *env) { + + size_t read = env->readData( + env->readDataEnv, + env->workingBuffer + env->workingBufferLength, + EGTS_STATIC_HEADER_LENGTH - env->workingBufferLength + ); + + env->workingBufferLength += read; + + if (env->workingBufferLength < EGTS_STATIC_HEADER_LENGTH) { + return false; + } + + uint16_t fullLength = EgtsGetTransportFullLength(env); + read = env->readData( + env->readDataEnv, + env->workingBuffer + env->workingBufferLength, + fullLength - env->workingBufferLength + ); + + env->workingBufferLength += read; + + if (env->workingBufferLength < fullLength) { + return false; + } + + return true; +} + +bool EgtsIsTransportComplete(EgtsWorkerEnvironment *env) { + + if (env->workingBufferLength < EGTS_STATIC_HEADER_LENGTH) { + return false; + } + uint16_t fullLength = EgtsGetTransportFullLength(env); + if (env->workingBufferLength < fullLength) { + return false; + } + + return true; +} + +void EgtsParseHeader(EgtsWorkerEnvironment *env) { +// uint8_t protocol; +// uint8_t SecKeyID; +// uint8_t flags; +// uint16_t length; +// uint8_t encoding; +// uint16_t id; +// uint8_t type; +// uint8_t crc; + + env->header.protocol = *env->workingBuffer; + env->header.SecKeyID = *(env->workingBuffer + 1); + env->header.flags = *(env->workingBuffer + 2); + env->header.headerLength = *(uint8_t *) (env->workingBuffer + 3); + env->header.encoding = *(env->workingBuffer + 4); + env->header.frameDataLength = *(uint16_t *) (env->workingBuffer + 5); + env->header.packetId = *(uint16_t *) (env->workingBuffer + 7); + env->header.type = *(uint8_t *) (env->workingBuffer + 9); + env->header.crc = *(env->workingBuffer + 10); + +} + + +void EgtsParseFrameData(EgtsWorkerEnvironment *env) { + env->frameData = env->workingBuffer + env->headerLength; + + if (env->header.type == EGTS_PT_RESPONSE) { + env->ptResponse.responsePacketId = *(uint16_t *) (env->frameData); + env->ptResponse.status = *(env->frameData + 2); + env->record = (env->frameData + 3); + } else { + env->record = env->frameData; + } + +} + + +void EgtsParseSrvSubRecordSrCommand(EgtsWorkerEnvironment *env) { + uint16_t inRecOffset = 0; + + env->srCommand->cmdType = *((uint8_t *) env->subRecData + inRecOffset) >> 0x4; + env->srCommand->cmdConfirmationType = *((uint8_t *) env->subRecData + inRecOffset) & 0b1111; + inRecOffset += 1; + + env->srCommand->cmdId = *((uint32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + env->srCommand->srcId = *((uint32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + uint8_t flags = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + env->srCommand->hasCharset = flags & 0b1; + env->srCommand->hasAuth = (flags >> 0x1) & 0b1; + + if (env->srCommand->hasCharset) { + env->srCommand->charset = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + } + + if (env->srCommand->hasAuth) { + env->srCommand->authLen = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + memcpy(env->srCommand->auth, (env->subRecData + inRecOffset), env->srCommand->authLen); + inRecOffset += env->srCommand->authLen; + } + + env->srCommand->address = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + uint8_t actFlags = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + env->srCommand->act = actFlags & 0xF; + env->srCommand->size = (actFlags >> 0x4) & 0xF; + + env->srCommand->cmd = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + if (env->srCommand->cmd == EGTS_SEND_ACCIDENT_DATA) { + + env->srCommand->data.next.profile = *((bool *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + } else if (env->srCommand->cmd == EGTS_START_SEND_READY) { + + env->srCommand->data.next.enabled = *((uint32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + } else if (env->srCommand->cmd == EGTS_ECALL_MSD_REQ) { + env->srCommand->data.msdReq.mid = *((int32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + env->srCommand->data.msdReq.transport = *((uint8_t *) (env->subRecData + inRecOffset)); + + } else if (env->srCommand->cmd == EGTS_ECALL_REQ) { + + env->srCommand->data.ecallReq.reqType = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + } else if ((env->srCommand->cmd == EGTS_ECALL_TEST_NUMBER) || + (env->srCommand->cmd == EGTS_ECALL_SMS_FALLBACK_NUMBER)) { + + tString32 *number = &env->srCommand->data.newFallbackNumber; + + number->length = env->subRecLength - inRecOffset; + memcpy(number->data, env->subRecData + inRecOffset, number->length); + + inRecOffset += number->length; + } else if (env->srCommand->cmd == EGTS_FLEET_MAX_SPEED_THRESHOLD) { + + int32_t *arr = env->srCommand->data.arr; + + memcpy(arr, env->subRecData + inRecOffset, 5 * 4); + + inRecOffset += (5 * 4); + } +} + +void EgtsParseSrvNotificationData(uint8_t *rec, EgtsSrNotificationData *notificationData) { + notificationData->flags = rec[0]; + notificationData->count = rec[1]; + + if (notificationData->count) { + memcpy((uint8_t *) notificationData->notifications, rec + 2, (notificationData->count * 2)); + } + + uint8_t afterArray = (notificationData->count * 2) + 2; + + notificationData->storeHours = rec[afterArray + 0]; + notificationData->repeatCount = rec[afterArray + 1]; + notificationData->repeatIntervalMin = rec[afterArray + 2]; +} + +void EgtsParseSrvSubRecord(EgtsWorkerEnvironment *env, uint8_t *subRecRaw) { + env->subRecType = subRecRaw[0]; + env->subRecLength = *((uint16_t *) (subRecRaw + 1)); + env->subRecData = subRecRaw + 3; + + env->srNotificationData = NULL; + env->srCommand = NULL; + + if (env->recSourceService == EGTS_COMMANDS_SERVICE) { + env->srCommand = &env->subRecMemAlloc.cmd; + EgtsParseSrvSubRecordSrCommand(env); + } else if (env->recSourceService == EGTS_NOTIFICATION_SERVICE) { + switch (env->subRecType) { + case EGTS_SR_NOTIFICATION_DATA: + env->srNotificationData = &env->subRecMemAlloc.notificationData; + EgtsParseSrvNotificationData(env->subRecData, env->srNotificationData); + break; + + case EGTS_SR_NOTIFICATION_FULL_DATA: +// LOG("EGTS_SR_NOTIFICATION_FULL_DATA") + break; + } + } else { +// LOG("UNKNOWN EGTS SERVICE, CODE: ") + } +} + + +void EgtsParseSrvRecord(EgtsWorkerEnvironment *env) { + + env->recordLength = *((uint16_t *) env->record); + env->recordNumber = *((uint16_t *) (env->record + 2)); + env->recordFlags = env->record[4]; + + env->recHasTime = env->recordFlags & 0b00000100 ? true : false; + env->recHasEvent = env->recordFlags & 0b00000010 ? true : false; + env->recHasObj = env->recordFlags & 0b00000001 ? true : false; + + uint8_t variableOffset = (env->recHasTime ? 4 : 0) + (env->recHasEvent ? 4 : 0) + (env->recHasObj ? 4 : 0); + + env->recSourceService = env->record[5 + variableOffset]; + env->recRecipientService = env->record[6 + variableOffset]; + env->recordData = env->record + 7 + variableOffset; + + + EgtsParseSrvSubRecord(env, env->recordData); +} diff --git a/Src/egtsWorkerExt.c b/Src/egtsWorkerExt.c new file mode 100644 index 0000000..3db1a5b --- /dev/null +++ b/Src/egtsWorkerExt.c @@ -0,0 +1,282 @@ +// +// Created by cfif on 18.05.2024. +// +#include "egtsWorkerExt.h" +#include "egts_crc.h" +#include "string.h" + +#define EGTS_STATIC_HEADER_EXT_LENGTH 11 + +bool EgtsParseHeaderExt(EgtsWorkerEnvironment *env) { +// uint8_t protocol; +// uint8_t SecKeyID; +// uint8_t flags; +// uint16_t length; +// uint8_t encoding; +// uint16_t id; +// uint8_t type; +// uint8_t crc; + + env->header.protocol = *env->workingBuffer; + env->header.SecKeyID = *(env->workingBuffer + 1); + env->header.flags = *(env->workingBuffer + 2); + env->header.headerLength = *(uint8_t *) (env->workingBuffer + 3); + env->header.encoding = *(env->workingBuffer + 4); + env->header.frameDataLength = *(uint16_t *) (env->workingBuffer + 5); + env->header.packetId = *(uint16_t *) (env->workingBuffer + 7); + env->header.type = *(uint8_t *) (env->workingBuffer + 9); + env->header.crc = *(env->workingBuffer + 10); + + if (env->header.protocol != 1) + return false; + + uint8_t crc = CRC8EGTS((uint8_t *) &env->header, 10);//Header CRC + + if (crc != env->header.crc) + return false; + + return true; +} + +void EgtsParseSrvSubRecordSrCommandExt(EgtsWorkerEnvironment *env) { + uint16_t inRecOffset = 0; + + env->srCommand->cmdType = *((uint8_t *) env->subRecData + inRecOffset) >> 0x4; + env->srCommand->cmdConfirmationType = *((uint8_t *) env->subRecData + inRecOffset) & 0b1111; + inRecOffset += 1; + + env->srCommand->cmdId = *((uint32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + env->srCommand->srcId = *((uint32_t *) (env->subRecData + inRecOffset)); + inRecOffset += 4; + + uint8_t flags = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + env->srCommand->hasCharset = flags & 0b1; + env->srCommand->hasAuth = (flags >> 0x1) & 0b1; + + if (env->srCommand->hasCharset) { + env->srCommand->charset = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + } + + if (env->srCommand->hasAuth) { + env->srCommand->authLen = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + memcpy(env->srCommand->auth, (env->subRecData + inRecOffset), env->srCommand->authLen); + inRecOffset += env->srCommand->authLen; + } + + env->srCommand->address = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + uint8_t actFlags = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + env->srCommand->act = actFlags & 0xF; + env->srCommand->size = (actFlags >> 0x4) & 0xF; + + env->srCommand->cmd = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + env->srCommand->dataPointer = (env->subRecData + inRecOffset); +} + +void EgtsParseSrvSubRecordFirmwareExt(EgtsWorkerEnvironment *env) { + uint16_t inRecOffset = 0; + + env->firmware->Identity = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + env->firmware->PartNumber = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + env->firmware->ExpectedPartsQuantity = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + if (env->firmware->PartNumber == 1) { + + uint8_t OA = *((uint8_t *) (env->subRecData + inRecOffset)); + ((uint8_t *) ((uint8_t *) &env->firmware->ObjectAttribute))[0] = OA; + inRecOffset += 1; + + env->firmware->ComponentOrModuleIdentifier = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + env->firmware->Version = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + env->firmware->WholeObjectSignature = *((uint16_t *) (env->subRecData + inRecOffset)); + inRecOffset += 2; + + for (size_t i = 0; i < 64 + 1; ++i) { + env->firmware->FileName[i] = *((uint8_t *) (env->subRecData + inRecOffset)); + inRecOffset += 1; + + if (env->firmware->FileName[i] == 0) + break; + } + + } + + env->firmware->dataPointer = env->subRecData + inRecOffset; + env->firmware->dataLength = env->subRecLength - inRecOffset; + +} + +void EgtsParseSrvSubRecordExt(EgtsWorkerEnvironment *env, uint8_t *subRecRaw) { + env->subRecType = subRecRaw[0]; + env->subRecLength = *((uint16_t *) (subRecRaw + 1)); + env->subRecData = subRecRaw + 3; + + env->srNotificationData = NULL; + env->srCommand = NULL; + + if (env->recSourceService == EGTS_COMMANDS_SERVICE) { + env->srCommand = &env->subRecMemAlloc.cmd; + EgtsParseSrvSubRecordSrCommandExt(env); + } else if (env->recSourceService == EGTS_FIRMWARE_SERVICE) { + env->firmware = &env->subRecMemAlloc.firmware; + EgtsParseSrvSubRecordFirmwareExt(env); + } else if (env->recSourceService == EGTS_NOTIFICATION_SERVICE) { + switch (env->subRecType) { + case EGTS_SR_NOTIFICATION_DATA: + env->srNotificationData = &env->subRecMemAlloc.notificationData; + EgtsParseSrvNotificationData(env->subRecData, env->srNotificationData); + break; + + case EGTS_SR_NOTIFICATION_FULL_DATA: +// LOG("EGTS_SR_NOTIFICATION_FULL_DATA") + break; + } + } else { +// LOG("UNKNOWN EGTS SERVICE, CODE: ") + } +} + + +uint16_t EgtsParseSrvRecordExt(EgtsWorkerEnvironment *env, uint8_t *record) { + + + env->recordLength = *((uint16_t *) record); + env->recordNumber = *((uint16_t *) (record + 2)); + env->recordFlags = record[4]; + + env->recHasTime = env->recordFlags & 0b00000100 ? true : false; + env->recHasEvent = env->recordFlags & 0b00000010 ? true : false; + env->recHasObj = env->recordFlags & 0b00000001 ? true : false; + + uint8_t variableOffset = (env->recHasTime ? 4 : 0) + (env->recHasEvent ? 4 : 0) + (env->recHasObj ? 4 : 0); + + env->recSourceService = record[5 + variableOffset]; + env->recRecipientService = record[6 + variableOffset]; + env->recordData = record + 7 + variableOffset; + + EgtsParseSrvSubRecordExt(env, env->recordData); + + // 3 - env->subRecType + env->subRecLength + return 7 + variableOffset + 3 + env->subRecLength; +} + +EgtsCompleteResult egtsCompleteResult; + +EgtsCompleteResult *EgtsCompleteTransportExt(EgtsWorkerEnvironment *env) { + uint16_t read; + + if (env->workingBufferLength < EGTS_STATIC_HEADER_EXT_LENGTH) { + + read = env->readData( + env->readDataEnv, + env->workingBuffer + env->workingBufferLength, + EGTS_STATIC_HEADER_EXT_LENGTH - env->workingBufferLength + ); + + env->workingBufferLength += read; + + if (env->workingBufferLength < EGTS_STATIC_HEADER_EXT_LENGTH) { + egtsCompleteResult.completeResult = EGTS_COMPLETE_WAIT; + return &egtsCompleteResult; + } + + if (env->workingBuffer[0] != 1) { + env->workingBufferLength = 0; + egtsCompleteResult.completeResult = EGTS_COMPLETE_ERR_VER; + return &egtsCompleteResult; + } + + uint8_t crc = CRC8EGTS(env->workingBuffer, EGTS_STATIC_HEADER_EXT_LENGTH - 1); //Header CRC + + if (crc != env->workingBuffer[EGTS_STATIC_HEADER_EXT_LENGTH - 1]) { + env->workingBufferLength = 0; + + egtsCompleteResult.calcHeaderCrc = crc; + egtsCompleteResult.receivedHeaderCrc = env->workingBuffer[EGTS_STATIC_HEADER_EXT_LENGTH - 1]; + + egtsCompleteResult.completeResult = EGTS_COMPLETE_HEADER_ERR_CRC; + return &egtsCompleteResult; + } + } + + uint16_t fullLength = EgtsGetTransportFullLength(env); + + // Переполнение приемного буфера + if ((env->workingBufferLength + fullLength) >= env->workingBufferLimit) { + egtsCompleteResult.completeResult = EGTS_COMPLETE_ERR_OVERFLOW; + env->workingBufferLength = 0; + return &egtsCompleteResult; + } + + if (env->workingBufferLength < fullLength) { + + read = env->readData( + env->readDataEnv, + env->workingBuffer + env->workingBufferLength, + fullLength - env->workingBufferLength + ); + + env->workingBufferLength += read; + + if (env->workingBufferLength < fullLength) { + egtsCompleteResult.completeResult = EGTS_COMPLETE_WAIT; + return &egtsCompleteResult; + } + + uint16_t crc = CRC16EGTS(env->workingBuffer + EGTS_STATIC_HEADER_EXT_LENGTH, + fullLength - EGTS_STATIC_HEADER_EXT_LENGTH - 2); + uint16_t crcBody = *(uint16_t *) &env->workingBuffer[fullLength - 2]; + + if (crc != crcBody) { + env->workingBufferLength = 0; + + egtsCompleteResult.fullLength = fullLength; + + egtsCompleteResult.calcBodyCrc = crc; + egtsCompleteResult.receivedBodyCrc = crcBody; + + egtsCompleteResult.completeResult = EGTS_COMPLETE_BODY_ERR_CRC; + return &egtsCompleteResult; + + } + + } + + egtsCompleteResult.completeResult = EGTS_COMPLETE_OK; + + return &egtsCompleteResult; +} + +eEgts_CompleteResult EgtsIsTransportCompleteExt(EgtsWorkerEnvironment *env) { + + if (env->workingBufferLength < EGTS_STATIC_HEADER_EXT_LENGTH) { + return EGTS_COMPLETE_WAIT; + } + uint16_t fullLength = EgtsGetTransportFullLength(env); + if (env->workingBufferLength < fullLength) { + return EGTS_COMPLETE_WAIT; + } + + return EGTS_COMPLETE_OK; +} \ No newline at end of file diff --git a/Src/egts_common.c b/Src/egts_common.c new file mode 100644 index 0000000..81eb27c --- /dev/null +++ b/Src/egts_common.c @@ -0,0 +1,116 @@ +/* + * egts.c + * + * Created on: Jun 4, 2021 + * Author: zemon + */ + + +#include "egts.h" +#include "egts_crc.h" +#include "string.h" + +#define EGTS_TIMESTAMP_EPOCH_OFFSET 1262304000 // epoch timestamp of Fri, 01 Jan 2010 00:00:00 GMT + +uint32_t toEgtsTimestamp(uint32_t ts) { + return ts - EGTS_TIMESTAMP_EPOCH_OFFSET; +} + + +uint16_t vEgtsPackSrv( + uint8_t *out, + uint8_t flags, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t epochTimestamp, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGenerator subRecGen, + void *subRecArgs +) { + + uint16_t subRecordLength = subRecGen(out + 14, subRecArgs); + + *(uint16_t *) (out + 0) = subRecordLength + 3; //data length + + *(uint16_t *) (out + 2) = 0x0001; //counter + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// | flags | +// Sender Rcver Group Prior hasTime hasEvntID hasObjId +// DEV SRV None value exist not not +// 1 0 0 10 1 0 0 => 10010100 => 0x94 + out[4] = flags; +////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //time + *(uint32_t *) (out + 5) = toEgtsTimestamp(epochTimestamp); + + //SourceServType + *(uint8_t *) (out + 9) = (uint8_t) sourceServiceId; + + //RecipientServType + *(uint8_t *) (out + 10) = (uint8_t) recipientServiceId; + + //SRT + *(uint8_t *) (out + 11) = subRecordType; //(uint8_t) SRT; + + //SRL + *(uint16_t *) (out + 12) = subRecordLength; + + return subRecordLength + 14; +} + +uint16_t vEgtsPackTransport( + uint16_t cid, + uint16_t packetId, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGenerator subRecGen, + void *subRecArgs +) { + + uint8_t ptOffset = 0; + + if (packetTypeId == EGTS_PT_RESPONSE) { + ptOffset = 3; + } + + uint16_t srvLen = ptOffset + vEgtsPackSrv( + out + TRANSPORT_HEADER_LENGTH+ptOffset, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordType, + subRecGen, + subRecArgs + ); + + out[0] = 0x01;//version + out[1] = 0x00;//secure key + out[2] = 0x01;//flags + out[3] = 0x0B;//header length + out[4] = 0x00;//header encoding + + *((uint16_t *) (out + 5)) = srvLen; + + *((uint16_t *) (out + 7)) = packetId;//package Id + + out[9] = packetTypeId;//Packet type + + out[10] = CRC8EGTS(out, 10);//Header CRC + + if (packetTypeId == EGTS_PT_RESPONSE) { + *((uint16_t *) (out + 11)) = cid;// response packet id + out[13] = 0b0000;//Packet type + } + + *((uint16_t *) (out + TRANSPORT_HEADER_LENGTH + srvLen)) = CRC16EGTS(out + TRANSPORT_HEADER_LENGTH, srvLen); + + return TRANSPORT_HEADER_LENGTH + srvLen + 2; +} diff --git a/Src/egts_commonExt.c b/Src/egts_commonExt.c new file mode 100644 index 0000000..f348770 --- /dev/null +++ b/Src/egts_commonExt.c @@ -0,0 +1,333 @@ +// +// Created by cfif on 22.04.2024. +// +#include "egts_commonExt.h" +#include "EgtsTimestamp.h" + +uint16_t vEgtsPackSrvEx( + uint8_t *out, + uint16_t counter, + uint8_t flags, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t epochTimestamp, + uint16_t subRecordCount, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGeneratorEx subRecGen, + void *subRecArgs +) { + + uint16_t subRecordLengthFull = 0; + // 3 - Для SRT + SRT + // 11 - Заголовок + uint16_t subRecordLengthOffsetHeader = 11; + + bool isPresentSubRecord = false; + + for (uint16_t i = 0; i < subRecordCount; ++i) { + uint16_t subRecordLength = subRecGen(out + subRecordLengthOffsetHeader + 3, subRecArgs, i); + + if (subRecordLength > 0) { + isPresentSubRecord = true; + + subRecordLengthFull += (subRecordLength + 3); + //SRT + *(uint8_t *) (out + subRecordLengthOffsetHeader) = subRecordType; + //SRL + *(uint16_t *) (out + subRecordLengthOffsetHeader + 1) = subRecordLength; + + subRecordLengthOffsetHeader += (subRecordLength + 3); + } + } + + if (!isPresentSubRecord) + return 0; + + +// uint16_t subRecordLength = subRecGen(out + 14, subRecArgs); +// *(uint16_t *) (out + 0) = subRecordLength + 3; //data length + + *(uint16_t *) (out + 0) = subRecordLengthFull; + + *(uint16_t *) (out + 2) = counter; //counter + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// | flags | +// Sender Rcver Group Prior hasTime hasEvntID hasObjId +// DEV SRV None value exist not not +// 1 0 0 10 1 0 0 => 10010100 => 0x94 + out[4] = flags; +////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //time + *(uint32_t *) (out + 5) = Egts_EpochTimestampToEgtsTime(epochTimestamp); + + //SourceServType + *(uint8_t *) (out + 9) = (uint8_t) sourceServiceId; + + //RecipientServType + *(uint8_t *) (out + 10) = (uint8_t) recipientServiceId; + + + + //SRT +// *(uint8_t *) (out + 11) = subRecordType; //(uint8_t) SRT; + + //SRL +// *(uint16_t *) (out + 12) = subRecordLength; + +// return subRecordLength + 14; + + return subRecordLengthFull + 11; +} + +uint16_t vEgtsPackTransportEx1( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + uint16_t subRecordCount, + eEgtsSubRecordId subRecordType, + tEgtsServiceSubRecordGeneratorEx subRecGen, + void *subRecArgs +) { + + uint8_t ptOffset = 0; + + if (packetTypeId == EGTS_PT_RESPONSE) { + ptOffset = 3; + } + + uint16_t srvLen = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount, + subRecordType, + subRecGen, + subRecArgs + ); + + ++*counter; + + out[0] = 0x01;//version + out[1] = 0x00;//secure key + out[2] = 0x01;//flags + out[3] = 0x0B;//header length + out[4] = 0x00;//header encoding + + *((uint16_t *) (out + 5)) = srvLen; + + *((uint16_t *) (out + 7)) = packetId;//package Id + + out[9] = packetTypeId;//Packet type + + out[10] = CRC8EGTS(out, 10);//Header CRC + + if (packetTypeId == EGTS_PT_RESPONSE) { + *((uint16_t *) (out + 11)) = cid;// response packet id + out[13] = 0b0000;//Packet type + } + + *((uint16_t *) (out + TRANSPORT_HEADER_LENGTH + srvLen)) = CRC16EGTS(out + TRANSPORT_HEADER_LENGTH, srvLen); + + return TRANSPORT_HEADER_LENGTH + srvLen + 2; +} + +uint16_t vEgtsPackTransportEx2( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + + uint16_t subRecordCount1, + eEgtsSubRecordId subRecordType1, + tEgtsServiceSubRecordGeneratorEx subRecGen1, + void *subRecArgs1, + + uint16_t subRecordCount2, + eEgtsSubRecordId subRecordType2, + tEgtsServiceSubRecordGeneratorEx subRecGen2, + void *subRecArgs2 + +) { + + uint8_t ptOffset = 0; + + if (packetTypeId == EGTS_PT_RESPONSE) { + ptOffset = 3; + } + + uint16_t srvLen1 = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount1, + subRecordType1, + subRecGen1, + subRecArgs1 + ); + + ++*counter; + + uint16_t srvLen2 = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + srvLen1 + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount2, + subRecordType2, + subRecGen2, + subRecArgs2 + ); + + ++*counter; + + uint16_t srvLen = srvLen1 + srvLen2; + + out[0] = 0x01;//version + out[1] = 0x00;//secure key + out[2] = 0x01;//flags + out[3] = 0x0B;//header length + out[4] = 0x00;//header encoding + + *((uint16_t *) (out + 5)) = srvLen; + + *((uint16_t *) (out + 7)) = packetId;//package Id + + out[9] = packetTypeId;//Packet type + + out[10] = CRC8EGTS(out, 10);//Header CRC + + if (packetTypeId == EGTS_PT_RESPONSE) { + *((uint16_t *) (out + 11)) = cid;// response packet id + out[13] = 0b0000;//Packet type + } + + *((uint16_t *) (out + TRANSPORT_HEADER_LENGTH + srvLen)) = CRC16EGTS(out + TRANSPORT_HEADER_LENGTH, srvLen); + + return TRANSPORT_HEADER_LENGTH + srvLen + 2; +} + +uint16_t vEgtsPackTransportEx3( + uint16_t cid, + uint16_t packetId, + uint16_t *counter, + uint8_t *out, + uint8_t srvFlags, + eEgtsPacketTypeId packetTypeId, + eEgtsServiceId sourceServiceId, + eEgtsServiceId recipientServiceId, + uint32_t timestamp, + + uint16_t subRecordCount1, + eEgtsSubRecordId subRecordType1, + tEgtsServiceSubRecordGeneratorEx subRecGen1, + void *subRecArgs1, + + uint16_t subRecordCount2, + eEgtsSubRecordId subRecordType2, + tEgtsServiceSubRecordGeneratorEx subRecGen2, + void *subRecArgs2, + + uint16_t subRecordCount3, + eEgtsSubRecordId subRecordType3, + tEgtsServiceSubRecordGeneratorEx subRecGen3, + void *subRecArgs3 + +) { + + uint8_t ptOffset = 0; + + if (packetTypeId == EGTS_PT_RESPONSE) { + ptOffset = 3; + } + + uint16_t srvLen1 = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount1, + subRecordType1, + subRecGen1, + subRecArgs1 + ); + + ++*counter; + + uint16_t srvLen2 = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + srvLen1 + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount2, + subRecordType2, + subRecGen2, + subRecArgs2 + ); + + ++*counter; + + uint16_t srvLen3 = ptOffset + vEgtsPackSrvEx( + out + TRANSPORT_HEADER_LENGTH + srvLen1 + srvLen2 + ptOffset, + *counter, + srvFlags, + sourceServiceId, + recipientServiceId, + timestamp, + subRecordCount3, + subRecordType3, + subRecGen3, + subRecArgs3 + ); + + ++*counter; + + uint16_t srvLen = srvLen1 + srvLen2 + srvLen3; + + out[0] = 0x01;//version + out[1] = 0x00;//secure key + out[2] = 0x01;//flags + out[3] = 0x0B;//header length + out[4] = 0x00;//header encoding + + *((uint16_t *) (out + 5)) = srvLen; + + *((uint16_t *) (out + 7)) = packetId;//package Id + + out[9] = packetTypeId;//Packet type + + out[10] = CRC8EGTS(out, 10);//Header CRC + + if (packetTypeId == EGTS_PT_RESPONSE) { + *((uint16_t *) (out + 11)) = cid;// response packet id + out[13] = 0b0000;//Packet type + } + + *((uint16_t *) (out + TRANSPORT_HEADER_LENGTH + srvLen)) = CRC16EGTS(out + TRANSPORT_HEADER_LENGTH, srvLen); + + return TRANSPORT_HEADER_LENGTH + srvLen + 2; +} \ No newline at end of file diff --git a/Src/egts_crc.c b/Src/egts_crc.c new file mode 100644 index 0000000..7a8f029 --- /dev/null +++ b/Src/egts_crc.c @@ -0,0 +1,128 @@ +/* + * egts_crc.c + * + * Created on: Oct 2, 2020 + * Author: FICOM-IT LTD + */ + +#include "egts_crc.h" + +const uint16_t Crc16Table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +uint16_t egts_crc16( uint8_t *data, uint16_t len ) +{ + uint16_t crc = 0xFFFF; + while (len--) + crc = (crc << 8) ^ Crc16Table[(crc >> 8) ^ *data++]; + return crc; +} + +/* + Name : CRC-8 + Poly : 0x31 x^8 + x^5 + x^4 + 1 + Init : 0xFF + Revert: false + XorOut: 0x00 + Check : 0xF7 ("123456789") +*/ +const uint8_t CRC8Table[256] = { + 0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97, + 0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E, + 0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4, + 0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D, + 0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11, + 0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8, + 0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52, + 0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB, + 0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA, + 0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13, + 0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9, + 0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50, + 0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C, + 0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95, + 0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F, + 0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6, + 0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED, + 0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54, + 0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE, + 0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17, + 0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B, + 0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2, + 0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28, + 0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91, + 0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0, + 0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69, + 0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93, + 0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A, + 0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56, + 0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF, + 0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15, + 0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC +}; + +/* + Name : CRC-8 + Poly : 0x31 x^8 + x^5 + x^4 + 1 + Init : 0xFF + Revert: false + XorOut: 0x00 + Check : 0xF7 ("123456789") +*/ +uint8_t CRC8EGTS(unsigned char *lpBlock, unsigned char len) +{ + unsigned char crc = 0xFF; + while (len--) + crc = CRC8Table[crc ^ *lpBlock++]; + return crc; +} +//------------------------------------------------------------------------------ + +/* + Name : CRC-16 CCITT + Poly : 0x1021 x^16 + x^12 + x^5 + 1 + Init : 0xFFFF + Revert: false + XorOut: 0x0000 + Check : 0x29B1 ("123456789") +*/ +uint16_t CRC16EGTS(unsigned char * pcBlock, unsigned int len) +{ + unsigned short crc = 0xFFFF; + while (len--) + crc = (crc << 8) ^ Crc16Table[(crc >> 8) ^ *pcBlock++]; + return crc; +} +//------------------------------------------------------------------------------ diff --git a/Src/egts_europrotocol.c b/Src/egts_europrotocol.c new file mode 100644 index 0000000..a10d425 --- /dev/null +++ b/Src/egts_europrotocol.c @@ -0,0 +1,52 @@ +// +// Created by zemon on 11.02.2022. +// + +#include "egts.h" +//#include "BitOps.h" +#include "BitBuffer.h" + +uint16_t vEgtsPackTrackData(uint8_t *out, uint16_t bitsOffset, tEgtsTrackData *trackData) { + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, trackData->LOHS ? 0b1 : 0b0, 1); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, trackData->LAHS ? 0b1 : 0b0, 1); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->speed)[1], 5); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, trackData->TrackDataExist ? 0b1 : 0b0, 1); + + + bitsOffset += vBitBufferAppendBitsReverseBytes(out, bitsOffset, (uint8_t *) &trackData->Latitude, 32); + bitsOffset += vBitBufferAppendBitsReverseBytes(out, bitsOffset, (uint8_t *) &trackData->Longitude, 32); + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->speed)[0], 8); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->Altitude)[0], 8); + + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->Direction)[1], 1); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, trackData->AltitudeDirection ? 0b1 : 0b0, 1); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->Altitude)[1], 6); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &trackData->Direction)[0], 8); + +} + + +uint16_t vEgtsPackSrEpTrackData(uint8_t *out, tEgtsSrEpTrackDataArgs *args) { + + uint16_t bitsOffset = 0; + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &args->blockNumber)[0], 8); + + bitsOffset += vBitBufferAppendBitsReverseBytes(out, bitsOffset, (uint8_t *) &args->absoluteTime, 32); + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, args->relativeAmount, 8); + + bitsOffset += vBitBufferAppendByte(out, bitsOffset, args->timeShift, 4); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, args->CoordinateSystem ? 0b1 : 0b0, 1); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, ((uint8_t *) &args->blockNumber)[1], 2); + bitsOffset += vBitBufferAppendByte(out, bitsOffset, args->RTU ? 0b1 : 0b0, 1); + + + bitsOffset += vEgtsPackTrackData(out, bitsOffset, &args->originPoint); + + + return (bitsOffset / 8) + ((bitsOffset % 8) ? 1 : 0) + args->relativeAmount; +} \ No newline at end of file diff --git a/Src/egts_msd.c b/Src/egts_msd.c new file mode 100644 index 0000000..0ae25d9 --- /dev/null +++ b/Src/egts_msd.c @@ -0,0 +1,51 @@ +/* + * egts.c + * + * Created on: Jun 4, 2021 + * Author: zemon + */ + + +#include "egts.h" +#include "egts_crc.h" +#include "string.h" + + +uint16_t vEgtsPackMsdData(uint8_t *out, tEgtsMsdDataArgs *args) { + out[0] = EGTS_SR_RAW_MSD_DATA; + *(uint16_t *) (out + 1) = args->msdLength + 1;//+ 1 phantom + + //Phantom Byte + *(uint8_t *) (out + 0) = 0x01; + + memcpy(out + 1, args->msd, args->msdLength); + return args->msdLength + 1; +} +// +//uint16_t vEgtsPackMsdDataGen(uint8_t *out, void *args) { +// return vEgtsPackMsdData(out, (tEgtsMsdDataArgs *) args); +//} + +uint16_t vEgtsPackMsdTransport(uint16_t packetId, uint8_t *out, uint8_t *msd, uint8_t msdLength, uint32_t timestamp) { + + tEgtsMsdDataArgs args = { + .msdLength = msdLength, + .msd = msd, + }; + + return vEgtsPackTransport( + 0, + packetId, + out, + EGTS_SERVICE_FLAGS_MSD, + EGTS_PT_APPDATA, + EGTS_ECALL_SERVICE, + EGTS_ECALL_SERVICE, + timestamp, + EGTS_SR_RAW_MSD_DATA, +// SRL, +// SRT, + vEgtsPackMsdDataGen, + &args + ); +} diff --git a/Src/egts_teledata.c b/Src/egts_teledata.c new file mode 100644 index 0000000..3c8f1bd --- /dev/null +++ b/Src/egts_teledata.c @@ -0,0 +1,314 @@ +/* + * egts.c + * + * Created on: Jun 4, 2021 + * Author: zemon + */ + + +#include "egts.h" +#include "egts_crc.h" +#include "string.h" +#include "stdint.h" +#include "math.h" +#include "egtsWorker.h" + +#define ADD_TO_RESULT(DATA, LEN) memcpy(out + offset, (uint8_t * ) & DATA, LEN); offset+=LEN; + + +//flags +const uint8_t flags = 0b10000001; +//const uint16_t SPD = 50; +const uint8_t DIR = 0; +const uint32_t ODR = 0x000000; +const uint8_t DIN = 0; +const uint8_t SRC = 16; +const uint32_t ALT = 0x00; + +//uint16_t vEgtsPackPosDataGen(uint8_t *out, void *args) { +// tEgtsPosDataArgs *posDataArgs = (tEgtsPosDataArgs *) args; +// return vEgtsPackPosData(out, posDataArgs); +//} + +uint16_t vEgtsPackPosData(uint8_t *out, tEgtsPosDataArgs *args) { + + uint32_t NTM = toEgtsTimestamp(args->epochTimestamp); + + double lat = (fabs(args->latitude) / 90) * 0xFFFFFFFF; + double lon = (fabs(args->longitude) / 180) * 0xFFFFFFFF; + uint32_t LAT = (uint32_t) lat; + uint32_t LONG = (uint32_t) lon; + + uint16_t offset = 0; + + + ADD_TO_RESULT(NTM, 4); + ADD_TO_RESULT(LAT, 4); + ADD_TO_RESULT(LONG, 4); + ADD_TO_RESULT(flags, 1); + ADD_TO_RESULT(args->velocity, 2); + ADD_TO_RESULT(DIR, 1); + ADD_TO_RESULT(ODR, 3); + ADD_TO_RESULT(DIN, 1); + ADD_TO_RESULT(SRC, 1); + ADD_TO_RESULT(ALT, 3); + + return offset; + +} + +uint16_t vEgtsPackSensorsData(uint8_t *out, tEgtsSensorsDataArgs *args) { + + uint16_t offset = 0; + + ADD_TO_RESULT(args->digitalInPresent, 1); + ADD_TO_RESULT(args->digitalOutPresent, 1); + ADD_TO_RESULT(args->analogInPresent, 1); + + for (uint16_t i = 0; i < 8; ++i) { + uint8_t mask = 0x1 << i; + if (args->digitalInPresent & mask) { + ADD_TO_RESULT(args->digitalIn[i], 1); + } + } + + for (uint16_t i = 0; i < 8; ++i) { + uint8_t mask = 0x1 << i; + if (args->analogInPresent & mask) { + ADD_TO_RESULT(args->analogIn[i], 3); + } + } + return offset; + +} + +//uint32_t TID = 4168809385; +uint8_t TermIdentityFlags = 0b01000010; +//unit16_t TermIdentityHDID = ; +//unit32_t TermIdentityNID = ; +uint16_t TermIdentityBS = 512; + + +//uint16_t vEgtsPackTermIdentityGen(uint8_t *out, void *args) { +// tEgtsTermIdentityArgs *termIdentityArgs = (tEgtsTermIdentityArgs *) args; +// return vEgtsPackTermIdentity(out, termIdentityArgs); +//} + +uint16_t vEgtsPackTermIdentity(uint8_t *out, tEgtsTermIdentityArgs *args) { + + uint16_t offset = 0; + + ADD_TO_RESULT(args->TerminalID, 4); + ADD_TO_RESULT(TermIdentityFlags, 1); + ADD_TO_RESULT((*args->IMEI), args->IMEI_len); + ADD_TO_RESULT(TermIdentityBS, 2); + + return offset; + +} + +uint16_t vEgtsPackResponse(uint8_t *out, tEgtsRecordResponseData *args) { + + uint16_t offset = 0; + + ADD_TO_RESULT(args->CRN, 2); + ADD_TO_RESULT(args->RST, 1); + + return offset; + +} + +uint16_t vEgtsPacSrCommandDataResponse(uint8_t *out, tEgtsSrCmdConfirmation *args) { + + uint16_t offset = 0; + + uint8_t flag = (args->CT << 0x4) | (args->CCT & 0xF); + ADD_TO_RESULT(flag, 1); + + ADD_TO_RESULT(args->CID, 4); + ADD_TO_RESULT(args->SID, 4); + + uint8_t hasFlags = (args->ACFE << 0x1) | (args->CHSFE & 0x1); + ADD_TO_RESULT(hasFlags, 1); + + if (args->CHSFE) { + ADD_TO_RESULT(args->CHS, 1); + } + if (args->ACFE) { + ADD_TO_RESULT(args->ACL, 1); + ADD_TO_RESULT(args->AC, 4); + } + + if ((args->CT == CT_COMCONF) && (args->CCT == CC_OK)) { + ADD_TO_RESULT(args->CmdData.ADR, 2); + uint8_t flagComData = (args->CmdData.SZ << 0x4) | (args->CmdData.ACT & 0xF); + ADD_TO_RESULT(flagComData, 1); + ADD_TO_RESULT(args->CmdData.CCD, 2); + } + if (args->CmdData.DT) { + //todo? + } + + return offset; +} + +uint16_t vEgtsPackTeledataTransport( + uint16_t packetId, + uint8_t *out, + double latitude, + double longitude, + uint16_t velocity, + uint32_t epochTimestamp +) { + tEgtsPosDataArgs args = { + .longitude = longitude, + .latitude = latitude, + .velocity = velocity, + .epochTimestamp = epochTimestamp, + }; + + return vEgtsPackTransport( + 0, + packetId, + out, + EGTS_SERVICE_FLAGS_POS, + EGTS_PT_APPDATA, + EGTS_TELEDATA_SERVICE, + EGTS_TELEDATA_SERVICE, + epochTimestamp, + EGTS_SR_POS_DATA, + vEgtsPackPosDataGen, + &args + ); + +// return vEgtsPackPosData(out, &args); +} + + +uint16_t vEgtsPackSensorsTransport( + uint16_t packetId, + uint8_t *out, + uint32_t epochTimestamp, + tEgtsSensorsDataArgs *sensors +) { + return vEgtsPackTransport( + 0, + packetId, + out, + EGTS_SERVICE_FLAGS_POS, + EGTS_PT_APPDATA, + EGTS_TELEDATA_SERVICE, + EGTS_TELEDATA_SERVICE, + epochTimestamp, + EGTS_SR_AD_SENSORS_DATA, + vEgtsPackSensorsDataGen, + sensors + ); + +// return vEgtsPackPosData(out, &args); +} + +uint16_t vEgtsPackTermIdentityTransport( + uint16_t packetId, + uint8_t *out, + uint8_t *IMEI, + uint8_t IMEI_len, + uint32_t TerminalID, + uint32_t epochTimestamp +) { + tEgtsTermIdentityArgs args = { + .IMEI = IMEI, + .IMEI_len = IMEI_len, + .TerminalID = TerminalID, +// .epochTimestamp = epochTimestamp, + }; + + return vEgtsPackTransport( + 0, + packetId, + out, + EGTS_SERVICE_FLAGS_AUTH, + EGTS_PT_APPDATA, + EGTS_AUTH_SERVICE, + EGTS_AUTH_SERVICE, + epochTimestamp, + EGTS_SR_TERM_IDENTITY, + vEgtsPackTermIdentityGen, + &args + ); + +// return vEgtsPackPosData(out, &args); +} + +uint16_t +vEgtsPackEgtsResponse(uint16_t packetId, uint8_t *out, uint8_t rst, uint16_t crn, uint16_t cid, uint32_t timestamp) { + + tEgtsRecordResponseData args = { + .CRN = crn, + .RST = rst, + }; + + return vEgtsPackTransport( + cid, + packetId, + out, + EGTS_SERVICE_FLAGS_POS, + EGTS_PT_RESPONSE, + EGTS_ECALL_SERVICE, + EGTS_ECALL_SERVICE, + timestamp, + EGTS_SR_RECORD_RESPONSE, + vEgtsPackResponseGen, + &args + ); +} + +uint16_t vEgtsPackSrCmdConfirmation( + uint8_t *out, + uint16_t packetId, + uint16_t cmdType, + uint16_t cmdConfirType, + uint16_t cid, + uint16_t sid, + uint16_t acfe, + uint16_t chsfe, + uint16_t adr, + uint8_t sz, + uint8_t act, + uint16_t ccd, + uint32_t dt +) { + + bool authCodeExist = false; + bool charsetExist = false; + + tEgtsSrCmdConfirmation args = { + .CT = cmdType, + .CCT = cmdConfirType, + .CID = cid, + .SID = sid, + .ACFE = acfe, + .CHSFE = chsfe, + .CmdData.ADR = adr, + .CmdData.SZ = sz, + .CmdData.ACT = act, + .CmdData.CCD = ccd, + .CmdData.DT = dt, + }; + + return vEgtsPackTransport( + 0, + packetId, + out, + EGTS_SERVICE_FLAGS_POS, + EGTS_PT_APPDATA, + EGTS_COMMANDS_SERVICE, + EGTS_COMMANDS_SERVICE, + 0, + EGTS_SR_COMMAND_DATA, + vEgtsPacSrCommandDataResponseGen, + &args + ); +} + + diff --git a/Tst/CMakeLists.txt b/Tst/CMakeLists.txt new file mode 100644 index 0000000..4582f0f --- /dev/null +++ b/Tst/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.17) +project(Module C) + +set(CMAKE_C_STANDARD 11) + +include(modular.cmake) + +add_executable(test_module ${SOURCES} test_module.c) + +#ADD_CUSTOM_COMMAND( +# TARGET test_module POST_BUILD +# COMMAND nc -l 5020&echo ok +#) \ No newline at end of file diff --git a/Tst/egts.lua b/Tst/egts.lua new file mode 100644 index 0000000..86d76e5 --- /dev/null +++ b/Tst/egts.lua @@ -0,0 +1,905 @@ +-- создаем описание нового протокола +local egts_proto = Proto("egts", "EGTS") + +-- настройки плагина +local default_settings = { + port = 5020 +} + +local EGTS_PT_RESPONSE = "EGTS_PT_RESPONSE" +local EGTS_PT_APPDATA = "EGTS_PT_APPDATA" +local EGTS_PT_SIGNED_APPDATA = "EGTS_PT_SIGNED_APPDATA" + +local egts_packet_type = { + [0] = EGTS_PT_RESPONSE, + [1] = EGTS_PT_APPDATA, + [2] = EGTS_PT_SIGNED_APPDATA, +} + +local egts_subrecord_type = { + [0] = "EGTS_SR_RECORD_RESPONSE", + [1] = "EGTS_SR_TERM_IDENTITY", + [9] = "EGTS_SR_RESULT_CODE", + [15] = "EGTS_SR_EGTSPLUS_DATA", + [16] = "EGTS_SR_POS_DATA", + [17] = "EGTS_SR_EXT_POS_DATA", + [18] = "EGTS_SR_AD_SENSORS_DATA", + [19] = "EGTS_SR_COUNTERS_DATA", + [20] = "EGTS_SR_STATE_DATA", + [22] = "EGTS_SR_LOOPIN_DATA", + [23] = "EGTS_SR_ABS_DIG_SENS_DATA", + [24] = "EGTS_SR_ABS_AN_SENS_DATA", + [25] = "EGTS_SR_ABS_CNTR_DATA", + [26] = "EGTS_SR_ABS_LOOPIN_DATA", + [27] = "EGTS_SR_LIQUID_LEVEL_SENSOR", + + -- Список подзаписей сервиса EGTS_ECALL_SERVICE + --[20] = "EGTS_SR_ACCEL_DATA", + [40] = "EGTS_SR_RAW_MSD_DATA", + [62] = "EGTS_SR_TRACK_DATA", + + -- Описание подзаписей сервиса EGTS_COMMAND_SERVICE + [51] = "EGTS_SR_COMМAND_DАТА", +} + +local result_code = { + [0] = "EGTS_PC_OK", + [1] = "EGTS_PC_IN_PROGRESS", + [128] = "EGTS_PC_UNS_PROTOCOL", + [129] = "EGTS_PC_DECRYPT_ERROR", + [130] = "EGTS_PC_PROC_DENIED", + [131] = "EGTS_PC_INC_HEADERFORM", + [132] = "EGTS_PC_INC_DATAFORM", + [133] = "EGTS_PC_UNS_TYPE", + [134] = "EGTS_PC_NOTEN_PARAMS", + [135] = "EGTS_PC_DBL_PROC", + [136] = "EGTS_PC_PROC_SRC_DENIED", + [137] = "EGTS_PC_HEADERCRC_ERROR", + [138] = "EGTS_PC_DATACRC_ERROR", + [139] = "EGTS_PC_INVDATALEN", + [140] = "EGTS_PC_ROUTE_NFOUND", + [141] = "EGTS_PC_ROUTE_CLOSED", + [142] = "EGTS_PC_ROUTE_DENIED", + [143] = "EGTS_PC_INVADDR", + [144] = "EGTS_PC_TTLEXPIRED", + [145] = "EGTS_PC_NO_ACK", + [146] = "EGTS_PC_OBJ_NFOUND", + [147] = "EGTS_PC_EVNT_NFOUND", + [148] = "EGTS_PC_SRVC_NFOUND", + [149] = "EGTS_PC_SRVC_DENIED", + [150] = "EGTS_PC_SRVC_UNKN", + [151] = "EGTS_PC_AUTH_DENIED", + [152] = "EGTS_PC_ALREADY_EXISTS", + [153] = "EGTS_PC_ID_NFOUND", + [154] = "EGTS_PC_INC_DATETIME", + [155] = "EGTS_PC_IO_ERROR", + [156] = "EGTS_PC_NO_RES_AVAIL", + [157] = "EGTS_PC_MODULE_FAULT", + [158] = "EGTS_PC_MODULE_PWR_FLT", + [159] = "EGTS_PC_MODULE_PROC_FLT", + [160] = "EGTS_PC_MODULE_SW_FLT", + [161] = "EGTS_PC_MODULE_FW_FLT", + [162] = "EGTS_PC_MODULE_IO_FLT", + [163] = "EGTS_PC_MODULE_MEM_FLT", + [164] = "EGTS_PC_TEST_FAILED", +} +local command_srv_command_type = { + [0001] = "СT_COMCONF", + [0010] = "CT_MSGCONF", + [0011] = "CT_MSGFROM", + [0100] = "CT_MSGTO", + [0101] = "CT_COM", + [0110] = "CT_DELCOM", + [0111] = "CT_SUBREQ", + [1000] = "CT_DELIV", +} +local command_srv_command_confirmation_type = { + [0000] = "CC_OK", + [0001] = "CC_ERROR", + [0010] = "CC_ILL", + [0011] = "CC_DEL", + [0100] = "CC_NFOUND", + [0101] = "CC_NCONF", + [0110] = "CC_INPROG", +} + +local command_srv_command_code = { + [0x0000] = "EGTS_RAW_DATA", + [0x0001] = "EGTS_TEST_MODE", + [0x0006] = "EGTS_CONFIG_RESET", + [0x0007] = "EGTS_SET_AUTH_CODE", + [0x0108] = "EGTS_RESTART", + [0x020D] = "EGTS_ECALL_TEST_NUMBER", + [0x0223] = "EGTS_ECALL_SMS_FALLBACK_NUMBER", +} + +local header = { + + prv = ProtoField.new("ProtocolVersion", "egts.prv", ftypes.UINT8, nil, base.DEC), + skid = ProtoField.new("SecurityKeyID", "egts.skid", ftypes.UINT8, nil, base.DEC), + prf = ProtoField.new("Prefix", "egts.prf", ftypes.UINT8, nil, base.DEC, 0xc0), + rte = ProtoField.new("Route", "egts.rte", ftypes.UINT8, nil, base.DEC, 0x20), + ena = ProtoField.new("Encryption alg", "egts.ena", ftypes.UINT8, nil, base.DEC, 0x18), + cmp = ProtoField.new("Compression", "egts.cmp", ftypes.UINT8, nil, base.DEC, 0x4), + prt = ProtoField.new("Priority", "egts.prt", ftypes.UINT8, nil, base.DEC, 0x3), + hl = ProtoField.new("Header length", "egts.hl", ftypes.UINT8, nil, base.DEC), + he = ProtoField.new("Header encoding", "egts.he", ftypes.UINT8, nil, base.DEC), + fdl = ProtoField.new("Frame data length", "egts.fdl", ftypes.UINT16, nil, base.DEC), + pid = ProtoField.new("Packet identifier", "egts.pid", ftypes.UINT16, nil, base.DEC), + pt = ProtoField.new("Packet type", "egts.pt", ftypes.UINT8, egts_packet_type, base.DEC), + pra = ProtoField.new("Peer address", "egts.pra", ftypes.UINT16, nil, base.DEC), + rca = ProtoField.new("Recipient address", "egts.rca", ftypes.UINT16, nil, base.DEC), + ttl = ProtoField.new("Time to live", "egts.ttl", ftypes.UINT8, nil, base.DEC), + hcs = ProtoField.new("Header checksum", "egts.hcs", ftypes.UINT8, nil, base.HEX), + sfrd = ProtoField.new("Services frame data", "egts.sfrd", ftypes.BYTES), + rpid = ProtoField.new("Response packetID", "egts.rpid", ftypes.UINT16, nil, base.DEC), + pr = ProtoField.new("Processing result", "egts.pr", ftypes.UINT8, nil, base.DEC), + rl = ProtoField.new("Record length", "egts.rl", ftypes.UINT16, nil, base.DEC), + rn = ProtoField.new("Record number", "egts.rn", ftypes.UINT16, nil, base.DEC), + ssod = ProtoField.new("Source service on device", "egts.ssod", ftypes.UINT8, nil, base.DEC, 0x80), + rsod = ProtoField.new("Recipient service on device", "egts.rsod", ftypes.UINT8, nil, base.DEC, 0x40), + grp = ProtoField.new("Group", "egts.grp", ftypes.UINT8, nil, base.DEC, 0x20), + rpr = ProtoField.new("Record processing priority", "egts.rpr", ftypes.UINT8, nil, base.DEC, 0x18), + tmfe = ProtoField.new("Time field exists", "egts.tmfe", ftypes.UINT8, nil, base.DEC, 0x4), + evfe = ProtoField.new("Event ID field exists", "egts.evfe", ftypes.UINT8, nil, base.DEC, 0x2), + obfe = ProtoField.new("Object ID field exists", "egts.obfe", ftypes.UINT8, nil, base.DEC, 0x1), + oid = ProtoField.new("Object identifier", "egts.oid", ftypes.UINT32, nil, base.DEC), + evid = ProtoField.new("Event identifier", "egts.evid", ftypes.UINT32, nil, base.DEC), + tm = ProtoField.new("Time", "egts.tm", ftypes.UINT32, nil, base.DEC), + sst = ProtoField.new("Source service type", "egts.sst", ftypes.UINT8, nil, base.DEC), + rst = ProtoField.new("Recipient service type", "egts.rst", ftypes.UINT8, nil, base.DEC), + rd = ProtoField.new("Record data", "egts.rd", ftypes.BYTES), + srt = ProtoField.new("Subrecord type", "egts.srt", ftypes.UINT8, egts_subrecord_type, base.DEC), + srl = ProtoField.new("Subrecord length", "egts.srl", ftypes.UINT16, nil, base.DEC), + srd = ProtoField.new("Subrecord data", "egts.srd", ftypes.STRING), + crn = ProtoField.new("Confirmed record number", "egts.crn", ftypes.UINT16, nil, base.DEC), + rs = ProtoField.new("Record status", "egts.rs", ftypes.UINT8, result_code, base.DEC), + tid = ProtoField.new("Terminal identifier", "egts.tid", ftypes.UINT32, nil, base.DEC), + mne = ProtoField.new("MNE", "egts.mne", ftypes.UINT8, nil, base.DEC, 0x80), + bse = ProtoField.new("BSE", "egts.bse", ftypes.UINT8, nil, base.DEC, 0x40), + nide = ProtoField.new("NIDE", "egts.nide", ftypes.UINT8, nil, base.DEC, 0x20), + ssra = ProtoField.new("SSRA", "egts.ssra", ftypes.UINT8, nil, base.DEC, 0x10), + lngce = ProtoField.new("LNGCE", "egts.lngce", ftypes.UINT8, nil, base.DEC, 0x8), + imsie = ProtoField.new("IMSIE", "egts.imsie", ftypes.UINT8, nil, base.DEC, 0x4), + imeie = ProtoField.new("IMEIE", "egts.imeie", ftypes.UINT8, nil, base.DEC, 0x2), + hdide = ProtoField.new("HDIDE", "egts.hdide", ftypes.UINT8, nil, base.DEC, 0x1), + hdid = ProtoField.new("Home dispatcher identifier", "egts.hdid", ftypes.UINT16, nil, base.DEC), + imei = ProtoField.new("International mobile equipment identity", "egts.imei", ftypes.STRING), + imsi = ProtoField.new("International mobile subscriber identity", "egts.imsi", ftypes.STRING), + lngc = ProtoField.new("Language code", "egts.lngc", ftypes.STRING), + nid = ProtoField.new("Network identifier", "egts.nid", ftypes.UINT32, nil, base.DEC), + bs = ProtoField.new("Buffer size", "egts.bs", ftypes.UINT32, nil, base.DEC), + msisdn = ProtoField.new("Mobile station integrated services digital network number", "egts.msisdn", ftypes.STRING), + ntm = ProtoField.new("Navigation time", "egts.ntm", ftypes.ABSOLUTE_TIME), + lat = ProtoField.new("Latitude", "egts.lat", ftypes.DOUBLE), + long = ProtoField.new("Longitude", "egts.long", ftypes.DOUBLE), + alte = ProtoField.new("ALTE", "egts.alte", ftypes.UINT8, nil, base.DEC, 0x80), + lohs = ProtoField.new("LONS", "egts.lohs", ftypes.UINT8, nil, base.DEC, 0x40), + lahs = ProtoField.new("LAHS", "egts.lahs", ftypes.UINT8, nil, base.DEC, 0x20), + mv = ProtoField.new("MV", "egts.mv", ftypes.UINT8, nil, base.DEC, 0x10), + bb = ProtoField.new("BB", "egts.bb", ftypes.UINT8, nil, base.DEC, 0x8), + cs = ProtoField.new("CS", "egts.cs", ftypes.UINT8, nil, base.DEC, 0x4), + fix = ProtoField.new("FIX", "egts.fix", ftypes.UINT8, nil, base.DEC, 0x2), + vld = ProtoField.new("VLD", "egts.vld", ftypes.UINT8, nil, base.DEC, 0x1), + dirh = ProtoField.new("Direction the Highest bit", "egts.dirh", ftypes.UINT16, nil, base.DEC, 0x8000), + alts = ProtoField.new("Altitude sign", "egts.alts", ftypes.UINT16, nil, base.DEC, 0x4000), + spd = ProtoField.new("Speed", "egts.spd", ftypes.UINT16, nil, base.DEC, 0x3fff), + dir = ProtoField.new("Direction", "egts.dir", ftypes.UINT8, nil, base.DEC), + odm = ProtoField.new("Odometer", "egts.odm", ftypes.UINT32, nil, base.DEC), + din = ProtoField.new("Digital inputs", "egts.din", ftypes.UINT8, nil, base.DEC), + src = ProtoField.new("Source", "egts.src", ftypes.UINT8, nil, base.DEC), + alt = ProtoField.new("Altitude", "egts.alt", ftypes.UINT32, nil, base.DEC), + srcd = ProtoField.new("Source data", "egts.srcd", ftypes.UINT16, nil, base.DEC), + nsfe = ProtoField.new("NSFE", "egts.nsfe", ftypes.UINT8, nil, base.DEC, 0x10), + sfe = ProtoField.new("SFE", "egts.sfe", ftypes.UINT8, nil, base.DEC, 0x8), + pfe = ProtoField.new("PFE", "egts.pfe", ftypes.UINT8, nil, base.DEC, 0x4), + hfe = ProtoField.new("HFE", "egts.hfe", ftypes.UINT8, nil, base.DEC, 0x2), + vfe = ProtoField.new("VFE", "egts.vfe", ftypes.UINT8, nil, base.DEC, 0x1), + vdop = ProtoField.new("Vertical dilution of precision", "egts.vdop", ftypes.UINT16, nil, base.DEC), + hdop = ProtoField.new("Horizontal dilution of precision", "egts.hdop", ftypes.UINT16, nil, base.DEC), + pdop = ProtoField.new("Position dilution of precision", "egts.pdop", ftypes.UINT16, nil, base.DEC), + sat = ProtoField.new("Satellites", "egts.sat", ftypes.UINT8, nil, base.DEC), + ns = ProtoField.new("Navigation system", "egts.ns", ftypes.UINT16, nil, base.DEC), + st = ProtoField.new("State", "egts.ns", ftypes.UINT8, nil, base.DEC), + mpsv = ProtoField.new("Main power source voltage", "egts.mpsv", ftypes.UINT8, nil, base.DEC), + bbv = ProtoField.new("Back up battery voltage", "egts.bbv", ftypes.UINT8, nil, base.DEC), + ibv = ProtoField.new("Internal battery voltage", "egts.ibv", ftypes.UINT8, nil, base.DEC), + nms = ProtoField.new("NMS", "egts.nms", ftypes.UINT8, nil, base.DEC, 0x4), + ibu = ProtoField.new("IBU", "egts.ibu", ftypes.UINT8, nil, base.DEC, 0x2), + bbu = ProtoField.new("BBU", "egts.bbu", ftypes.UINT8, nil, base.DEC, 0x1), + sfrcs = ProtoField.new("Services frame data checksum", "egts.sfrcs", ftypes.UINT16, nil, base.HEX), + llsef = ProtoField.new("Liquid Level Sensor Error Flag", "egts.llsef", ftypes.UINT8, nil, base.DEC, 0x40), + llsvu = ProtoField.new("Liquid Level Sensor Value Unit", "egts.llsvu", ftypes.UINT8, nil, base.DEC, 0x30), + rdf = ProtoField.new("Raw Data Flag", "egts.rdf", ftypes.UINT8, nil, base.DEC, 0x8), + llsn = ProtoField.new("Liquid Level Sensor Number", "egts.llsn", ftypes.UINT8, nil, base.DEC, 0x7), + maddr = ProtoField.new("Module address", "egts.maddr", ftypes.UINT16, nil, base.DEC), + llsd = ProtoField.new("Liquid Level Sensor Data", "egts.llsd", ftypes.UINT32, nil, base.DEC), + llsdraw = ProtoField.new("Liquid Level Sensor Data bytes", "egts.llsdraw", ftypes.STRING), + dioe1 = ProtoField.new("Digital Inputs Octet Exists 1", "egts.dioe1", ftypes.UINT8, nil, base.DEC, 0x1), + dioe2 = ProtoField.new("Digital Inputs Octet Exists 2", "egts.dioe2", ftypes.UINT8, nil, base.DEC, 0x2), + dioe3 = ProtoField.new("Digital Inputs Octet Exists 3", "egts.dioe3", ftypes.UINT8, nil, base.DEC, 0x4), + dioe4 = ProtoField.new("Digital Inputs Octet Exists 4", "egts.dioe4", ftypes.UINT8, nil, base.DEC, 0x8), + dioe5 = ProtoField.new("Digital Inputs Octet Exists 5", "egts.dioe5", ftypes.UINT8, nil, base.DEC, 0x10), + dioe6 = ProtoField.new("Digital Inputs Octet Exists 6", "egts.dioe6", ftypes.UINT8, nil, base.DEC, 0x20), + dioe7 = ProtoField.new("Digital Inputs Octet Exists 7", "egts.dioe7", ftypes.UINT8, nil, base.DEC, 0x40), + dioe8 = ProtoField.new("Digital Inputs Octet Exists 8", "egts.dioe8", ftypes.UINT8, nil, base.DEC, 0x80), + dout = ProtoField.new("Digital Outputs", "egts.dout", ftypes.UINT8, nil, base.DEC), + asfe1 = ProtoField.new("Analog Sensor Fields Exist 1", "egts.asfe1", ftypes.UINT8, nil, base.DEC, 0x1), + asfe2 = ProtoField.new("Analog Sensor Fields Exist 2", "egts.asfe2", ftypes.UINT8, nil, base.DEC, 0x2), + asfe3 = ProtoField.new("Analog Sensor Fields Exist 3", "egts.asfe3", ftypes.UINT8, nil, base.DEC, 0x4), + asfe4 = ProtoField.new("Analog Sensor Fields Exist 4", "egts.asfe4", ftypes.UINT8, nil, base.DEC, 0x8), + asfe5 = ProtoField.new("Analog Sensor Fields Exist 5", "egts.asfe5", ftypes.UINT8, nil, base.DEC, 0x10), + asfe6 = ProtoField.new("Analog Sensor Fields Exist 6", "egts.asfe6", ftypes.UINT8, nil, base.DEC, 0x20), + asfe7 = ProtoField.new("Analog Sensor Fields Exist 7", "egts.asfe7", ftypes.UINT8, nil, base.DEC, 0x40), + asfe8 = ProtoField.new("Analog Sensor Fields Exist 8", "egts.asfe8", ftypes.UINT8, nil, base.DEC, 0x80), + adio1 = ProtoField.new("Additional Digital Inputs Octet 1", "egts.adio1", ftypes.UINT8, nil, base.DEC), + adio2 = ProtoField.new("Additional Digital Inputs Octet 2", "egts.adio2", ftypes.UINT8, nil, base.DEC), + adio3 = ProtoField.new("Additional Digital Inputs Octet 3", "egts.adio3", ftypes.UINT8, nil, base.DEC), + adio4 = ProtoField.new("Additional Digital Inputs Octet 4", "egts.adio4", ftypes.UINT8, nil, base.DEC), + adio5 = ProtoField.new("Additional Digital Inputs Octet 5", "egts.adio5", ftypes.UINT8, nil, base.DEC), + adio6 = ProtoField.new("Additional Digital Inputs Octet 6", "egts.adio6", ftypes.UINT8, nil, base.DEC), + adio7 = ProtoField.new("Additional Digital Inputs Octet 7", "egts.adio7", ftypes.UINT8, nil, base.DEC), + adio8 = ProtoField.new("Additional Digital Inputs Octet 8", "egts.adio8", ftypes.UINT8, nil, base.DEC), + ans1 = ProtoField.new("Analog Sensor 1", "egts.ans1", ftypes.UINT16, nil, base.DEC), + ans2 = ProtoField.new("Analog Sensor 2", "egts.ans2", ftypes.UINT16, nil, base.DEC), + ans3 = ProtoField.new("Analog Sensor 3", "egts.ans3", ftypes.UINT16, nil, base.DEC), + ans4 = ProtoField.new("Analog Sensor 4", "egts.ans4", ftypes.UINT16, nil, base.DEC), + ans5 = ProtoField.new("Analog Sensor 5", "egts.ans5", ftypes.UINT16, nil, base.DEC), + ans6 = ProtoField.new("Analog Sensor 6", "egts.ans6", ftypes.UINT16, nil, base.DEC), + ans7 = ProtoField.new("Analog Sensor 7", "egts.ans7", ftypes.UINT16, nil, base.DEC), + ans8 = ProtoField.new("Analog Sensor 8", "egts.ans8", ftypes.UINT16, nil, base.DEC), + cn = ProtoField.new("Counter Number", "egts.cn", ftypes.UINT8, nil, base.DEC), + cnv = ProtoField.new("Counter Value", "egts.cnv", ftypes.UINT16, nil, base.DEC), + -- EGTS_SR_COMMAND_DATA + CT = ProtoField.new("Command Type", "egts.CT", ftypes.UINT8, command_srv_command_type, base.DEC, 0xF0), + CCT = ProtoField.new("Command Confirmation Type", "egts.CCT", ftypes.UINT8, command_srv_command_confirmation_type, base.DEC, 0x0F), + CID = ProtoField.new("Command Identifier", "egts.CID", ftypes.UINT32, nil, base.DEC), + SID = ProtoField.new("Source Identifier", "egts.SID", ftypes.UINT32, nil, base.DEC), + + ACFE = ProtoField.new("Authorization Code Field Exist", "egts.ACFE", ftypes.UINT8, nil, base.DEC, 0x02), + CHSFE = ProtoField.new("Charset Field Exists", "egts.CHSFE", ftypes.UINT8, nil, base.DEC, 0x01), + + CHS = ProtoField.new("Charset", "egts.CHS", ftypes.UINT8, nil, base.DEC), + ACL = ProtoField.new("Authorization Code Length", "egts.ACL", ftypes.UINT8, nil, base.DEC), + AC = ProtoField.new("Authorization Code", "egts.AC", ftypes.STRING), + + ADR = ProtoField.new("Address", "egts.ADR", ftypes.UINT16, nil, base.DEC), + + SZ = ProtoField.new("Size", "egts.SZ", ftypes.UINT8, nil, base.DEC, 0xF0), + ACT = ProtoField.new("Action", "egts.ACT", ftypes.UINT8, nil, base.DEC, 0x0F), + + CCD = ProtoField.new("Command Code", "egts.CCD", ftypes.UINT16, command_srv_command_code, base.HEX), + + DT = ProtoField.new("Data", "egts.DT", ftypes.STRING), +} + + + +-- регистрация полей протокола +egts_proto.fields = header + +local function parse_sr_command_data_body(buf, tree) + local cur_offset = 0 + + tree:add(header.ADR, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + + local sub = buf:range(cur_offset, 1):le_uint() + tree:add(header.SZ, sub) + tree:add(header.ACT, sub) + cur_offset = cur_offset + 1 + + tree:add(header.CCD, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + + if cur_offset < buf:len() then + tree:add(header.DT, buf:range(cur_offset)) + end + +end + +local function parse_sr_command_data(buf, tree) + local cur_offset = 0 + + local types = buf:range(cur_offset, 1):le_uint() + tree:add(header.CT, types) + tree:add(header.CCT, types) + cur_offset = cur_offset + 1 + + tree:add(header.CID, buf:range(cur_offset, 4):le_uint()) + cur_offset = cur_offset + 4 + + tree:add(header.SID, buf:range(cur_offset, 4):le_uint()) + cur_offset = cur_offset + 4 + + local flags = buf:range(cur_offset, 1):le_uint() + tree:add(header.ACFE, flags) + tree:add(header.CHSFE, flags) + cur_offset = cur_offset + 1 + + if bit.band(flags, 0x1) ~= 0 then + tree:add(header.CHS, buf:range(cur_offset, 1):le_uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(flags, 0x2) ~= 0 then + local len = buf:range(cur_offset, 1):le_uint(); + tree:add(header.ACL, len) + cur_offset = cur_offset + 1 + + tree:add(header.AC, buf:range(cur_offset, len)) + cur_offset = cur_offset + len + + end + + --tree:add(header.srd, buf:range(cur_offset):bytes():tohex()) + + local cmd_data = buf:range(cur_offset) + + local cmd = tree:add(egts_proto, cmd_data, "Subrecord data") + + parse_sr_command_data_body(cmd_data, cmd); + + return buf:len() +end + +local MIN_HEADE_LENGHT = 11 + +local function get_packet_type(type_id) + return egts_packet_type[type_id] +end + +local function get_egts_length(tvbuf, pktinfo, offset) + local header_len = tvbuf:range(offset + 3, 1):uint() + local data_len = tvbuf:range(offset + 5, 2):le_uint() + + return header_len + data_len + 2 +end + +local function parse_sr_response(buf, tree) + local cur_offset = 0 + + tree:add(header.crn, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + + tree:add(header.rs, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + return buf:len() +end + +local function parse_sr_term_identity(buf, tree) + local cur_offset = 0 + + tree:add(header.tid, buf:range(cur_offset, 4):le_uint()) + cur_offset = cur_offset + 4 + + local flags = buf:range(cur_offset, 1):le_uint() + tree:add(header.mne, flags) + tree:add(header.bse, flags) + tree:add(header.nide, flags) + tree:add(header.ssra, flags) + tree:add(header.lngce, flags) + tree:add(header.imsie, flags) + tree:add(header.imeie, flags) + tree:add(header.hdide, flags) + cur_offset = cur_offset + 1 + + if bit.band(flags, 0x1) ~= 0 then + tree:add(header.hdid, buf:range(cur_offset, 2):uint()) + cur_offset = cur_offset + 2 + end + + if bit.band(flags, 0x2) ~= 0 then + tree:add(header.imei, buf:range(cur_offset, 15):string()) + cur_offset = cur_offset + 15 + end + + if bit.band(flags, 0x4) ~= 0 then + tree:add(header.imsi, buf:range(cur_offset, 16):string()) + cur_offset = cur_offset + 16 + end + + if bit.band(flags, 0x8) ~= 0 then + tree:add(header.lngc, buf:range(cur_offset, 3):string()) + cur_offset = cur_offset + 3 + end + + if bit.band(flags, 0x20) ~= 0 then + tree:add(header.nid, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(flags, 0x40) ~= 0 then + tree:add(header.bs, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + end + + if bit.band(flags, 0x80) ~= 0 then + tree:add(header.msisdn, buf:range(cur_offset, 15):le_uint()) + cur_offset = cur_offset + 15 + end + + return cur_offset +end + +local function parse_sr_pos_data(buf, tree) + local cur_offset = 0 + + local ntm = buf:range(cur_offset, 4):le_uint() + local offset_time = os.time { year = 2010, month = 1, day = 1, hour = 0 } + ntm = ntm + offset_time + + tree:add(header.ntm, NSTime.new(ntm)) + cur_offset = cur_offset + 4 + + tree:add(header.lat, buf:range(cur_offset, 4):le_uint() * 90 / 0xFFFFFFFF) + cur_offset = cur_offset + 4 + + tree:add(header.long, buf:range(cur_offset, 4):le_uint() * 180 / 0xFFFFFFFF) + cur_offset = cur_offset + 4 + + local flg = buf:range(cur_offset, 1):uint() + tree:add(header.alte, flg) + tree:add(header.lohs, flg) + tree:add(header.lahs, flg) + tree:add(header.mv, flg) + tree:add(header.bb, flg) + tree:add(header.cs, flg) + tree:add(header.fix, flg) + tree:add(header.vld, flg) + cur_offset = cur_offset + 1 + + local spd = buf:range(cur_offset, 2):le_uint() + tree:add(header.dirh, spd) + tree:add(header.alts, spd) + tree:add(header.spd, spd) + cur_offset = cur_offset + 2 + + tree:add(header.dir, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.odm, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + + tree:add(header.din, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.src, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + if bit.band(flg, 0x80) ~= 0 then + tree:add(header.alt, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + -- TODO: разобраться с разбором SourceData + return buf:len() +end + +local function parse_sr_ext_pos_data(buf, tree) + local cur_offset = 0 + local flags = buf:range(cur_offset, 1):uint() + tree:add(header.nsfe, flags) + tree:add(header.sfe, flags) + tree:add(header.pfe, flags) + tree:add(header.hfe, flags) + tree:add(header.vfe, flags) + cur_offset = cur_offset + 1 + + if bit.band(flags, 0x1) ~= 0 then + -- если флаг VFE установлен, то есть поле снижение точности в вертикальной плоскости + tree:add(header.vdop, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + end + + if bit.band(flags, 0x2) ~= 0 then + -- если флаг HFE установлен, то есть поле снижение точности в горизонтальной плоскости + tree:add(header.hdop, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + end + + if bit.band(flags, 0x4) ~= 0 then + -- если флаг HFE установлен, то есть поле снижение точности по местоположению + tree:add(header.pdop, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + end + + local sectionLen = buf:len() + if bit.band(flags, 0x8) ~= 0 then + -- если флаг SFE установлен, то есть поле c данными о текущем количестве видимых спутников и типе используемой навигационной спутниковой системы + tree:add(header.sat, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + if cur_offset < sectionLen then + tree:add(header.ns, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + end + end + + return sectionLen +end + +local function parse_sr_state_data(buf, tree) + local cur_offset = 0 + + tree:add(header.st, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.mpsv, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.bbv, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.ibv, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + local flags = buf:range(cur_offset, 1):uint() + tree:add(header.nms, flags) + tree:add(header.ibu, flags) + tree:add(header.bbu, flags) + cur_offset = cur_offset + 1 + + return cur_offset +end + +local function parse_sr_liquid_level_sensor(buf, tree) + local cur_offset = 0 + + local flags = buf:range(cur_offset, 1):uint() + tree:add(header.llsef, flags) + tree:add(header.llsvu, flags) + tree:add(header.rdf, flags) + tree:add(header.llsn, flags) + cur_offset = cur_offset + 1 + + tree:add(header.maddr, buf:range(cur_offset, 2):le_uint()) + cur_offset = cur_offset + 2 + + if bit.band(flags, 0x8) == 0 then + -- если флаг RDF флаг установлен, то значение имеет длину 4 байта + tree:add(header.llsd, buf:range(cur_offset, 4):le_uint()) + cur_offset = cur_offset + 4 + else + tree:add(header.llsdraw, buf:bytes():tohex()) + end + + return cur_offset +end + +local function parse_sr_ad_sensors_data(buf, tree) + local cur_offset = 0 + local sectionLen = buf:len() + + local diflg = buf:range(cur_offset, 1):uint() + tree:add(header.dioe1, diflg) + tree:add(header.dioe2, diflg) + tree:add(header.dioe3, diflg) + tree:add(header.dioe4, diflg) + tree:add(header.dioe5, diflg) + tree:add(header.dioe6, diflg) + tree:add(header.dioe7, diflg) + tree:add(header.dioe8, diflg) + cur_offset = cur_offset + 1 + + tree:add(header.dout, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + local ansflg = buf:range(cur_offset, 1):uint() + tree:add(header.asfe1, ansflg) + tree:add(header.asfe2, ansflg) + tree:add(header.asfe3, ansflg) + tree:add(header.asfe4, ansflg) + tree:add(header.asfe5, ansflg) + tree:add(header.asfe6, ansflg) + tree:add(header.asfe7, ansflg) + tree:add(header.asfe8, ansflg) + cur_offset = cur_offset + 1 + + if bit.band(diflg, 0x1) ~= 0 then + tree:add(header.adio1, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x2) ~= 0 then + tree:add(header.adio2, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x4) ~= 0 then + tree:add(header.adio3, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x8) ~= 0 then + tree:add(header.adio4, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x10) ~= 0 then + tree:add(header.adio5, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x20) ~= 0 then + tree:add(header.adio6, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x40) ~= 0 then + tree:add(header.adio7, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(diflg, 0x80) ~= 0 then + tree:add(header.adio8, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + end + + if bit.band(ansflg, 0x1) ~= 0 then + tree:add(header.ans1, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x2) ~= 0 then + tree:add(header.ans2, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x4) ~= 0 then + tree:add(header.ans3, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x8) ~= 0 then + tree:add(header.ans4, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x10) ~= 0 then + tree:add(header.ans5, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x20) ~= 0 then + tree:add(header.ans6, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x40) ~= 0 then + tree:add(header.ans7, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + if bit.band(ansflg, 0x80) ~= 0 then + tree:add(header.ans8, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + end + + return sectionLen +end + +local function parse_sr_abs_cntr_data(buf, tree) + local cur_offset = 0 + + tree:add(header.cnv, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + tree:add(header.cnv, buf:range(cur_offset, 3):le_uint()) + cur_offset = cur_offset + 3 + + return offset +end + +local function parse_sr_result_code(buf, tree) + local cur_offset = 0 + + tree:add(header.rs, buf:range(cur_offset, 1):uint()) + cur_offset = cur_offset + 1 + + return buf:len() +end + +local function parse_subrecord(buf, tree) + local subrecords = tree:add(egts_proto, buf, "Record data") + local current_offset = 0 + while current_offset < buf:len() do + local subrecord = subrecords:add(egts_proto, buf, "Subrecord") + + local subrecord_type = buf:range(current_offset, 1):uint() + subrecord:add(header.srt, subrecord_type) + current_offset = current_offset + 1 + + local subrecord_data_len = buf:range(current_offset, 2):le_uint() + subrecord:add(header.srl, subrecord_data_len) + current_offset = current_offset + 2 + + local sr_data = buf:range(current_offset, subrecord_data_len) + + local srd = subrecord:add(egts_proto, sr_data, "Subrecord data") + + if subrecord_type == 0 then + parse_sr_response(sr_data, srd) + elseif subrecord_type == 1 then + parse_sr_term_identity(sr_data, srd) + elseif subrecord_type == 9 then + parse_sr_result_code(sr_data, srd) + elseif subrecord_type == 16 then + parse_sr_pos_data(sr_data, srd) + elseif subrecord_type == 17 then + parse_sr_ext_pos_data(sr_data, srd) + elseif subrecord_type == 20 then + parse_sr_state_data(sr_data, srd) + elseif subrecord_type == 27 then + parse_sr_liquid_level_sensor(sr_data, srd) + elseif subrecord_type == 18 then + parse_sr_ad_sensors_data(sr_data, srd) + elseif subrecord_type == 25 then + parse_sr_abs_cntr_data(sr_data, srd) + elseif subrecord_type == 51 then + parse_sr_command_data(sr_data, srd) + else + subrecord:add(header.srd, sr_data:bytes():tohex()) + end + + current_offset = current_offset + subrecord_data_len + end + + return current_offset +end + +local function parse_sdr(buf, tree) + local current_offset = 0 + local sdr_len = 0 + while (current_offset < buf:len()) do + sdr_len = buf:range(current_offset, 2):le_uint() + local service_data_record = tree:add(egts_proto, buf, "Service Data Record") + current_offset = current_offset + 2 + + service_data_record:add(header.rl, sdr_len) + service_data_record:add(header.rn, buf:range(current_offset, 2):le_uint()) + current_offset = current_offset + 2 + + local rfl = buf:range(current_offset, 1):uint() + service_data_record:add(header.ssod, rfl) + service_data_record:add(header.rsod, rfl) + service_data_record:add(header.grp, rfl) + service_data_record:add(header.rpr, rfl) + service_data_record:add(header.tmfe, rfl) + service_data_record:add(header.evfe, rfl) + service_data_record:add(header.obfe, rfl) + current_offset = current_offset + 1 + + if bit.band(rfl, 0x1) ~= 0 then + -- если флаг OBFE установлен, то значит есть поле с id объекта и его надо заполнить + service_data_record:add(header.oid, buf:range(current_offset, 4):le_uint()) + current_offset = current_offset + 4 + end + + if bit.band(rfl, 0x2) ~= 0 then + -- если флаг EVFE установлен, то значит присутствует поле с id события + service_data_record:add(header.evid, buf:range(current_offset, 4):le_uint()) + current_offset = current_offset + 4 + end + + if bit.band(rfl, 0x4) ~= 0 then + -- если флаг TMFE установлен, то есть поле со временем, которое нужно разобрать + service_data_record:add(header.tm, buf:range(current_offset, 4):le_uint()) + current_offset = current_offset + 4 + end + + service_data_record:add(header.sst, buf:range(current_offset, 1):uint()) + current_offset = current_offset + 1 + + service_data_record:add(header.rst, buf:range(current_offset, 1):uint()) + current_offset = current_offset + 1 + + local computed_bytes = parse_subrecord(buf:range(current_offset, sdr_len), service_data_record) + current_offset = current_offset + computed_bytes + end + + return current_offset +end + +local function parse_pt_response (buf, tree) + local current_offset = 0 + tree:add(header.rpid, buf:range(current_offset, 2):le_uint()) + current_offset = current_offset + 2 + + tree:add(header.pr, buf:range(current_offset, 1):uint()) + current_offset = current_offset + 1 + + if buf:len() - current_offset > 0 then + local computed_bytes = parse_sdr(buf:range(current_offset), tree) + current_offset = current_offset + computed_bytes + end + + return buf:len() +end + +local function parse_pt_appdata (buf, tree) + local current_offset = 0 + local computed_bytes = 0 + while (current_offset < buf:len()) do + computed_bytes = parse_sdr(buf:range(current_offset), tree) + current_offset = current_offset + computed_bytes + end + + return current_offset +end + +local function parse_pt_signed_appdata (buf, tree) + tree:add(header.sfrd, buf:raw()) + return buf:len() +end + +local function dissect_egts_pdu(tvbuf, pktinfo, root) + local header_len = tvbuf:range(3, 1):uint() + local data_len = tvbuf:range(5, 2):le_uint() + local msglen = header_len + data_len + 2 + + pktinfo.cols.protocol:set("EGTS") + + -- Начинаем заполнения дерева в отображении + local tree = root:add(egts_proto, tvbuf:range(0, msglen)) + + tree:add(header.prv, tvbuf:range(0, 1):uint()) + tree:add(header.skid, tvbuf:range(1, 1):uint()) + + local prf_tvbr = tvbuf:range(2, 1):uint() + tree:add(header.prf, prf_tvbr) + tree:add(header.rte, prf_tvbr) + tree:add(header.ena, prf_tvbr) + tree:add(header.cmp, prf_tvbr) + tree:add(header.prt, prf_tvbr) + + tree:add(header.hl, header_len) + tree:add(header.he, tvbuf:range(4, 1):uint()) + + tree:add(header.fdl, data_len) + tree:add(header.pid, tvbuf:range(7, 2):le_uint()) + + local packet_type_id = tvbuf:range(9, 1):uint() + tree:add(header.pt, packet_type_id) + + local field_offset = 10; + + if bit.band(prf_tvbr, 0x20) ~= 0 then + -- если RTE флаг присутствует, то заполняем не обязательные поля + + tree:add(header.pra, tvbuf:range(field_offset, 2):le_uint()) + field_offset = field_offset + 2 + tree:add(header.rca, tvbuf:range(field_offset, 2):le_uint()) + field_offset = field_offset + 2 + tree:add(header.ttl, tvbuf:range(field_offset, 1):uint()) + field_offset = field_offset + 1 + end + tree:add(header.hcs, tvbuf:range(field_offset, 1):uint()) + field_offset = field_offset + 1 + + local subtree = tree:add(egts_proto, tvbuf, "Services frame data") + if get_packet_type(packet_type_id) == EGTS_PT_RESPONSE then + parse_pt_response(tvbuf:range(field_offset, data_len), subtree) + elseif get_packet_type(packet_type_id) == EGTS_PT_APPDATA then + parse_pt_appdata(tvbuf:range(field_offset, data_len), subtree) + else + parse_pt_signed_appdata(tvbuf:range(field_offset, data_len), subtree) + end + + tree:add(header.sfrcs, tvbuf:range(field_offset + data_len, 2):le_uint()) + + return msglen +end + +-- задаем функию обработки, которая получает на вход данные tvbuf (объект Tvb), информацию о пакете +-- pktinfo (объект Pinfo) и root дерево распарсенного объекта. +function egts_proto.dissector(tvbuf, pktinfo, root) + dissect_tcp_pdus(tvbuf, root, MIN_HEADE_LENGHT, get_egts_length, dissect_egts_pdu) + local bytes_consumed = tvbuf:len() + return bytes_consumed + +end + +-- добавляем парсер в таблицу +DissectorTable.get("tcp.port"):add(default_settings.port, egts_proto) diff --git a/Tst/listner.sh b/Tst/listner.sh new file mode 100755 index 0000000..b52b4c2 --- /dev/null +++ b/Tst/listner.sh @@ -0,0 +1,3 @@ +while true; do + nc -l 5020; +done \ No newline at end of file diff --git a/Tst/modular.json b/Tst/modular.json new file mode 100644 index 0000000..168f06d --- /dev/null +++ b/Tst/modular.json @@ -0,0 +1,18 @@ +{ + "dep": [ + { + "type": "local", + "dir": "../" + }, + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "ArrayPrint" + }, + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "AsciiStringParsingUtils" + } + ] +} \ No newline at end of file diff --git a/Tst/test_module.c b/Tst/test_module.c new file mode 100644 index 0000000..3db57c4 --- /dev/null +++ b/Tst/test_module.c @@ -0,0 +1,253 @@ +// +// Created by xemon on 8/23/22. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ArrayPrint.h" + +void SystemDelayMs() { + + +} + +void parseTest(uint8_t *data, size_t data_size) { + + EgtsWorkerEnvironment egtsWorkerEnv; + + egtsWorkerEnv.workingBufferLength = data_size; + egtsWorkerEnv.workingBuffer = data; + + if (EgtsIsTransportComplete(&egtsWorkerEnv)) { + EgtsParseHeader(&egtsWorkerEnv); + EgtsParseFrameData(&egtsWorkerEnv); + EgtsParseSrvRecord(&egtsWorkerEnv); + if (egtsWorkerEnv.header.type == EGTS_PT_RESPONSE) { + printf(" - EGTS_PT_RESPONSE\n"); + } else if (egtsWorkerEnv.header.type == EGTS_PT_APPDATA) { + printf(" - EGTS_PT_APPDATA\n"); + } else { + printf(" - unknown %i\n", egtsWorkerEnv.header.type); + } + + if (egtsWorkerEnv.srCommand) { +///sms + switch (egtsWorkerEnv.srCommand->cmd) { + case EGTS_ECALL_MSD_REQ: + printf("Запрос МНД"); + return; + + case EGTS_ECALL_REQ: + printf("Запрос эксренного вызова"); + return; + + case EGTS_ECALL_TEST_NUMBER: + printf("Запрос на установку номера для тестового вызова"); + return; + + case EGTS_ECALL_SMS_FALLBACK_NUMBER: + printf("Запрос на установку номера для SMS"); + return; + } + } + } + +} + +uint8_t sendTcp(char *ip, uint16_t port, uint8_t *data, size_t size) { + int sockfd = 0, n = 0; + char recvBuff[1024]; + struct sockaddr_in serv_addr; + + + printf("\n Usage: %s \n", ip); + + + memset(recvBuff, '0', sizeof(recvBuff)); + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("\n Error : Could not create socket \n"); + return 1; + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + + if (inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0) { + printf("\n inet_pton error occured\n"); + return 1; + } + + if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + printf("\n Error : Connect Failed \n"); + return 1; + } + +// while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) +// { +// recvBuff[n] = 0; +// if(fputs(recvBuff, stdout) == EOF) +// { +// printf("\n Error : Fputs error\n"); +// } +// } + + + write(sockfd, data, size); + + if (n < 0) { + printf("\n Read error \n"); + } + + return 0; +} + +void testResponse() { + uint8_t data[1024]; + + size_t len = vEgtsPackEgtsResponse( + 111, + data, + 0b000, + 333, + 444, + 0 + ); + + + +///============================= +// uint16_t Address = 1; +// uint8_t Size = 0b0001; +// uint8_t Action = 0b0010; +// uint16_t CommandCode = EGTS_TEST_MODE; +// uint32_t Data = 0; +// size_t len = vEgtsPackSrCmdConfirmation( +// data, +// 2, +// CT_COMCONF, +// CC_OK, +// 44, +// 0, +// 0, +// 0, +// Address, +// Size, +// Action, +// CommandCode, +// Data +// ); +///============================= + +// uint8_t imei[] = "356133310612543"; +// size_t len = vEgtsPackTermIdentityTransport( +// 1, +// data, +// imei, +// sizeof(imei) - 1, +// 1233, +// 0 +// ); + +// size_t len = vEgtsPackMsdTransport( +// 555, +// data, +// imei, +// sizeof(imei) - 1, +// 0 +// ); + + ArrayPrint_Hex(data, len); + + sendTcp("127.0.0.1", 5020, data, len); + +} + +#define BIN(DATA, LEN, HEX_STRING) \ +uint8_t DATA[(sizeof(HEX_STRING)-1)/2]; \ +size_t LEN = iAsciiStringParseHexBytes(DATA, HEX_STRING, sizeof(HEX_STRING) - 1); + +void send_test() { + +// char hexData[] = "0100000B001E00080001BD13000800010800000004043310005F08000000A90100000001000012010044C8"; +// char hexData[] = "0100010B0018000000012E0D0001000400C5C2B40404330A000101000000A9010000002DB0"; +// char hexData[] = "0100010B0018000000012E0D0001000400C5C2B40404330A000105000000A901000000C22C"; + + + +// char hexData[] = "0100000B001E000300012513000300010300000004043310005003000000A9010000000100001201003DEF"; + +/// set sms number + +// BIN_FROM_HEX(binData,binDataLen,"0100000B0028000A00013D1D000A00010A0000000404331A00500A000000A9010000000100420D0237393410102010101010101010"); +// BIN_FROM_HEX(binData, binDataLen, "0100020B001D004800019916004900000404331300507347061B00000000000C00000000EBAEBAEB1C01"); +// BIN_FROM_HEX(binData, binDataLen, "0100020B001D00020001B516000300000404331300507347061B00000000000C00000000EBAEBAEBC589"); + +// BIN_FROM_HEX(binData, binDataLen, "0100020B001C0007000109150008000004043312005080E5061B00000000000A000000004C44932560"); +// BIN_FROM_HEX(binData, binDataLen, "0100010B001400070000DD07000006000100041F16B1830404000300080000020A"); + +// BIN_FROM_HEX(binData, binDataLen, "0100020B001C00030001201500040000040433120050E2F3061B00000000000A00000000B5EB2DAB72"); +// BIN_FROM_HEX(binData, binDataLen, "0100010B00110003000109060001000426732E19040400030004000065C5"); + +// BIN_FROM_HEX(binData, binDataLen, "0100020B001D00020001B51600030000040433130050C276111B00000000000A0000000074657374DAA0"); +// BIN_FROM_HEX(binData, binDataLen, "0100010B001D000200016E120001000400C5C2B40404330F0010C276111B00000000000A000000009198"); +// +// 01 00 03 0B 00 1000 3800 00 3C 3800 00 06003900000202000300010000DD22 + + + BIN_FROM_HEX(binData, binDataLen, "0100000B0019000200013812000200800404330F0010020000009F010000000100120100B347"); + + parseTest(binData, binDataLen); + sendTcp("127.0.0.1", 5020, binData, binDataLen); + + +// testResponse(); + + printf("\n"); +} + + +void parse_test() { + //запрос на скорость +// BIN_FROM_HEX(binData, binDataLen, "0100020B001D004800019916004900000404331300507347061B00000000000C00000000EBAEBAEB1C01"); + BIN_FROM_HEX(binData, binDataLen, + "0100020B001D00020001B516000300000404331300507347061B00000000000C00000000EBAEBAEBC589"); + parseTest(binData, binDataLen); +} + +void test_sensors() { + uint8_t data[1024]; + + tEgtsSensorsDataArgs sensors = { + .analogInPresent = SENSOR_1 | SENSOR_2, + .digitalInPresent = SENSOR_1 | SENSOR_5, + .digitalOutPresent = SENSOR_NO, + .digitalIn = {SENSOR_1 | SENSOR_5, SENSOR_8 | SENSOR_7}, + .analogIn = {200,500} + }; + + size_t len = vEgtsPackSensorsTransport( + 111, + data, + 0b000, + &sensors + ); + + sendTcp("127.0.0.1", 5020, data, len); + +} + +int main() { +// send_test(); +// parse_test(); + test_sensors(); +} \ No newline at end of file diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..904666f --- /dev/null +++ b/modular.json @@ -0,0 +1,27 @@ +{ + "dep": [ + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "BitBufferOperations" + }, + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "SystemDelayInterface" + }, + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "BaseTypes" + } + ], + "cmake": { + "inc_dirs": [ + "Inc" + ], + "srcs": [ + "Src/**.c" + ] + } +} \ No newline at end of file