inwudriver-weibo/app/mrs/proto/mrs_proto_1376_2.c

465 lines
14 KiB
C

/*
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
* Description: MRS protocol
*/
#include "mrs_proto_1376_2.h"
#include "mrs_common_tools.h"
#include "mrs_dfx.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MRS_13762_HEAD_BYTE 0x68
#define MRS_13762_TAIL_BYTE 0x16
#define MRS_13762_HEAD_SIZE 1
#define MRS_13762_LEN_SIZE 2
#define MRS_13762_CTRL_SIZE 1
#define MRS_13762_R_SIZE 6
#define MRS_13762_AFN_SIZE 1
#define MRS_13762_FN_SIZE 2
#define MRS_13762_CS_SIZE 1
#define MRS_13762_TAIL_SIZE 1
#define MRS_13762_FRAME_MIN_SIZE (MRS_13762_HEAD_SIZE + MRS_13762_LEN_SIZE + MRS_13762_CTRL_SIZE + \
MRS_13762_R_SIZE + MRS_13762_AFN_SIZE + MRS_13762_FN_SIZE + \
MRS_13762_CS_SIZE + MRS_13762_TAIL_SIZE)
#define MRS_13762_COM_FORM 3
#define MRS_13762_DIR_DN 0
#define MRS_13762_DIR_UP 1
#define MRS_YEAR_BASE 2000
static td_void mrs_proto_1376_2_rx_notify(EXT_CONST mrs_proto_buffer *buf);
static td_void mrs_proto_1376_2_rx_full_notify(EXT_CONST mrs_proto_buffer *buf);
static td_void mrs_proto_1376_2_parse(mrs_proto_buffer *buf);
static td_u8 mrs_proto_1376_2_get_fn(const td_u8 dt[2]); /* 2bytes */
td_u32 mrs_proto_1376_2_init(td_void)
{
mrs_proto_handler handler = { mrs_proto_1376_2_rx_notify, mrs_proto_1376_2_rx_full_notify, mrs_proto_1376_2_parse };
mrs_proto_register_handler(&handler);
return EXT_ERR_SUCCESS;
}
td_bool mrs_proto_1376_2_check(td_pbyte buffer, td_u16 length)
{
td_u16 frm_len;
td_u8 cs;
if ((buffer == TD_NULL) || (length < MRS_13762_FRAME_MIN_SIZE)) {
return TD_FALSE;
}
if ((buffer[0] != MRS_13762_HEAD_BYTE) || (buffer[length - 1] != MRS_13762_TAIL_BYTE)) {
return TD_FALSE;
}
frm_len = uapi_make_u16(buffer[1], buffer[2]); /* index 1&2: length */
if (frm_len != length) {
return TD_FALSE;
}
cs = mrs_checksum8(buffer + 3, length - 5); /* shifts 3B, length is 5B less than all */
if (cs != buffer[length - 2]) { /* check sum shifts 2bytes */
return TD_FALSE;
}
return TD_TRUE;
}
static td_u32 mrs_proto_1376_2_check_sucess_for_parse(mrs_proto_buffer *buf, td_pbyte head,
td_pbyte *buffer, td_u16 *length)
{
td_u16 frm_len;
frm_len = uapi_make_u16(head[1], head[2]); /* index 1&2: length */
if (frm_len > sizeof(buf->buffer)) {
(*buffer)++;
(*length)--;
return EXT_ERR_CONTINUE;
}
if (*length < frm_len) {
if (memmove_s(buf->buffer, sizeof(buf->buffer), head, *length) != EOK) {}
buf->rx_len = *length;
return EXT_ERR_FAILURE;
}
if (mrs_proto_1376_2_check(head, frm_len) == TD_TRUE) {
td_pbyte payload = (td_pbyte)mrs_malloc(frm_len);
td_u32 ret;
if (payload == TD_NULL) {
buf->rx_len = 0;
return EXT_ERR_FAILURE;
}
(td_void) memcpy_s(payload, frm_len, head, frm_len);
mrs_dfx_uart_chl_rx_frame(frm_len, EXT_ERR_SUCCESS, TD_FALSE);
ret = mrs_msg_queue_send(MRS_MSG_ID_APP_FRAME_RX_13762, frm_len, (uintptr_t)payload, 0);
if (ret != EXT_ERR_SUCCESS) {
mrs_dfx_uart_chl_rx_frame(frm_len, ret, TD_FALSE);
mrs_free(payload);
buf->rx_len = 0;
return EXT_ERR_FAILURE;
}
(*buffer) += frm_len;
*length -= frm_len;
return EXT_ERR_CONTINUE;
}
return EXT_ERR_SUCCESS;
}
static td_void mrs_proto_1376_2_parse(mrs_proto_buffer *buf)
{
td_pbyte buffer = buf->buffer;
td_u16 length = buf->rx_len;
td_u32 ret;
while (length > 0) {
td_pbyte head = mrs_find_byte_in_stream(buffer, length, MRS_13762_HEAD_BYTE);
if (head == TD_NULL) {
buf->rx_len = 0;
return;
}
length -= (td_u16)(head - buffer);
buffer = head;
if (length <= 2) { /* length less than 2bytes */
if (memmove_s(buf->buffer, sizeof(buf->buffer), head, length) != EOK) {}
buf->rx_len = length;
return;
}
ret = mrs_proto_1376_2_check_sucess_for_parse(buf, head, &buffer, &length);
if (ret == EXT_ERR_CONTINUE) {
continue;
} else if (ret == EXT_ERR_FAILURE) {
return;
}
buffer++;
length--;
}
buf->rx_len = 0;
}
static td_void mrs_proto_1376_2_rx_notify(EXT_CONST mrs_proto_buffer *buf)
{
mrs_timer_start(MRS_TIMER_ID_UART,
(buf->simu_enable == TD_FALSE) ? MRS_UART_FRAME_INTERVAL : MRS_SIMU_FRAME_INTERVAL,
EXT_TIMER_TYPE_ONCE);
}
static td_void mrs_proto_1376_2_rx_full_notify(EXT_CONST mrs_proto_buffer *buf)
{
ext_unref_param(buf);
mrs_proto_parse(TD_FALSE);
}
td_void mrs_proto_1376_2_on_timer(td_void)
{
mrs_proto_parse(TD_TRUE);
}
static td_u32 mrs_proto_1376_2_get_frame_for_decode(mrs_proto_1376_2_frame *frame,
td_pbyte *data, td_u16 length)
{
td_u16 min_size_13762 = (td_u16)MRS_13762_FRAME_MIN_SIZE;
td_u16 addr_len = 0;
frame->comm = **data & 0x3F;
frame->prm = (**data >> 6) & 0x01; /* the 6th bit */
frame->dir = (**data >> 7) & 0x01; /* the 7th bit means dir */
if (frame->dir == 1) {
/* ignore up frame */
return EXT_ERR_BAD_DATA;
}
/* R filed */
(*data)++;
frame->route_flag = **data & 0x1;
frame->sub_flag = (**data >> 1) & 0x01;
frame->module_flag = (**data >> 2) & 0x01; /* the 2nd bit means module flag */
frame->conflict_flag = (**data >> 3) & 0x01; /* the 3rd bit means conflict flag */
frame->relay_level = (**data >> EXT_U4_BITS) & EXT_U4_MAX; /* high 4bits means relay level */
(*data)++;
frame->ch_flag = **data & EXT_U4_MAX;
frame->err_corr_code = (**data >> EXT_U4_BITS) & EXT_U4_MAX; /* high 4bits means err correction code */
(*data)++;
frame->expect_bytes_phase = *((*data)++);
*data += 2; /* skip rate(2B) */
frame->seq = *((*data)++);
if (frame->module_flag == 1) {
addr_len = (frame->relay_level + 2) * EXT_METER_ADDR_LEN; /* relay level add 2 */
if (addr_len + min_size_13762 > length) {
return EXT_ERR_BAD_DATA;
}
if (memcpy_s(frame->src_addr, sizeof(frame->src_addr), *data, EXT_METER_ADDR_LEN) != EOK) {
return EXT_ERR_BAD_DATA;
}
*data += EXT_METER_ADDR_LEN + EXT_METER_ADDR_LEN * frame->relay_level;
if (memcpy_s(frame->dst_addr, sizeof(frame->dst_addr), *data, EXT_METER_ADDR_LEN) != EOK) {
return EXT_ERR_BAD_DATA;
}
*data += EXT_METER_ADDR_LEN;
}
frame->data_len = length - min_size_13762 - addr_len;
frame->afn = *((*data)++);
frame->fn = mrs_proto_1376_2_get_fn(*data);
if (frame->fn == 0) {
return EXT_ERR_BAD_DATA;
}
*data += 2; /* fn 2B */
return EXT_ERR_SUCCESS;
}
td_u32 mrs_proto_1376_2_decode(td_pbyte buffer, td_u16 length, mrs_proto_1376_2_frame **frame)
{
mrs_proto_1376_2_frame tmp_frame;
td_pbyte payload;
td_u16 payload_len;
td_pbyte data = buffer;
if (buffer == TD_NULL) {
return EXT_ERR_INVALID_PARAMETER;
}
if (mrs_proto_1376_2_check(buffer, length) != TD_TRUE) {
return EXT_ERR_BAD_DATA;
}
(td_void) memset_s(&tmp_frame, sizeof(tmp_frame), 0, sizeof(tmp_frame));
/* C field */
data += MRS_13762_HEAD_SIZE;
data += MRS_13762_LEN_SIZE;
if (mrs_proto_1376_2_get_frame_for_decode(&tmp_frame, &data, length) != EXT_ERR_SUCCESS) {
return EXT_ERR_BAD_DATA;
}
payload_len = sizeof(mrs_proto_1376_2_frame) + tmp_frame.data_len;
payload = (td_pbyte)mrs_malloc(payload_len);
if (payload == TD_NULL) {
return EXT_ERR_MALLOC_FAILUE;
}
if (memcpy_s(payload, sizeof(mrs_proto_1376_2_frame), &tmp_frame, sizeof(tmp_frame)) != EOK) {
mrs_free(payload);
return EXT_ERR_FAILURE;
}
(td_void) memcpy_s(payload + sizeof(mrs_proto_1376_2_frame), payload_len - sizeof(mrs_proto_1376_2_frame), data,
tmp_frame.data_len);
*frame = (mrs_proto_1376_2_frame *)payload;
return EXT_ERR_SUCCESS;
}
static td_u8 mrs_proto_1376_2_get_fn(const td_u8 dt[2]) /* 2B */
{
td_u8 i;
if (dt[1] >= 32) { /* if the 1st byte more than 32 */
return 0;
}
for (i = 0; i < 8; i++) { /* less than 8 */
if ((dt[0] & (1 << i)) != 0) {
break;
}
}
if (i == 8) { /* if equal to 8 */
return 0;
}
return (td_u8)(dt[1] * 8 + i + 1); /* result: 1stByte *8 +i + 1 */
}
static td_u32 mrs_proto_1376_2_set_frame_for_create(EXT_CONST mrs_proto_1376_2_encode *param,
td_u16 payload_len, td_pbyte payload, td_u16 *offset)
{
/* head byte */
payload[(*offset)++] = MRS_13762_HEAD_BYTE;
/* len */
payload[(*offset)++] = (td_u8)(payload_len & EXT_U8_MAX);
payload[(*offset)++] = (td_u8)((payload_len >> EXT_U8_BITS) & EXT_U8_MAX);
/* C field */
payload[(*offset)++] = (MRS_13762_DIR_UP << 7) | /* the 7th bit */
(param->prm << 6) | MRS_13762_COM_FORM; /* the 6th bit */
/* R field */
payload[(*offset)++] = (td_u8)(param->module_flag << 2); /* module flag shifts 2bits */
payload[(*offset)++] = 0;
payload[(*offset)++] = 0;
payload[(*offset)++] = 0;
payload[(*offset)++] = param->evt_flag;
payload[(*offset)++] = param->seq;
/* addr */
if (param->module_flag == 1) {
if (memcpy_s(payload + *offset, payload_len - *offset, param->src_addr, EXT_METER_ADDR_LEN) != EOK) {
return EXT_ERR_FAILURE;
}
(*offset) += EXT_METER_ADDR_LEN;
if (memcpy_s(payload + *offset, payload_len - *offset, param->dst_addr, EXT_METER_ADDR_LEN) != EOK) {
return EXT_ERR_FAILURE;
}
(*offset) += EXT_METER_ADDR_LEN;
}
/* AFN */
payload[(*offset)++] = param->afn;
/* Fn(Dt) */
payload[(*offset)++] = (1 << ((param->fn - 1) & 0x7));
payload[(*offset)++] = (param->fn - 1) / 8; /* fn calc method : devide 8 */
/* app data */
if (param->length > 0 && memcpy_s(payload + *offset, payload_len - *offset, param->data, param->length) != EOK) {
return EXT_ERR_FAILURE;
}
(*offset) += param->length;
return EXT_ERR_SUCCESS;
}
td_u32 mrs_proto_1376_2_create_frame(const mrs_proto_1376_2_encode *param, td_pbyte *buffer, td_u16 *length)
{
td_pbyte payload;
td_u16 payload_len = MRS_13762_FRAME_MIN_SIZE;
td_u16 offset = 0;
if ((param == TD_NULL) || (buffer == TD_NULL) || (length == TD_NULL)) {
return EXT_ERR_INVALID_PARAMETER;
}
if (param->fn < 1) {
return EXT_ERR_INVALID_PARAMETER;
}
payload_len += (param->module_flag == 1) ? 12 : 0; /* addr 12 */
payload_len += param->length;
payload = (td_pbyte)mrs_malloc(payload_len);
if (payload == TD_NULL) {
return EXT_ERR_MALLOC_FAILUE;
}
(td_void) memset_s(payload, payload_len, 0, payload_len);
if (mrs_proto_1376_2_set_frame_for_create(param, payload_len, payload, &offset) != EXT_ERR_SUCCESS) {
mrs_free(payload);
return EXT_ERR_FAILURE;
}
/* cs */
payload[offset++] = mrs_checksum8(payload + 3, payload_len - 5); /* cs shifts 3B, length is 5B less than all */
/* tail byte */
payload[offset++] = MRS_13762_TAIL_BYTE;
*buffer = payload;
*length = payload_len;
return EXT_ERR_SUCCESS;
}
td_u32 mrs_1376_2_time_verify(const td_pbyte date_time, td_u8 length)
{
td_u8 temp[7]; /* date time 7B */
if (length != 6) { /* length of variable data_time must equal to 6B */
return EXT_ERR_INVALID_PARAMETER;
}
temp[0] = date_time[0]; /* index 0 */
temp[1] = date_time[1]; /* index 1 */
temp[2] = date_time[2]; /* index 2 */
temp[3] = 0; /* index 3 */
temp[4] = date_time[3]; /* index 4 = 3 */
temp[5] = date_time[4]; /* index 5 = 4 */
temp[6] = date_time[5]; /* index 6 = 5 */
return mrs_1376_2_time_week_verify(temp, sizeof(temp));
}
td_u32 mrs_1376_2_time_week_verify(const td_pbyte date_time, td_u8 length)
{
td_u16 year;
td_u8 month;
td_u8 month_day[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; /* 12months */
if ((length != 7) || (mrs_check_bcd_stream(date_time, length) == TD_FALSE)) { /* date time 7B */
return EXT_ERR_BAD_DATA;
}
year = (td_u16)bcd2int(date_time[6]) + MRS_YEAR_BASE; /* year: index 6 */
month = bcd2int(date_time[5]); /* month : index 5 */
if ((month == 0) || (month > 12)) { /* month is between 0 and 12 */
return EXT_ERR_BAD_DATA;
}
if (is_leap_year(year)) {
month_day[2] = 0x29; /* index 2: 0x29 */
}
/* check 'second' */
if (not_in_range(0x01, 0x60, date_time[0] + 1)) {
return EXT_ERR_BAD_DATA;
}
/* check 'minute' */
if (not_in_range(0x01, 0x60, date_time[1] + 1)) {
return EXT_ERR_BAD_DATA;
}
/* check 'hour' */
if (not_in_range(0x01, 0x24, date_time[2] + 1)) { /* index 2 add 1: hour is between 0x01 and 0x24 */
return EXT_ERR_BAD_DATA;
}
/* check 'week' */
if (not_in_range(0x01, 0x07, date_time[3] + 1)) { /* index 3: week is between 0x01 and 0x7 */
return EXT_ERR_BAD_DATA;
}
/* check 'day' */
if (not_in_range(0x01, month_day[month - 1], date_time[4])) { /* index 4: between 0x01 and max day of month */
return EXT_ERR_BAD_DATA;
}
/* check 'month' */
if (not_in_range(0x01, 0x12, date_time[5])) { /* index 5: month is between 0x01 and 0x12 */
return EXT_ERR_BAD_DATA;
}
return EXT_ERR_SUCCESS;
}
#ifdef __cplusplus
}
#endif