Files
kunlun/app/iot_sunsolar_app/src/iot_sunsolar_task.c
2024-09-28 14:24:04 +08:00

443 lines
13 KiB
C

/****************************************************************************
Copyright(c) 2024 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
/* os_ship header files */
#include "os_task_api.h"
/* iot common header files */
#include "iot_io_api.h"
#include "iot_module_api.h"
#include "iot_errno_api.h"
#include "iot_task_api.h"
#include "iot_pkt_api.h"
#include "iot_board_api.h"
#include "iot_app_api.h"
#include "proto_conn_less.h"
#include "iot_sg_ext_api.h"
#include "iot_plc_msg_api.h"
#include "proto_gw_app.h"
/* sunsolar internal header files */
#include "iot_sunsolar_task.h"
#include "iot_sunsolar_flash.h"
#if (IOT_SUNSOLAR_APP_ENABLE)
/* ipc address of sg app */
static iot_ipc_addr_t sg_app_addr =
{ IOT_IPC_FID_SG_EXT_SDK, IOT_IPC_CID_SG_EXT_SG_APP};
g_sunsolar_t *p_gsunsolar = NULL ;
#if IOT_SUNSOLAR_DEBUG
void iot_sunsolar_data_print(const char* str, uint8_t* buf, uint32_t len)
{
static char log_buf[1024];
uint32_t offset = 0;
offset = iot_sprintf(log_buf, "%s[len:%d]", str, len);
for (uint32_t i = 0; i < len; ++i) {
offset += iot_sprintf(log_buf + offset, "%02X ", buf[i]);
if (IOT_ARRAY_CNT(log_buf) <= offset + 4) {
break;
}
}
log_buf[offset] = 0;
iot_cus_printf("%s\n", log_buf);
}
#else
void iot_sunsolar_data_print(const char* str, uint8_t* buf, uint32_t len)
{
(void)str;
(void)buf;
(void)len;
}
#endif
int32_t iot_sunsolar_rtctime_to_time(iot_time_tm_t *tm)
{
int64_t diff;
iot_time_tm_t tm_base;
tm_base.tm_year = 1970;
tm_base.tm_mon = 1;
tm_base.tm_mday = 1;
/* GMT+800 */
tm_base.tm_hour = 8;
tm_base.tm_min = 0;
tm_base.tm_sec = 0;
diff = iot_rtc_delta_calc(&tm_base, tm);
return (int32_t)diff;
}
void iot_sunsolar_time_to_rtctime(uint32_t time, iot_time_tm_t *tm)
{
iot_time_tm_t tm_base;
tm_base.tm_year = 1970;
tm_base.tm_mon = 1;
tm_base.tm_mday = 1;
tm_base.tm_hour = 8;
tm_base.tm_min = 0;
tm_base.tm_sec = 0;
iot_rtc_delta_add((int64_t)time, &tm_base);
*tm = tm_base;
}
int8_t iot_sunsolar_msdu_send(uint8_t *addr, uint8_t *data, uint16_t len)
{
/* sunsolar send data default retry count */
#define SUNSOLAR_SEND_DATA_DEF_RETRY_CNT 3
uint8_t *ds;
uint16_t pkt_len = 0;
iot_pkt_t *msdu_pkt = NULL;
proto_conn_less_hdr_t *hdr;
uint8_t err_code = 0;
uint8_t bcast_mac_addr[IOT_MAC_ADDR_LEN] = {};
iot_set_bcast_mac(bcast_mac_addr);
/* sta connect packet send */
// TODO: cco need check addr is online or offline
if (p_gsunsolar->plclink_state == SUNSOLAR_ONLINE) {
if (iot_mac_addr_cmp(addr, bcast_mac_addr)) {
msdu_pkt = iot_plc_alloc_msdu(p_gsunsolar->plc_app_h,
IOT_PLC_MSG_TYPE_BCAST, IOT_PLC_ACK_TYPE_NONE,
bcast_mac_addr, p_gsunsolar->local_mac, GW_APP_PRIO_METER_READ,
len, SUNSOLAR_SEND_DATA_DEF_RETRY_CNT);
} else {
msdu_pkt = iot_plc_alloc_msdu(p_gsunsolar->plc_app_h,
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
addr, p_gsunsolar->local_mac, GW_APP_PRIO_METER_READ,
len, SUNSOLAR_SEND_DATA_DEF_RETRY_CNT);
}
} else {
/* connless packet send */
pkt_len = sizeof(proto_conn_less_hdr_t) + len;
msdu_pkt = iot_plc_alloc_conn_less_msdu(p_gsunsolar->plc_app_h,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, bcast_mac_addr,
p_gsunsolar->local_mac, CONN_LESS_APP_PRIO_METER_READ,
pkt_len, SUNSOLAR_SEND_DATA_DEF_RETRY_CNT);
}
if (msdu_pkt == NULL) {
err_code = 1;
goto out;
}
if (p_gsunsolar->plclink_state != SUNSOLAR_ONLINE) {
ds = iot_pkt_tail(msdu_pkt);
iot_pkt_put(msdu_pkt, sizeof(proto_conn_less_hdr_t));
hdr = (proto_conn_less_hdr_t*)ds;
hdr->port = CONN_LESS_APP_PORT;
hdr->id = CONN_LESS_APP_ID_SUNSOLAR;
}
os_mem_cpy(iot_pkt_tail(msdu_pkt), data, len);
iot_pkt_put(msdu_pkt, len);
iot_sunsolar_data_print(TASK_NAME"send msdu:", iot_pkt_data(msdu_pkt),
iot_pkt_data_len(msdu_pkt));
iot_plc_send_msdu(p_gsunsolar->plc_app_h, msdu_pkt);
out:
if (err_code) {
iot_sunsolar_printf("alloc msdu err link_state:%d err_code:%d!\n",
p_gsunsolar->plclink_state, err_code);
}
return err_code;
}
/* iot_sunsolar_plc_callback() - callback method to receive messages from
* plc link
* @param: param registered alone with the callback
* @pkt: pointer to iot packet which contains the message from plc link
*/
static void iot_sunsolar_plc_callback(void *param, iot_pkt_t *pkt)
{
(void)param;
iot_sunsolar_task_msg_post(IOT_SUNSOLAR_MSG_TYPE_PLC,
IOT_SUNSOLAR_MSG_ID_PLC_PKT, 0, pkt, 0);
}
void iot_sunsolar_uart_config(uint32_t baud, uint8_t parity,
uint8_t data, uint8_t stop, uint8_t proto_type)
{
iot_frame_fmt fmt = { 0 };
iot_uart_set_config(p_gsunsolar->uart_h, baud, parity, data, stop);
switch (proto_type) {
case IOT_SUNSOLAR_PROTO_TYPE_645_2007:
{
fmt.preamble_code[0] = PROTO_645_START_CHAR;
fmt.preamble_codelen = 1;
fmt.datalen_offset = 8;
fmt.datalen_size = 1;
fmt.backcode_offset = 1;
fmt.backcode_len = 1;
fmt.datalen_fix = 0;
fmt.backcode[0] = PROTO_645_END_CHAR;
fmt.frame_timeout = 30;
fmt.timeout_mode = TIMEOUT_PERDATA;
iot_uart_set_frame(p_gsunsolar->uart_h, &fmt);
break;
}
case IOT_SUNSOLAR_PROTO_TYPE_TRANSPARENT:
{
iot_uart_set_frame(p_gsunsolar->uart_h, NULL);
break;
}
default:
IOT_ASSERT(0);
break;
}
}
/**
* @brief iot_sunsolar_uart_receive_func() - uart driver callback function
* when data received.
* @param buffer: pointer of data buffer.
* @param buffer_len: length of data received.
* @param is_full_frame: tell if this is a whole frame in this buffer.
* @param invalid_data_len: length of invalid data received. we ignore this.
*/
static void iot_sunsolar_uart_receive_func(uint8_t* p_buffer, uint32_t buffer_len,
bool_t is_full_frame, uint32_t invalid_data_len)
{
(void)invalid_data_len;
iot_pkt_t *pkt;
iot_sunsolar_data_print(TASK_NAME"uart recv:", (void*)p_buffer, buffer_len);
pkt = iot_pkt_alloc(buffer_len, IOT_SUNSOLAR_TASK_ID);
if (pkt) {
os_mem_cpy(iot_pkt_data(pkt), p_buffer, buffer_len);
iot_pkt_put(pkt, buffer_len);
iot_sunsolar_task_msg_post(IOT_SUNSOLAR_MSG_TYPE_UART,
IOT_SUNSOLAR_MSG_ID_UART_DATA, 0, pkt, 0);
}
return;
}
void iot_sunsolar_task_msg_post(uint16_t msg_type, uint16_t msg_id,
uint8_t prio, void *data, uint32_t data2)
{
sunsolar_msg_t *msg;
msg = (sunsolar_msg_t*)iot_task_alloc_msg(p_gsunsolar->task);
if (NULL == msg) {
if (NULL != data) {
iot_pkt_free(data);
}
IOT_ASSERT(0);
return;
}
msg->task_msg.type = msg_type;
msg->task_msg.id = msg_id;
msg->data = data;
msg->data2 = data2;
iot_task_queue_msg(p_gsunsolar->task, &msg->task_msg, prio);
return;
}
uint32_t iot_sunsolar_uart_send(iot_pkt_t *pkt)
{
uint32_t ret = ERR_FAIL;
if (p_gsunsolar->uart_h) {
iot_sunsolar_data_print(TASK_NAME"send uart:", iot_pkt_data(pkt),
iot_pkt_data_len(pkt));
ret = iot_uart_send(p_gsunsolar->uart_h, pkt, NULL);
}
return (ERR_OK == ret) ? ERR_OK : ERR_FAIL;
}
void iot_sunsolar_send_data_to_sg_app(uint8_t *data, uint8_t data_len)
{
iot_pkt_t *pkt;
iot_sg_ext_header_t *hdr;
pkt = iot_ipc_pkt_alloc(data_len + sizeof(*hdr), IOT_SUNSOLAR_TASK_ID);
if (pkt) {
hdr = (iot_sg_ext_header_t*)iot_pkt_data(pkt);
hdr->mid = IOT_SG_EXT_MID_UART_DATA_FROM_CUS;
os_mem_cpy(hdr->data, data, data_len);
iot_pkt_put(pkt, data_len + sizeof(*hdr));
iot_sunsolar_data_print(TASK_NAME"to_sg_app:", data, data_len);
iot_ipc_send(p_gsunsolar->ipc_h, &sg_app_addr, pkt);
} else {
iot_sunsolar_printf("alloc pkt error\n");
}
return;
}
static void iot_sunsolar_ipc_recv(void *param, iot_ipc_addr_t *addr,
iot_pkt_t *pkt)
{
(void)param;
iot_sunsolar_task_msg_post(IOT_SUNSOLAR_MSG_TYPE_SG_APP,
IOT_SUNSOLAR_MSG_ID_SG_DATA, 0, pkt, 0);
}
/**
* @brief iot_sunsolar_task_init() - The main entry to initialize our
* sunsolar task.
* @return ERR_OK
*/
static uint32_t iot_sunsolar_task_init(void)
{
uint32_t ret = ERR_OK;
iot_ipc_client_t client;
iot_sunsolar_printf("task_init pool sz=%d\n",
IOT_SUNSOLAR_TASK_POOL_SIZE);
p_gsunsolar = os_mem_malloc(IOT_SUNSOLAR_TASK_ID,
sizeof(*p_gsunsolar));
if (p_gsunsolar == NULL) {
ret = ERR_NOMEM;
goto out;
}
p_gsunsolar->plclink_state = SUNSOLAR_OFFLINE;
p_gsunsolar->uart_h = iot_uart_open(iot_board_get_uart(UART_METER_PORT),
iot_sunsolar_uart_receive_func, IOT_SUNSOLAR_TASK_UART_BUF_SIZE, NULL);
if (p_gsunsolar->uart_h == NULL) {
iot_sunsolar_printf("open uart port %d error.\n",
iot_board_get_uart(UART_METER_PORT));
ret = ERR_FAIL;
goto err_uart;
}
if (iot_sunsolar_flash_init()) {
ret = ERR_FAIL;
goto err_flash_init;
}
p_gsunsolar->role
= PLC_SUPPORT_STA_ROLE ? IOT_PLC_DEV_ROLE_STA : IOT_PLC_DEV_ROLE_CCO;
switch (p_gsunsolar->role) {
case IOT_PLC_DEV_ROLE_STA:
ret = iot_sunsolar_sta_init();
break;
case IOT_PLC_DEV_ROLE_CCO:
ret = iot_sunsolar_cco_init();
break;
default:
IOT_ASSERT(0);
ret = ERR_INVAL;
break;
}
if (ret) {
goto err_role;
}
/* create task */
os_mem_set(&p_gsunsolar->task_cfg, 0, sizeof(p_gsunsolar->task_cfg));
p_gsunsolar->task_cfg.stack_size = IOT_SUNSOLAR_TASK_STACK_SIZE;
p_gsunsolar->task_cfg.task_prio = IOT_SUNSOLAR_TASK_PROTO_TASK_PRIO;
p_gsunsolar->task_cfg.msg_size = sizeof(sunsolar_msg_t);
p_gsunsolar->task_cfg.msg_cnt = IOT_SUNSOLAR_TASK_POOL_SIZE;
p_gsunsolar->task_cfg.queue_cnt = 1;
p_gsunsolar->task_cfg.queue_cfg[0].quota = 0;
p_gsunsolar->task_cfg.msg_exe_func = p_gsunsolar->msg_exe_func;
p_gsunsolar->task_cfg.msg_cancel_func = p_gsunsolar->msg_cancel_func;
p_gsunsolar->task_cfg.task_event_func = p_gsunsolar->event_exe_func;
p_gsunsolar->task = iot_task_create(IOT_SUNSOLAR_TASK_ID,
&p_gsunsolar->task_cfg);
if (NULL == p_gsunsolar->task) {
ret = ERR_NOMEM;
goto err_task;
}
/* register IPC for iot_sunsolar */
client.addr.f_id = IOT_IPC_FID_SG_EXT_SDK;
client.addr.c_id = IOT_IPC_CID_SG_EXT_CUS_APP;
client.recv = iot_sunsolar_ipc_recv;
client.param = NULL;
p_gsunsolar->ipc_h = iot_ipc_register_client(&client);
if (p_gsunsolar->ipc_h == NULL) {
ret = ERR_BUSY;
goto err_ipc;
}
/* register app to plc network */
p_gsunsolar->app_cfg.app_id = IOT_SUNSOLAR_APP_ID;
p_gsunsolar->app_cfg.param = p_gsunsolar;
p_gsunsolar->app_cfg.prio = 0;
p_gsunsolar->app_cfg.recv = iot_sunsolar_plc_callback;
p_gsunsolar->plc_app_h =
iot_plc_register_app(&p_gsunsolar->app_cfg);
if (p_gsunsolar->plc_app_h == NULL) {
ret = ERR_BUSY;
goto err_plc;
}
goto out;
err_plc:
iot_ipc_deregister_client(p_gsunsolar->ipc_h);
p_gsunsolar->ipc_h = NULL;
err_ipc:
iot_task_delete(p_gsunsolar->task);
p_gsunsolar->task = NULL;
err_task:
switch (p_gsunsolar->role) {
case IOT_PLC_DEV_ROLE_STA:
iot_sunsolar_sta_deinit();
break;
case IOT_PLC_DEV_ROLE_CCO:
iot_sunsolar_cco_deinit();
break;
default:
IOT_ASSERT(0);
break;
}
err_role:
iot_sunsolar_flash_deinit();
err_flash_init:
if (p_gsunsolar->uart_h != NULL) {
iot_uart_close(p_gsunsolar->uart_h);
p_gsunsolar->uart_h = NULL;
}
err_uart:
os_mem_free(p_gsunsolar);
p_gsunsolar = NULL;
out:
if (!ret) {
iot_sunsolar_printf("task create successfully.\n");
} else {
iot_sunsolar_printf("task init fail:%d.\n", ret);
}
return ret;
}
/**
* @brief app_sunsolar_task_entry() - the sunsolar app main entry.
* @return ERR_OK
*/
uint32_t app_sunsolar_task_entry(void)
{
uint32_t ret = ERR_PENDING;
if (ERR_OK == iot_sunsolar_task_init()) {
ret = ERR_OK;
}
return ret;
}
#endif /* end IOT_SUNSOLAR_APP_ENABLE */