extern_interface/include/comframe.h

262 lines
9.7 KiB
C
Executable File

#ifndef _INCLUDE_FRAME_
#define _INCLUDE_FRAME_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
//#define COM_FRAME_DEBUG
#define COM_FRAME_MAGIC_NUMBER 0xEB90
#define COM_FRAME_DEFAULT_PAYLOAD_LENGTH 2
#define COM_FRAME_PADDING_DATA 0xAA
#define COM_FRAME_TYPE_COMMAND 0x00C0
#define COM_FRAME_TYPE_SPEECH_INJECTED 0x00D0
#define COM_FRAME_TYPE_SPEECH_TEXT 0x00D0
#define COM_FRAME_TYPE_SPEECH_PCM 0x00D1
#define COM_FRAME_TYPE_AUDIO 0x00D1
#define COM_FRAME_TYPE_REQUEST 0x0090
#define COM_FRAME_TYPE_TELEMETRY_REQUEST 0x00B0
#define COM_FRAME_TYPE_TELEMETRY_ANSWER 0x0070
#define COM_FRAME_TYPE_TELEMETRY_ERROR 0x0071
#define COM_FRAME_ADDRESS_VOIX 0x011A
// added by gejp start 2024.10.03
#define COM_FRAME_TYPE_GRANT_TIME 0x0085
#define COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_REQUEST 0x0083
#define COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_RESPONSE 0x0083
#define byteswapl(x) (0xff000000 & x << 24) \
|(0x00ff0000 & x << 8) \
|(0x0000ff00 & x >> 8) \
|(0x000000ff & x >> 24)
#define byteswaps(x) (0xff00 & x << 8) \
|(0x00ff & x >> 8)
#ifdef __cplusplus
extern "C" {
#endif
struct ComFrameHeader {
uint16_t magic_number;
uint16_t address;
uint16_t type;
uint16_t length;
} __attribute__((packed));
typedef struct _ComFrame {
struct ComFrameHeader header;
uint8_t payload[COM_FRAME_DEFAULT_PAYLOAD_LENGTH];
} ComFrame;
#define ComFrame_HEADER(frame) ((struct ComFrameHeader*)(frame))
#define ComFrame_ADDRESS(frame) (ComFrame_HEADER(frame)->address)
#define ComFrame_TYPE(frame) (ComFrame_HEADER(frame)->type)
#define ComFrame_PAYLOAD(frame) (frame->payload)
#define ComFrame_PAYLOAD_LENGTH(frame) (ComFrame_HEADER(frame)->length - 1)
#define ComFrame_PAYLOAD_ALIGNED_LENGTH(frame) (ComFrame_HEADER(frame)->length & (~1))
#define ComFrame_CHECKSUM(frame) (((uint16_t*)&(frame)->payload)[ComFrame_HEADER(frame)->length >> 1])
#define ComFrame_LENGTH(frame) (sizeof(ComFrame) + ComFrame_PAYLOAD_ALIGNED_LENGTH(frame) - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t))
/// @brief init frame header struct
/// @param header header struct
/// @param address device address
/// @param type frame type
/// @param length frame payload length + 1
static __inline void ComFrameHeader_Init(struct ComFrameHeader* header, uint16_t address, uint16_t type, uint16_t length) {
header->magic_number = COM_FRAME_MAGIC_NUMBER;
header->address = address;
header->type = type;
header->length = length;
}
/// @brief swap haeder structure endianness
/// @param header header struct
static __inline void ComFrameHeader_SwapEndian(struct ComFrameHeader* header) {
header->magic_number = byteswaps(header->magic_number);
header->address = byteswaps(header->address);
header->type = byteswaps(header->type);
header->length = byteswaps(header->length);
}
/// @brief check magic number of header struct
/// @param header header struct
/// @param swap_endian whether to switch endianness
/// @return structure validity, true means invalid
static __inline bool ComFrameHeader_Check(const struct ComFrameHeader* header, const bool swap_endian) {
uint16_t number = header->magic_number;
if (swap_endian) {
number = byteswaps(number);
}
if (number != COM_FRAME_MAGIC_NUMBER) {
return true;
}
number = header->address;
if (swap_endian) {
number = byteswaps(number);
}
if (number != COM_FRAME_ADDRESS_VOIX) {
return true;
}
if (ComFrame_LENGTH(header) < 12) {
return true;
}
number = header->type;
if (swap_endian) {
number = byteswaps(number);
}
// if ( // commented by gejp 20201007
// number != COM_FRAME_TYPE_COMMAND &&
// number != COM_FRAME_TYPE_SPEECH_INJECTED &&
// number != COM_FRAME_TYPE_SPEECH_TEXT &&
// number != COM_FRAME_TYPE_SPEECH_PCM &&
// number != COM_FRAME_TYPE_AUDIO &&
// number != COM_FRAME_TYPE_REQUEST &&
// number != COM_FRAME_TYPE_TELEMETRY_REQUEST
// ) {
// return true;
// }
return false;
}
/// @brief create new com frame uninitialized
/// @param payload_length length of payload
/// @return new uinitialized frame
static __inline ComFrame* ComFrame_NewUninited(uint16_t payload_length) {
if (payload_length & 1) {
payload_length += 1;
}
return (ComFrame*)malloc(sizeof(ComFrame) + payload_length - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t));
}
/// @brief get frame checksum
/// @param frame com frame struct
/// @param swap_endian whether to switch endianness
/// @return checksum
static __inline uint16_t ComFrame_Checksum(const ComFrame* frame, const bool swap_endian) {
const uint16_t* buffer = (const uint16_t*)&frame->payload;
uint16_t length = ComFrame_HEADER(frame)->length;
if (swap_endian) {
length = byteswaps(length);
}
return buffer[length >> 1];
}
/// @brief get frame length
/// @param frame com frame struct
/// @param swap_endian whether to switch endianness
/// @return length of the frame
static __inline uint32_t ComFrame_Length(const ComFrame* frame, const bool swap_endian) {
uint16_t length = ComFrame_HEADER(frame)->length;
if (swap_endian) {
length = byteswaps(length);
}
length &= (~1);
return sizeof(ComFrame) + length - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t);
}
/// @brief destroy the frame
/// @param frame the frame to destroy
static __inline void ComFrame_Del(ComFrame* frame) {
if (frame) free(frame);
}
/// @brief flush receive buffer
/// @param offset the size used, usually the length of the data frame
/// @param buffer receive buffer
/// @param p_cached_size cache size to reset, not null
/// @note please set the offset to 0 after calling the function if used with ComFrame_ReceiveEx
static __inline void ComFrame_ReceiveFlushBuffer(size_t offset, uint8_t* buffer, size_t* p_cached_size) {
*p_cached_size -= offset;
memmove(buffer, buffer + offset, *p_cached_size);
}
/// @brief calculate the checksum of the specified payload
/// @param header header struct (must be little endian)
/// @param payload payload data
/// @return checksum
uint16_t ComFramePayload_EvalChecksum(const struct ComFrameHeader* header, const void* payload);
/// @brief verify the checksum of the specified payload
/// @param header header struct (must be little endian)
/// @param payload payload data
/// @param checksum checksum to verify
/// @param swap_checksum_endian whether to switch checksum endianness
/// @return payload validity, true means invalid
bool ComFramePayload_VerifyChecksum(const struct ComFrameHeader* header, const void* payload, uint16_t checksum);
/// @brief create new com frame from header and known checksum
/// @param header header struct (must be little endian)
/// @param payload payload data
/// @param checksum payload checksum
/// @param swap_endian whether to switch endianness
/// @return new frame
ComFrame* ComFrame_FromHeaderEx(const struct ComFrameHeader* header, const void* payload, uint16_t checksum, const bool swap_endian);
/// @brief create new com frame from header
/// @param header header struct (must be little endian)
/// @param payload payload data
/// @param swap_endian whether to switch endianness
/// @return new frame
ComFrame* ComFrame_FromHeader(const struct ComFrameHeader* header, const void* payload, const bool swap_endian);
/// @brief create new com frame
/// @param address device address
/// @param type frame type
/// @param payload payload data
/// @param payload_length payload data real length
/// @param swap_endian whether to switch endianness
/// @return new frame
ComFrame* ComFrame_New(uint16_t address, uint16_t type, const void* payload, uint16_t payload_length, const bool swap_endian);
/// @brief update frame payload and checksum
/// @param frame com frame struct
/// @param payload payload data or NULL, if set to NULL, the payload will not be updated.
/// @param payload_length payload data real length
/// @param swap_endian whether to switch endianness
void ComFrame_UpdatePayload(ComFrame* frame, const void* payload, const uint16_t payload_length, const bool swap_endian);
/// @brief verify frame checksum
/// @param frame con frame struct
/// @param swap_endian whether to switch endianness
/// @return structure validity, true means invalid
bool ComFrame_Verify(const ComFrame* frame, const bool swap_endian);
/// @brief send a frame to com
/// @param tty_id com tty id
/// @param frame con frame struct
/// @param swap_endian whether to switch endianness
/// @return error number, 0 means ok
ssize_t ComFrame_Send(int tty_id, const ComFrame* frame, const bool swap_endian);
/// @brief receive a frame from com
/// @param tty_id com tty id
/// @param buffer_size receive buffer size
/// @param swap_endian whether to switch endianness
/// @return new frame (little endian) or NULL
ComFrame* ComFrame_Receive(int tty_id, const size_t buffer_size, const bool swap_endian);
/// @brief receive a frame from com
/// @param tty_id com tty id
/// @param buffer buffer pointer, create a new one when it is NULL
/// @param buffer_size receive buffer size
/// @param p_offset offset will be set if not null
/// @param p_cached_size cached size will be set if not null
/// @param p_run_flag run flag pointer, if the inner date is set to false, the function will stop and return NULL
/// @param swap_endian whether to switch endianness
/// @return frame (little endian) in buffer or NULL
ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size, size_t* p_offset, size_t* p_cached_size, bool* p_run_flag, const bool swap_endian);
int get_com_tty_id(const char* path, unsigned int baudRate);
void init_tty(int tty_id, unsigned int baudRate);
#ifdef __cplusplus
}
#endif
#endif