443 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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 */
 |