inwudriver-weibo/app/mrs/cco/mrs_cco_broadcast.c

189 lines
5.2 KiB
C

/*
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
* Description: CCO broadcast implementation.
*/
#include "mrs_cco_broadcast.h"
#include "mrs_common_tools.h"
#if defined(PRODUCT_CFG_PRODUCT_TYPE_CCO)
#define MRS_CCO_BC_DL_VER 1
#define MRS_CCO_BC_STAT_IDLE 0
#define MRS_CCO_BC_STAT_BUSY 1
#define MRS_CCO_BC_TIMER_INTERVAL 1
#define MRS_CCO_BC_RESEND_MAX 5
typedef struct {
td_u8 state; /* < Global context state */
td_u8 retry; /* < Resend times */
td_u16 interval; /* < Resend polling period */
mrs_broadcast_frame *bc_frame; /* < Resend data */
} mrs_bc_ctx;
/* Init global context */
td_u32 mrs_cco_broadcast_init(td_void);
/* Create broadcast frame for PLC sending */
td_u32 mrs_bc_create_frame(const td_u8 *msg, td_u16 msg_len);
/* Put frame to sending ready queue */
td_u32 mrs_bc_send_frame(td_void);
/* Reset broadcast parameters and free memory */
td_void mrs_cco_broadcast_reset(td_void);
mrs_bc_ctx *g_bc_ctx = TD_NULL;
#define mrs_cco_broadcast_get_ctx() (mrs_bc_ctx *)(g_bc_ctx)
td_u32 mrs_cco_broadcast_init(td_void)
{
if (g_bc_ctx == TD_NULL) {
g_bc_ctx = (mrs_bc_ctx *)mrs_malloc(sizeof(mrs_bc_ctx));
if (g_bc_ctx == TD_NULL) {
return EXT_ERR_MALLOC_FAILUE;
}
g_bc_ctx->interval = MRS_CCO_BC_TIMER_INTERVAL;
g_bc_ctx->retry = 0;
g_bc_ctx->bc_frame = TD_NULL;
g_bc_ctx->state = MRS_CCO_BC_STAT_IDLE;
}
return EXT_ERR_SUCCESS;
}
td_u32 mrs_cco_broadcast_proc(td_u8 *deny_code, const td_pbyte content, td_u16 content_len)
{
td_u32 ret = EXT_ERR_SUCCESS;
mrs_bc_ctx *ctx = mrs_cco_broadcast_get_ctx();
if (content_len == 0) {
return ret;
}
if (ctx == TD_NULL) {
ret = mrs_cco_broadcast_init();
if (ret != EXT_ERR_SUCCESS) {
*deny_code = MRS_1376_2_DENY_TIMEOUT;
return EXT_ERR_MALLOC_FAILUE;
}
ctx = mrs_cco_broadcast_get_ctx();
}
/* Disallow multiable broadcast frames */
if (ctx->state != MRS_CCO_BC_STAT_IDLE) {
*deny_code = MRS_1376_2_DENY_CCO_BUSY;
return EXT_ERR_BUSY;
}
/* Mark flag busy */
ctx->state = MRS_CCO_BC_STAT_BUSY;
ret = mrs_bc_create_frame(content, content_len);
if (ret != EXT_ERR_SUCCESS) {
*deny_code = MRS_1376_2_DENY_TIMEOUT;
mrs_cco_broadcast_reset();
} else {
/* Move to PLC ready queue */
mrs_bc_send_frame();
}
return ret;
}
td_u32 mrs_bc_create_frame(const td_u8 *msg, td_u16 msg_len)
{
td_u32 frame_len = sizeof(mrs_broadcast_frame) + msg_len;
mrs_bc_ctx *ctx = mrs_cco_broadcast_get_ctx();
mrs_broadcast_frame *frame = TD_NULL;
if ((msg == TD_NULL) || (msg_len == 0)) {
return EXT_ERR_INVALID_PARAMETER;
}
frame = (mrs_broadcast_frame *)mrs_malloc(frame_len);
if (frame == TD_NULL) {
return EXT_ERR_MALLOC_FAILUE;
}
/* Set broadcast header */
(td_void) memset_s(frame, frame_len, 0, frame_len);
frame->stru_ver = MRS_CCO_BC_DL_VER;
frame->stru_size = sizeof(mrs_broadcast_frame);
frame->data_len = msg_len;
if (memcpy_s(frame->data, frame->data_len, msg, msg_len) != EOK) {
mrs_free(frame);
return EXT_ERR_MEMCPY_FAIL;
}
/* Store the frame for resending */
ctx->bc_frame = frame;
return EXT_ERR_SUCCESS;
}
td_void mrs_cco_broadcast_send_timeout(td_void)
{
td_u32 ret;
mrs_bc_ctx *ctx = mrs_cco_broadcast_get_ctx();
if ((ctx->retry >= MRS_CCO_BC_RESEND_MAX) || (ctx->bc_frame == TD_NULL)) {
mrs_cco_broadcast_reset();
return;
}
/* Retry */
ctx->retry++;
ret = mrs_bc_send_frame();
if (ret != EXT_ERR_SUCCESS) {
mrs_timer_start(MRS_TIMER_ID_BROADCAST_RESEND, ctx->interval * 1000, EXT_TIMER_TYPE_ONCE); /* time* 1000 */
} else {
mrs_cco_broadcast_reset();
}
}
td_void mrs_cco_broadcast_reset(td_void)
{
if (g_bc_ctx->bc_frame != TD_NULL) {
mrs_free(g_bc_ctx->bc_frame);
g_bc_ctx->bc_frame = TD_NULL;
}
mrs_free(g_bc_ctx);
g_bc_ctx = TD_NULL;
mrs_timer_stop(MRS_TIMER_ID_BROADCAST_RESEND);
}
td_u32 mrs_bc_send_frame(td_void)
{
mrs_bc_ctx *ctx = mrs_cco_broadcast_get_ctx();
mrs_broadcast_frame *bc_frame = ctx->bc_frame;
mrs_plc_frame_data plc;
td_u32 ret;
if (bc_frame == TD_NULL) {
mrs_cco_broadcast_reset();
return EXT_ERR_INVALID_PARAMETER;
}
/* Set PLC header */
(td_void) memset_s(&plc, sizeof(mrs_plc_frame_data), 0, sizeof(mrs_plc_frame_data));
plc.id = PLC_CMD_ID_BC;
plc.payload_len = bc_frame->stru_size + bc_frame->data_len;
plc.payload = (td_u8 *)bc_frame;
(td_void) memset_s(plc.addr, MRS_METER_ADDR_LEN, 0xff, MRS_METER_ADDR_LEN);
ret = mrs_plc_frame_send(&plc);
if (ret != EXT_ERR_SUCCESS) {
mrs_timer_start(MRS_TIMER_ID_BROADCAST_RESEND, ctx->interval * 1000, EXT_TIMER_TYPE_ONCE); /* time *1000 */
return ret;
}
mrs_cco_broadcast_reset();
return EXT_ERR_SUCCESS;
}
#endif /* defined PRODUCT_CFG_PRODUCT_TYPE_CCO */