/* * @Author : stark1898y 1658608470@qq.com * @Date : 2024-09-04 13:33:49 * @LastEditors: mbw && 1600520629@qq.com * @LastEditTime: 2025-02-13 08:55:43 * @FilePath: \JT-DT-YD4N02A_RTT_MRS-NT26K\bsp\src\at_device_nt26k.c * @Description : * * Copyright (c) 2024 by yzy, All Rights Reserved. */ /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-12-13 qiyongzhong first version */ // #include #include #include "bsp_flash.h" #include #include "bsp_nt26k.h" #include "user_sys.h" #include "bsp_rtc.h" #include "bsp_led.h" #include "bsp_rng.h" #define LOG_TAG "at.dev.nt26k" #include #include "pin.h" #if IOT_MODULE_SWITCH == 1 #define NT26K_POWER_OFF RT_FALSE #define NT26K_POWER_ON RT_TRUE #define NT26K_POWER_ON_TIME 3 #define NT26K_POWER_OFF_TIME 4 #define AT_CLIENT_RECV_BUFF_LEN 512 #define AT_DEFAULT_TIMEOUT 5000 #ifdef AT_DEVICE_USING_NT26K #define NT26K_WAIT_CONNECT_TIME 5000 #define NT26K_THREAD_STACK_SIZE 4096 #define NT26K_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 2) char data_buf[AT_CLIENT_RECV_BUFF_LEN] = {0}; nt26k_sys_info nt26k = {0}; struct rt_completion nt26k_init_complate; volatile int socket_id = 0; volatile rt_uint8_t ntp_flag = 0; // 将本地时间转换为对应时区时间 void Time_Zone_Conversion(TsRtcDateTime *timeInfo) { // 根据时区差异进行转换,这里时区差为8小时,没有分钟差异。 timeInfo->hour += RT_LIBC_DEFAULT_TIMEZONE; // 小时部分加8小时 if (timeInfo->hour >= 24) { // 如果超过24小时,则天数加1,小时数减24。 timeInfo->day++; timeInfo->hour -= 24; if (timeInfo->day > 365) { timeInfo->year += 1; } } } rt_err_t Nt26k_Reset(struct at_device *device) { LOG_I("NT26K Reset"); rt_pin_mode(NT26K_RST_PIN, PIN_MODE_OUTPUT); rt_pin_write(NT26K_RST_PIN, PIN_LOW); rt_thread_mdelay(10); rt_pin_write(NT26K_RST_PIN, PIN_HIGH); rt_thread_mdelay(50); rt_pin_write(NT26K_RST_PIN, PIN_LOW); return RT_EOK; } static int nt26k_power_on(struct at_device *device) { struct at_device_nt26k *nt26k = RT_NULL; nt26k = (struct at_device_nt26k *)device->user_data; rt_pin_write(nt26k->pwr_en_pin, PIN_LOW); rt_thread_mdelay(1000); rt_pin_write(nt26k->pwr_en_pin, PIN_HIGH); rt_thread_mdelay(1000); return 0; // return device->class->device_ops->control(device, AT_DEVICE_CTRL_WAKEUP, RT_NULL); } static rt_err_t nt26k_power_off(struct at_device *device) { struct at_device_nt26k *nt26k = RT_NULL; nt26k = (struct at_device_nt26k *)device->user_data; // device->class->device_ops->control(device, AT_DEVICE_RF_CLOSE, RT_NULL); rt_pin_write(nt26k->pwr_en_pin, PIN_LOW); return RT_EOK; } static rt_err_t nt26k_Close_Rf(struct at_device *device) { at_response_t resp = at_create_resp(64, 0, rt_tick_from_millisecond(60000)); if (resp == RT_NULL) { LOG_D("no memory for resp create."); at_delete_resp(resp); return (-RT_ERROR); } if (at_obj_exec_cmd(device->client, resp, "AT+QPOWD=1") == RT_EOK) { if (at_resp_get_line_by_kw(resp, "POWERED DOWN") != RT_NULL) { at_delete_resp(resp); return RT_EOK; } } at_delete_resp(resp); return (-RT_ERROR); } #ifdef TEST_ENABLE void TEST_Nt26k_Reset() { Nt26k_Reset(RT_NULL); } MSH_CMD_EXPORT(TEST_Nt26k_Reset, "test_nt26k_reset"); #endif static int nt26k_sleep(struct at_device *device) { at_response_t resp = RT_NULL; struct at_device_nt26k *nt26k = RT_NULL; nt26k = (struct at_device_nt26k *)device->user_data; if (!nt26k->power_status) // power off { return (RT_EOK); } if (nt26k->sleep_status) // is sleep status { return (RT_EOK); } resp = at_create_resp(64, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_D("no memory for resp create."); at_delete_resp(resp); return (-RT_ERROR); } /* enable sleep mode */ // Sleep1 if (at_obj_exec_cmd(device->client, resp, "AT+ECPMUCFG=1,2") != RT_EOK) { LOG_D("enable sleep fail.\"AT+ECPMUCFG=1,2\" execute fail."); at_delete_resp(resp); return (-RT_ERROR); } /* enable PSM mode */ if (at_obj_exec_cmd(device->client, resp, "AT+CPSMS=1,,,,\"00100010\"") != RT_EOK) { LOG_D("enable sleep fail.\"AT+CPSMS=1,,,,\"00100010\" execute fail."); at_delete_resp(resp); return (-RT_ERROR); } nt26k->sleep_status = RT_TRUE; at_delete_resp(resp); return (RT_EOK); } static int nt26k_wakeup(struct at_device *device) { struct at_device_nt26k *nt26k = RT_NULL; nt26k = (struct at_device_nt26k *)device->user_data; if (nt26k->pwr_key_pin != -1) { rt_pin_write(nt26k->pwr_key_pin, PIN_LOW); rt_thread_mdelay(100); rt_pin_write(nt26k->pwr_key_pin, PIN_HIGH); nt26k->sleep_status = RT_FALSE; } return (RT_EOK); } static void urc_tcp_recv(struct at_client *client, const char *data, rt_size_t size) { int len = 0; rt_uint16_t crc16 = 0; rt_uint16_t rec_crc16 = 0; char crc16_buf[6] = {0}; rt_uint8_t recv_byte_buf[AT_CLIENT_RECV_BUFF_LEN] = {0}; rt_memset(data_buf, 0, sizeof(data_buf)); if (sscanf(data, "+QIURC: \"recv\",%*d,%d,%s", &len, data_buf) == 2) { HexStrToBytes(data_buf, recv_byte_buf, len * 2); LOG_D("nt26k recv data: %s", data_buf); crc16 = crc1021(data_buf, len * 2 - 10); // 去掉帧尾三个字节和2个字节的校验值,字符长度为10 rt_strncpy(crc16_buf, data_buf + len * 2 - 10, 4); LOG_D("nt26k crc16: %04s", crc16_buf); rec_crc16 = strtol(crc16_buf, NULL, 16); if (crc16 != rec_crc16) // 看下数据接收的是否正确 { LOG_E("nt26k recv data error {crc16 [%x]!= rec_crc16[%x]}", crc16, rec_crc16); } else { /*比较数组的长度和结构体的长度是否一致,如果不一致则数据解析错误,如果一致复制数组值到结构体中*/ if (len == sizeof(struct Nt26kRecvData)) { rt_memset(nt26k_ops.recv, 0, sizeof(struct Nt26kRecvData)); // 清空结构体 rt_memcpy(nt26k_ops.recv, recv_byte_buf, sizeof(struct Nt26kRecvData)); nt26k_connect_sever_flag = 1; if ((nt26k_ops.recv->recv_data.event_type == INSTRUCTION_HEART_BEAT) || (nt26k_ops.recv->recv_data.event_type == EVENT_TYPE_POWER_ON)) // 加这个的原因就是如果有指令下发,会出现两个信号量,指令会执行两次,所以排除心跳包才释放信号量 { rt_sem_release(nt26k_recv_msg_sem); // 接收到的是心跳包 } else { rt_sem_release(nt26k_recv_sem); rt_sem_release(nt26k_recv_msg_sem); // 接收到的是响应包 } } else { LOG_E("nt26k recv data error {len [%d]!= sizeof(struct Nt26kRecvData)[%d]}", len, sizeof(struct Nt26kRecvData)); } } } rt_memset(recv_byte_buf, 0, sizeof(recv_byte_buf)); } static void urc_device_reset(struct at_client *client, const char *data, rt_size_t size) { LOG_D("device reset"); nt26k_conncet_tcp_flag = 0; } static void urc_tcp_disconnect(struct at_client *client, const char *data, rt_size_t size) { size_t id; if (sscanf(data, "+QIURC: \"closed\",%d", &id) == 1) { if (id == socket_id) { LOG_W("socket %d disconnect", id); nt26k_conncet_tcp_flag = 0; rt_sem_release(nt26k_disconnect_sem); } } } static const struct at_urc urc_table[] = { {"+QIURC: \"recv\"", "\r\n", urc_tcp_recv}, {"boot.rom", "\r\n", urc_device_reset}, // 这个是软件复位时, {"Lierda", "\r\n", urc_device_reset}, // 这个时硬件复位时回复 {"+QIURC: \"closed\"", "\r\n", urc_tcp_disconnect}, // tcp连接断开 }; void show_resp_info(at_response_t resp) { RT_ASSERT(resp); /* Print response line buffer */ const char *line_buffer = RT_NULL; for (rt_size_t line_num = 1; line_num <= resp->line_counts; line_num++) { if ((line_buffer = at_resp_get_line(resp, line_num)) != RT_NULL) LOG_I("line %d buffer : %s", line_num, line_buffer); else LOG_I("Parse line buffer error!"); } return; } int at_device_nt26k_disconnect_tcp(struct at_device *device) { #define NT26K_CLOSE_REP_TIME (5 * AT_DEFAULT_TIMEOUT) at_response_t resp = at_create_resp(AT_CLIENT_RECV_BUFF_LEN, 0, NT26K_CLOSE_REP_TIME); if (resp == RT_NULL) { LOG_E("No memory for response structure!"); at_delete_resp(resp); return -RT_ENOMEM; } if (at_obj_exec_cmd(device->client, resp, TCP_CLOSE_SOCKET, socket_id) != RT_EOK) { at_delete_resp(resp); return -RT_ERROR; } nt26k_conncet_tcp_flag = 0; at_delete_resp(resp); return RT_EOK; } static int at_device_nt26k_connect_tcp(struct at_device *device) { if (nt26k_conncet_tcp_flag) return RT_EOK; ASSERT(device); int err_code = 0; flash_sever_info upload_sever_info = {0}; at_response_t resp = at_create_resp(64, 4, AT_DEFAULT_TIMEOUT); if (resp == RT_NULL) { LOG_E("No memory for response structure!"); at_delete_resp(resp); return -RT_ENOMEM; } if (Flash_Get_Sever_Data(&upload_sever_info) != RT_EOK) { LOG_E("Get Sever Data Failed"); at_delete_resp(resp); return RT_ERROR; } if (at_obj_exec_cmd(device->client, resp, TCP_CONNECT_CMD, upload_sever_info.server_url, upload_sever_info.server_port) == RT_EOK) { if (at_resp_parse_line_args_by_kw(resp, "+QIOPEN:", "+QIOPEN:%d,%d", &socket_id, &err_code) > 0) { if (err_code == 0) { LOG_D("nt26k connect to tcp server success"); nt26k_conncet_tcp_flag = 1; at_delete_resp(resp); return RT_EOK; } else { LOG_E("nt26k connect to tcp server failed. error code: %d", err_code); if (err_code == 570) { nt26k_disconnect_pdp_flag = 1; } } } } at_delete_resp(resp); return RT_ERROR; } int at_send_data(struct at_device *device, const char *data, rt_size_t size) { rt_mutex_take(nt26k_mutex, RT_WAITING_FOREVER); #define NT26K_SEND_RESP_TIME (3000) const char *line_buffer = RT_NULL; at_response_t resp = at_create_resp(AT_CLIENT_RECV_BUFF_LEN, 2, NT26K_SEND_RESP_TIME); if (resp == RT_NULL) { LOG_E("no memory for nt26k device(%s) response structure.", device->name); at_delete_resp(resp); return -RT_ERROR; } if (at_obj_exec_cmd(device->client, resp, TCP_SEND_DATA, socket_id, data) == RT_EOK) { if ((line_buffer = at_resp_get_line(resp, 2)) != RT_NULL) { if (rt_strstr(line_buffer, "SEND OK") != RT_NULL) { LOG_D("send data success, socket_id: %d", socket_id); rt_mutex_release(nt26k_mutex); at_delete_resp(resp); return RT_EOK; } } } rt_mutex_release(nt26k_mutex); at_delete_resp(resp); return -RT_ERROR; } int nt26k_check_link_status(struct at_device *device) { at_response_t resp = RT_NULL; int result = -RT_ERROR; resp = at_create_resp(64, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_D("no memory for resp create."); at_delete_resp(resp); return (-RT_ERROR); } result = -RT_ERROR; if (at_obj_exec_cmd(device->client, resp, "AT+CEREG?") == RT_EOK) { int link_stat = 0; if (at_resp_parse_line_args_by_kw(resp, "+CEREG:", "+CEREG: %*d,%d", &link_stat) > 0) { if (link_stat == 1 || link_stat == 5) { result = RT_EOK; } } } at_delete_resp(resp); return (result); } /* ============================= nt26k network interface operations ============================= */ /* set nt26k network interface device status and address information */ int nt26k_netdev_set_info(struct netdev *netdev) { #define NT26K_INFO_RESP_SIZE 128 #define NT26K_INFO_RESP_TIMO rt_tick_from_millisecond(1000) int result = RT_EOK; at_response_t resp = RT_NULL; struct at_device *device = RT_NULL; RT_ASSERT(netdev); device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return -RT_ERROR; } /* set network interface device status */ netdev_low_level_set_status(netdev, RT_TRUE); netdev_low_level_set_link_status(netdev, RT_TRUE); netdev_low_level_set_dhcp_status(netdev, RT_TRUE); resp = at_create_resp(NT26K_INFO_RESP_SIZE, 0, NT26K_INFO_RESP_TIMO); if (resp == RT_NULL) { LOG_E("no memory for resp create."); at_delete_resp(resp); result = -RT_ENOMEM; goto __exit; } rt_thread_mdelay(IMEI_Delay()); device->class->device_ops->control(device, AT_DEVICE_CTRL_NET_CONN, RT_NULL); // 打开连接 __exit: if (resp) { at_delete_resp(resp); } return result; } /** * @brief check nt26k network interface device status * * @param netdev: nt26k network interface device */ static void nt26k_check_link_status_entry(void *parameter) { #define NT26K_LINK_DELAY_TIME (10 * 60 * RT_TICK_PER_SECOND) #define NT26K_LINK_STATUS_OK 1 int link_status; struct at_device *device = RT_NULL; struct netdev *netdev = (struct netdev *)parameter; device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return; } while (1) { link_status = nt26k_check_link_status(device); if (link_status < 0) { rt_thread_mdelay(NT26K_LINK_DELAY_TIME); continue; } /* check the network interface device link status */ if ((NT26K_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev)) { netdev_low_level_set_link_status(netdev, (NT26K_LINK_STATUS_OK == link_status)); } rt_thread_delay(NT26K_LINK_DELAY_TIME); } } int nt26k_netdev_check_link_status(struct netdev *netdev) { #define NT26K_LINK_THREAD_TICK 20 #define NT26K_LINK_THREAD_STACK_SIZE (1024 + 512) #define NT26K_LINK_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2) rt_thread_t tid; char tname[RT_NAME_MAX] = {0}; RT_ASSERT(netdev); rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name); /* create nt26k link status polling thread */ tid = rt_thread_create(tname, nt26k_check_link_status_entry, (void *)netdev, NT26K_LINK_THREAD_STACK_SIZE, NT26K_LINK_THREAD_PRIORITY, NT26K_LINK_THREAD_TICK); if (tid != RT_NULL) { rt_thread_startup(tid); } return RT_EOK; } static int nt26k_net_init(struct at_device *device); static int nt26k_netdev_set_up(struct netdev *netdev) { struct at_device *device = RT_NULL; device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); LOG_D("netdev->name:%s", netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return -RT_ERROR; } if (device->is_init == RT_FALSE) { nt26k_net_init(device); device->is_init = RT_TRUE; netdev_low_level_set_status(netdev, RT_TRUE); LOG_D("network interface device(%s) set up status.", netdev->name); } return RT_EOK; } static int nt26k_netdev_set_down(struct netdev *netdev) { struct at_device *device = RT_NULL; device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return -RT_ERROR; } if (device->is_init == RT_TRUE) { nt26k_power_off(device); device->is_init = RT_FALSE; netdev_low_level_set_status(netdev, RT_FALSE); LOG_D("network interface device(%s) set down status.", netdev->name); } return RT_EOK; } static int nt26k_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server) { #define NT26K_DNS_RESP_LEN 64 #define NT26K_DNS_RESP_TIMEO rt_tick_from_millisecond(300) int result = RT_EOK; at_response_t resp = RT_NULL; struct at_device *device = RT_NULL; RT_ASSERT(netdev); RT_ASSERT(dns_server); device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return -RT_ERROR; } resp = at_create_resp(NT26K_DNS_RESP_LEN, 0, NT26K_DNS_RESP_TIMEO); if (resp == RT_NULL) { LOG_D("no memory for resp create."); at_delete_resp(resp); result = -RT_ENOMEM; goto __exit; } /* send "AT+QIDNSCFG=[,]" commond to set dns servers */ if (at_obj_exec_cmd(device->client, resp, "AT+QIDNSCFG=%d,%s", dns_num, inet_ntoa(*dns_server)) != RT_EOK) { result = -RT_ERROR; goto __exit; } netdev_low_level_set_dns_server(netdev, dns_num, dns_server); __exit: if (resp) { at_delete_resp(resp); } return result; } #ifdef NETDEV_USING_PING static int nt26k_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp #if RT_VER_NUM >= 0x50100 , rt_bool_t is_bind #endif ) { #define NT26K_PING_RESP_SIZE 128 #define NT26K_PING_IP_SIZE 16 #define NT26K_PING_TIMEO (NT26K_CON_REP_TIME) rt_err_t result = RT_EOK; int response = -1, recv_data_len, ping_time, ttl; char ip_addr[NT26K_PING_IP_SIZE] = {0}; at_response_t resp = RT_NULL; struct at_device *device = RT_NULL; #if RT_VER_NUM >= 0x50100 RT_UNUSED(is_bind); #endif RT_ASSERT(netdev); RT_ASSERT(host); RT_ASSERT(ping_resp); device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name); if (device == RT_NULL) { LOG_E("get device(%s) failed.", netdev->name); return -RT_ERROR; } resp = at_create_resp(NT26K_PING_RESP_SIZE, 4, NT26K_PING_TIMEO); if (resp == RT_NULL) { LOG_E("no memory for resp create"); at_delete_resp(resp); return -RT_ENOMEM; } /* send "AT+QPING=""[,[][,]]" commond to send ping request */ if (at_obj_exec_cmd(device->client, resp, "AT+QPING=1,\"%s\",%d,1", host, timeout / RT_TICK_PER_SECOND) < 0) { result = -RT_ERROR; goto __exit; } at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d", &response); /* Received the ping response from the server */ if (response == 0) { if (at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d,\"%[^\"]\",%d,%d,%d", &response, ip_addr, &recv_data_len, &ping_time, &ttl) <= 0) { result = -RT_ERROR; goto __exit; } } /* prase response number */ switch (response) { case 0: inet_aton(ip_addr, &(ping_resp->ip_addr)); ping_resp->data_len = recv_data_len; ping_resp->ticks = ping_time; ping_resp->ttl = ttl; result = RT_EOK; break; case 569: result = -RT_ETIMEOUT; break; default: result = -RT_ERROR; break; } __exit: if (resp) { at_delete_resp(resp); } return result; } #endif /* NETDEV_USING_PING */ const struct netdev_ops nt26k_netdev_ops = { nt26k_netdev_set_up, nt26k_netdev_set_down, RT_NULL, nt26k_netdev_set_dns_server, RT_NULL, #ifdef NETDEV_USING_PING nt26k_netdev_ping, #endif RT_NULL, }; static struct netdev *nt26k_netdev_add(const char *netdev_name) { #define ETHERNET_MTU 1380 #define HWADDR_LEN 8 struct netdev *netdev = RT_NULL; netdev = netdev_get_by_name(netdev_name); if (netdev != RT_NULL) { return (netdev); } netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev)); if (netdev == RT_NULL) { LOG_E("no memory for netdev create."); return RT_NULL; } netdev->mtu = ETHERNET_MTU; netdev->ops = &nt26k_netdev_ops; netdev->hwaddr_len = HWADDR_LEN; #ifdef SAL_USING_AT extern int sal_at_netdev_set_pf_info(struct netdev * netdev); /* set the network interface socket/netdb operations */ sal_at_netdev_set_pf_info(netdev); #endif netdev_register(netdev, netdev_name, RT_NULL); return netdev; } /* ============================= nt26k device operations ============================= */ int Time_Calibration(struct at_device *device) { at_response_t resp = RT_NULL; RT_ASSERT(device); resp = at_create_resp(64, 2, rt_tick_from_millisecond(2000)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); at_delete_resp(resp); return RT_ERROR; } if (at_obj_exec_cmd(device->client, resp, "AT+CCLK?") == RT_EOK) { TsRtcDateTime rtc_dt; int year, mounth, days, hous, min, sec; /*+CCLK:24/11/12,06:08:19+32*/ if (at_resp_parse_line_args_by_kw(resp, "+CCLK:", "+CCLK: \"%d/%d/%d,%d:%d:%d+32\"", &year, &mounth, &days, &hous, &min, &sec) > 0) { if ((year != 0) && (year < 70))//如果获取失败,则不配置 例: +CCLK:00/01/01,00:00:12+08 { rtc_dt.year = (2000 + year); rtc_dt.month = mounth; rtc_dt.day = days; rtc_dt.hour = hous; // 此时为零区时间,需要转化为东八区 rtc_dt.minute = min; rtc_dt.second = sec; Time_Zone_Conversion(&rtc_dt); // 时区设置 rtc_dt.week = RTC_GetWeek(rtc_dt.year, rtc_dt.month, rtc_dt.day); RTC_SetTime(rtc_dt.year, rtc_dt.month, rtc_dt.day, rtc_dt.hour, rtc_dt.minute, rtc_dt.second); // 设置时间 LOG_I("RTC时间: %04d-%02d-%02d %02d:%02d:%02d \n", rtc_dt.year, rtc_dt.month, rtc_dt.day, rtc_dt.hour, rtc_dt.minute, rtc_dt.second); ntp_flag = 1; at_delete_resp(resp); } return RT_EOK; } else { ntp_flag = 0; } } else { ntp_flag = 0; } at_delete_resp(resp); return RT_ERROR; } /* initialize for nt26k */ static void nt26k_init_thread_entry(void *parameter) { #define INIT_RETRY 5 #define CPIN_RETRY 20 #define CSQ_RETRY 30 #define CEREG_RETRY 60 #define IPADDR_RETRY 10 int i; rt_err_t result = RT_EOK; at_response_t resp = RT_NULL; struct at_device *device = (struct at_device *)parameter; struct at_client *client = device->client; resp = at_create_resp(128, 0, rt_tick_from_millisecond(1000)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); at_delete_resp(resp); return; } LOG_D("start init %s device.", device->name); while (1) { /* power on the nt26k device */ device->class->device_ops->control(device, AT_DEVICE_CTRL_POWER_ON, RT_NULL); /* wait nt26k startup finish, send AT every 500ms, if recei ve OK, SYNC success*/ if (at_client_obj_wait_connect(client, RT_WAITING_FOREVER)) { result = -RT_ETIMEOUT; goto __exit; } /* disable echo */ if (at_obj_exec_cmd(device->client, resp, "ATE0") != RT_EOK) { result = -RT_ERROR; goto __exit; } /* get module version */ if (at_obj_exec_cmd(device->client, resp, "AT+CGMR") != RT_EOK) { result = -RT_ERROR; goto __exit; } for (i = 0; i < (int)resp->line_counts - 1; i++) { LOG_D("%s", at_resp_get_line(resp, i + 1)); } /*AT+QICFG="dataformat" 设置收发模式*/ if (at_obj_exec_cmd(device->client, resp, "AT+QICFG=\"dataformat\",%d,%d", AT_NSONMI_MODE_DEFAULT, AT_NSONMI_MODE_DEFAULT) != RT_EOK) { result = -RT_ERROR; goto __exit; } /*设置显示模式*/ if (at_obj_exec_cmd(device->client, resp, "AT+QICFG=\"viewmode\",1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /*设置保活信息*/ if (at_obj_exec_cmd(device->client, resp, "AT+QICFG=\"tcp/keepalive\",1,1000,100,10") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_obj_exec_cmd(device->client, resp, "AT+QICFG=\"passiveclosed\",1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /* check SIM card */ for (i = 0; i < CPIN_RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CPIN?") == RT_EOK) { if (at_resp_get_line_by_kw(resp, "+CPIN: READY") != RT_NULL) break; } rt_thread_mdelay(1000); } if (i == CPIN_RETRY) { LOG_E("%s device SIM card detection failed.", device->name); result = -RT_ERROR; goto __exit; } /* set etwork interface device hardware address(IMEI) */ if ((*(rt_uint16_t *)FLASH_IOT_IMEI_ADDR == 0xE339) || (*(rt_uint16_t *)FLASH_IOT_IMEI_ADDR == 0x39E3)) // 未写入 { #define NT26K_NETDEV_HWADDR_LEN 8 #define NT26K_IMEI_LEN 15 char imei[NT26K_IMEI_LEN] = {0}; /* send "AT+CGSN" commond to get device IMEI */ if (at_obj_exec_cmd(device->client, resp, "AT+CGSN") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw(resp, "86", "%s", imei) <= 0) { LOG_E("%s device prase \"AT+CGSN=1\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D("%s device IMEI number: %s", device->name, imei); rt_memcpy(nt26k.imei, imei, NT26K_IMEI_LEN); Flash_Sys_Cfg(kIotImeiId, nt26k.imei, NT26K_IMEI_LEN); } else { rt_memset((char *)nt26k.imei, 0, NT26K_IMEI_LEN); Get_IotImei((char *)&nt26k.imei[0], NT26K_IMEI_LEN); } rt_thread_mdelay(1); /* set network interface device hardware iccid */ if ((*(rt_uint16_t *)FLASH_IOT_ICCID_ADDR == 0xE339) || (*(rt_uint16_t *)FLASH_IOT_ICCID_ADDR == 0x39E3)) // 未写入 { #define NT26K_ICCID_LEN 20 char iccid[NT26K_ICCID_LEN] = {0}; /* send "AT+ECICCID" commond to get device iccid */ if (at_obj_exec_cmd(device->client, resp, "AT+QCCID") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw(resp, "+QCCID:", "+QCCID:%s", iccid) <= 0) { LOG_E("%s device prase \"AT+ECICCID\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D("%s device iccid number: %s", device->name, iccid); rt_memcpy(nt26k.iccid, iccid, NT26K_ICCID_LEN); Flash_Sys_Cfg(kIotIccidId, nt26k.iccid, NT26K_ICCID_LEN); } else { rt_memset((char *)nt26k.iccid, 0, NT26K_ICCID_LEN); Get_IotIccid((char *)&nt26k.iccid[0], NT26K_ICCID_LEN); } rt_thread_mdelay(100); /* set network interface device hardware imsi */ if ((*(rt_uint16_t *)FLASH_IOT_IMSI_ADDR == 0xE339) || (*(rt_uint16_t *)FLASH_IOT_IMSI_ADDR == 0x39E3)) // 未写入 { #define NT26K_IMSI_LEN 15 char imsi[NT26K_IMSI_LEN] = {0}; /* send "AT+CIMI" commond to get device imsi */ if (at_obj_exec_cmd(device->client, resp, "AT+CIMI") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw(resp, "46", "%s", imsi) <= 0) { LOG_E("%s device prase \"AT+CIMI\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D("%s device imsi number: %s", device->name, imsi); rt_memcpy(nt26k.imsi, imsi, NT26K_IMSI_LEN); Flash_Sys_Cfg(kIotImsiId, nt26k.imsi, NT26K_IMSI_LEN); } else { // 已经写入了,将其赋值给结构体 rt_memset((char *)nt26k.imsi, 0, NT26K_IMSI_LEN); Get_IotImei((char *)&nt26k.imsi[0], NT26K_IMSI_LEN); } /* check signal strength */ for (i = 0; i < CSQ_RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CSQ") == RT_EOK) { int signal_strength = 0, err_rate = 0; if (at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &signal_strength, &err_rate) > 0) { if ((signal_strength != 99) && (signal_strength != 0)) { LOG_D("%s device signal strength: %d, channel bit err_rate: %d", device->name, signal_strength, err_rate); nt26k.rssi = signal_strength; break; } } } rt_thread_mdelay(1000); } if (i == CSQ_RETRY) { LOG_E("%s device signal strength check failed", device->name); result = -RT_ERROR; goto __exit; } /* check the GPRS network is registered */ for (i = 0; i < CEREG_RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CEREG?") == RT_EOK) // 60s内注册CS业务 { int link_stat = 0; if (at_resp_parse_line_args_by_kw(resp, "+CEREG:", "+CEREG: %*d,%d", &link_stat) > 0) { if ((link_stat == 1) || (link_stat == 5)) { LOG_D("%s device GPRS is registered", device->name); break; } } } rt_thread_mdelay(1000); } if (i == CEREG_RETRY) { result = -RT_ERROR; goto __exit; } // for (i = 0; i < CEREG_RETRY; i++) // { // if (at_obj_exec_cmd (device->client, resp, "AT+QICSGP=1,1,\"cmnet\",\"\",\"\",1") == RT_EOK) // { // break; // } // rt_thread_mdelay (20000); // } // if (i == CEREG_RETRY) // { // result = -RT_ERROR; // goto __exit; // } for (i = 0; i < CEREG_RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CGACT=1,1") == RT_EOK) { LOG_D("pdp激活成功"); break; } else { // AT+CGACT=0,1 //去激活 PDP if (at_obj_exec_cmd(device->client, resp, "AT+CGACT=0,1") == RT_EOK) { LOG_D("pdp去激活成功"); } } rt_thread_mdelay(5000); } if (i == CEREG_RETRY) { result = -RT_ERROR; goto __exit; } // if (at_obj_exec_cmd(device->client, resp, "AT+CCLK?") == RT_EOK) // { // TsRtcDateTime rtc_dt; // int year, mounth, days, hous, min, sec; // /*+CCLK:24/11/12,06:08:19+32*/ // if (at_resp_parse_line_args_by_kw(resp, "+CCLK:", "+CCLK: \"%d/%d/%d,%d:%d:%d+32\"", &year, &mounth, &days, &hous, &min, &sec) > 0) // { // if ((year != 0) && (year < 70))//如果获取失败,则不配置 例: +CCLK:00/01/01,00:00:12+08 // { // rtc_dt.year = (2000 + year); // rtc_dt.month = mounth; // rtc_dt.day = days; // rtc_dt.hour = hous; // 此时为零区时间,需要转化为东八区 // rtc_dt.minute = min; // rtc_dt.second = sec; // Time_Zone_Conversion(&rtc_dt); // 时区设置 // rtc_dt.week = RTC_GetWeek(rtc_dt.year, rtc_dt.month, rtc_dt.day); // RTC_SetTime(rtc_dt.year, rtc_dt.month, rtc_dt.day, // rtc_dt.hour, rtc_dt.minute, rtc_dt.second); // 设置时间 // LOG_I("RTC时间: %04d-%02d-%02d %02d:%02d:%02d \n", // rtc_dt.year, rtc_dt.month, rtc_dt.day, rtc_dt.hour, rtc_dt.minute, rtc_dt.second); // // 网络时间同步标志 // ntp_flag = 1; // } // result = RT_EOK; // } // } Time_Calibration(device); /* initialize successfully */ result = RT_EOK; break; __exit: if (result != RT_EOK) { /* power off the nt26k device */ LOG_I("%s device initialize retry...", device->name); // nt26k_power_off(device); rt_thread_mdelay(1000); } } if (resp) { at_delete_resp(resp); } if (result == RT_EOK) { /* set network interface device status and address information */ nt26k_netdev_set_info(device->netdev); /* check and create link staus sync thread */ nt26k_netdev_check_link_status(device->netdev); LOG_I("%s device network initialize success.", device->name); rt_completion_done(&nt26k_init_complate); // 通知初始化完成 } else { LOG_E("%s device network initialize failed(%d).", device->name, result); } } /* nt26k device network initialize */ static int nt26k_net_init(struct at_device *device) { #ifdef AT_DEVICE_NT26K_INIT_ASYN rt_thread_t tid; /* 初始化完成量对象 */ rt_completion_init(&nt26k_init_complate); tid = rt_thread_create("nt26k_net", nt26k_init_thread_entry, (void *)device, NT26K_THREAD_STACK_SIZE, NT26K_THREAD_PRIORITY, 20); if (tid) { rt_thread_startup(tid); } else { LOG_E("create %s device init thread failed.", device->name); return -RT_ERROR; } #else nt26k_init_thread_entry(device); #endif /* AT_DEVICE_NT26K_INIT_ASYN */ return RT_EOK; } // 去除字符串中的 \r 和 \n void remove_crlf(char *str) { char *p = str; while (*p) { if (*p == '\r' || *p == '\n') { memmove(p, p + 1, strlen(p)); } else { p++; } } } rt_err_t Nt26k_Get_Signal_Info(struct at_device *device) { #define RETRY 10 rt_err_t result = RT_EOK; at_response_t resp = RT_NULL; rt_uint8_t i; RT_ASSERT(device); resp = at_create_resp(1024, 4, rt_tick_from_millisecond(2000)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); at_delete_resp(resp); return RT_ERROR; } /* check signal strength */ for (i = 0; i < RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CSQ") == RT_EOK) { int signal_strength = 0, err_rate = 0; if (at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &signal_strength, &err_rate) > 0) { if ((signal_strength != 99) && (signal_strength != 0)) { LOG_D("%s device signal strength: %d, channel bit err_rate: %d", device->name, signal_strength, err_rate); nt26k.rssi = signal_strength; break; } } } rt_thread_mdelay(1000); } if (i == RETRY) { LOG_E("%s device signal strength check failed", device->name); result = -RT_ERROR; at_delete_resp(resp); return result; } /* check signal strength */ //+CESQ:99,99,255,255,28,44 for (i = 0; i < RETRY; i++) { if (at_obj_exec_cmd(device->client, resp, "AT+CESQ") == RT_EOK) { rt_uint8_t rsrp = 0, rsrq = 0; if (at_resp_parse_line_args_by_kw(resp, "+CESQ:", "+CESQ:%*[^,],%*[^,],%*[^,],%*[^,],%d,%d", &rsrq, &rsrp) > 0) { if ((rsrp <= 97) && (rsrp > 0) && ((rsrq <= 34) && (rsrq > 0))) { LOG_D("%s device signal rsrp: %d, rsrq: %d", device->name, rsrp, rsrq); nt26k.rsrp = rsrp; nt26k.rsrq = rsrq; break; } } } rt_thread_mdelay(1000); } if (i == RETRY) { LOG_E("%s device signal data failed", device->name); result = -RT_ERROR; } // /* get signal snr, pci */ // for (int i = 0; i < RETRY; i++) // { // if (at_obj_exec_cmd(device->client, resp, "AT+NUESTATS") == RT_EOK) // { // const char *key1 = "SNR:"; // const char *key2 = "PCI:"; // int pci = 0, snr = 0; // // show_resp_info(resp); // // 获取第 2 行的响应 // const char *line = at_resp_get_line(resp, 2); // if (line != NULL) // { // snr = Extract_Value(line, key1); // pci = Extract_Value(line, key2); // if (snr != 0 && pci != 0) // { // nt26k.pci = pci; // nt26k.snr = snr; // LOG_D("pci:%d,snr:%d", nt26k.pci, nt26k.snr); // break; // } // else // { // LOG_D("Extracted values are invalid: SNR=%d, PCI=%d", snr, pci); // } // } // else // { // LOG_D("Failed to get line 2 from response"); // } // } // else // { // LOG_D("Failed to execute AT command"); // } // rt_thread_mdelay(2000); // } // if (i == RETRY) // { // LOG_E("%s device signal data failed", device->name); // result = -RT_ERROR; // } at_delete_resp(resp); return result; } /* nt26k device network interface attach * - set network interface device link status */ static int nt26k_init(struct at_device *device) { struct at_device_nt26k *nt26k = RT_NULL; RT_ASSERT(device); nt26k = (struct at_device_nt26k *)device->user_data; nt26k->power_status = RT_FALSE; // default power is off. nt26k->sleep_status = RT_FALSE; // default sleep is disabled. /* initialize AT client */ #if RT_VER_NUM >= 0x50100 at_client_init(nt26k->client_name, nt26k->recv_line_num, nt26k->recv_line_num); #else at_client_init(nt26k->client_name, nt26k->recv_line_num); #endif device->client = at_client_get(nt26k->client_name); if (device->client == RT_NULL) { LOG_E("get AT client(%s) failed.", nt26k->client_name); return -RT_ERROR; } /* register URC data execution function */ at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0])); #ifdef AT_USING_SOCKET nt26k_socket_init(device); #endif /* add nt26k device to the netdev list */ device->netdev = nt26k_netdev_add(nt26k->device_name); if (device->netdev == RT_NULL) { LOG_E("add netdev(%s) failed.", nt26k->device_name); return -RT_ERROR; } /* initialize nt26k pin configuration */ if (nt26k->pwr_en_pin != -1) { rt_pin_mode(nt26k->pwr_en_pin, PIN_MODE_OUTPUT); } if (nt26k->rst_pin != -1) { rt_pin_mode(nt26k->rst_pin, PIN_MODE_OUTPUT); } if (nt26k->pwr_key_pin != -1) { rt_pin_mode(nt26k->pwr_key_pin, PIN_MODE_OUTPUT); device->class->device_ops->control(device, AT_DEVICE_CTRL_WAKEUP, RT_NULL); } /* initialize nt26k device network */ return nt26k_netdev_set_up(device->netdev); } static int nt26k_deinit(struct at_device *device) { RT_ASSERT(device); return nt26k_netdev_set_down(device->netdev); } static int nt26k_control(struct at_device *device, int cmd, void *arg) { int result = -RT_ERROR; RT_ASSERT(device); switch (cmd) { case AT_DEVICE_CTRL_SLEEP: result = nt26k_sleep(device); break; case AT_DEVICE_CTRL_WAKEUP: result = nt26k_wakeup(device); break; case AT_DEVICE_CTRL_NET_CONN: result = at_device_nt26k_connect_tcp(device); break; case AT_DEVICE_CTRL_NET_DISCONN: result = at_device_nt26k_disconnect_tcp(device); // 直接删除Socket break; case AT_DEVICE_CTRL_GET_SIGNAL: result = Nt26k_Get_Signal_Info(device); break; case AT_DEVICE_CTRL_RESET: result = Nt26k_Reset(device); break; case AT_DEVICE_CTRL_POWER_ON: result = nt26k_power_on(device); break; case AT_DEVICE_CTRL_POWER_OFF: result = nt26k_power_off(device); break; case AT_DEVICE_RF_CLOSE: result = nt26k_Close_Rf(device); break; case AT_DEVICE_CTRL_LOW_POWER: case AT_DEVICE_CTRL_SET_WIFI_INFO: case AT_DEVICE_CTRL_GET_GPS: case AT_DEVICE_CTRL_GET_VER: LOG_W("not support the control command(%d).", cmd); break; default: LOG_E("input error control command(%d).", cmd); break; } return result; } const struct at_device_ops nt26k_device_ops = { nt26k_init, nt26k_deinit, nt26k_control, }; static int nt26k_device_class_register(void) { struct at_device_class *class = RT_NULL; class = (struct at_device_class *)rt_calloc(1, sizeof(struct at_device_class)); if (class == RT_NULL) { LOG_E("no memory for device class create."); rt_free(class); return -RT_ENOMEM; } class->device_ops = &nt26k_device_ops; return at_device_class_register(class, AT_DEVICE_CLASS_NT26K); } INIT_DEVICE_EXPORT(nt26k_device_class_register); #endif //! IOT_MODULE_SWITCH #endif /* AT_DEVICE_USING_NT26K */