/* * @Author: mbw * @Date: 2024-11-30 15:46:21 * @LastEditors: mbw && 1600520629@qq.com * @LastEditTime: 2025-06-21 10:37:54 * @FilePath: \ble_bjq_ch303rct6_ml307\bsp\src\at_device_ml307.c * @Description: * * Copyright (c) 2025 by ${git_name_email}, 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_ml307.h" #include "user_sys.h" #include "bsp_rtc.h" #include "bsp_led.h" #define LOG_TAG "at.dev.ml307" #include #include "pin.h" #if IOT_MODULE_SWITCH == 1 #define ML307_POWER_OFF RT_FALSE #define ML307_POWER_ON RT_TRUE #define ML307_POWER_ON_TIME 3 #define ML307_POWER_OFF_TIME 4 #define AT_CLIENT_RECV_BUFF_LEN 512 #define AT_DEFAULT_TIMEOUT 1000 #ifdef AT_DEVICE_USING_ML307 #define ML307_WAIT_CONNECT_TIME 5000 #define ML307_THREAD_STACK_SIZE (4096) #define ML307_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 2) ml307_sys_info ml307 = {0}; struct rt_completion ml307_init_complate; volatile int socket_id = 0; volatile rt_uint8_t ntp_flag = 0; rt_sem_t ml307_connect_flag_sem; // 将本地时间转换为对应时区时间 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_bool_t ml307_get_power_state (struct at_device *device) { struct at_device_ml307 *ml307 = RT_NULL; ml307 = (struct at_device_ml307 *)device->user_data; return (!rt_pin_read (ml307->power_status_pin)) ? ML307_POWER_ON : ML307_POWER_OFF; } static rt_err_t ml307_power_on (struct at_device *device) { struct at_device_ml307 *ml307 = RT_NULL; ml307 = (struct at_device_ml307 *)device->user_data; /* not nead to set pin configuration for ml307 device power on */ rt_pin_write (ml307->pwr_en_pin, PIN_LOW); rt_pin_write (ml307->pwr_en_pin, PIN_HIGH); rt_thread_mdelay (RT_TICK_PER_SECOND); rt_pin_write (ml307->power_pin, PIN_HIGH); rt_thread_mdelay (ML307_POWER_ON_TIME * RT_TICK_PER_SECOND); rt_pin_write (ml307->power_pin, PIN_LOW); return RT_EOK; } static rt_err_t ml307_power_off (struct at_device *device) { struct at_device_ml307 *ml307 = RT_NULL; ml307 = (struct at_device_ml307 *)device->user_data; rt_pin_write (ml307->power_pin, PIN_HIGH); rt_thread_mdelay (ML307_POWER_OFF_TIME * RT_TICK_PER_SECOND); rt_pin_write (ml307->power_pin, PIN_LOW); rt_thread_mdelay (100); LOG_D ("ml307 power off"); return RT_EOK; } rt_err_t Ml307_Reset (struct at_device *device) { // rt_pin_write(ML307_RST_PIN, PIN_HIGH); // rt_thread_mdelay(500); // rt_pin_write(ML307_RST_PIN, PIN_LOW); // rt_sem_release(ml307_disconnect_sem); at_client_send ("AT+MREBOOT\r\n", rt_strlen ("AT+MREBOOT\r\n")); return RT_EOK; } #ifdef TEST_ENABLE void TEST_Ml307_Reset (void) { Ml307_Reset (RT_NULL); } MSH_CMD_EXPORT (TEST_Ml307_Reset, "test_ml307_reset"); #endif static void urc_tcp_recv (struct at_client *client, const char *data, rt_size_t size) { int id; int len = 0; rt_uint16_t crc16 = 0; rt_uint16_t rec_crc16 = 0; char crc16_buf[6] = {0}; char data_buf[AT_CLIENT_RECV_BUFF_LEN] = {0}; #ifdef TEST_ENABLE RTC_ShowTime(); // 每次接收打印下时间,容易定位问题 #endif rt_uint8_t recv_byte_buf[AT_CLIENT_RECV_BUFF_LEN] = {0}; rt_memset (data_buf, 0, sizeof (data_buf)); /*+MIPURC: "rtcp",,,*/ if (sscanf (data, "+MIPURC: \"rtcp\",%d,%d,%s\r\n", &id, &len, data_buf) == 3) { HexStrToBytes (data_buf, recv_byte_buf, len * 2); LOG_D ("ml307 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 ("ml307 crc16: %04s", crc16_buf); rec_crc16 = strtol (crc16_buf, NULL, 16); if (crc16 != rec_crc16) // 看下数据接收的是否正确 { LOG_E ("ml307 recv data error {crc16 [%x]!= rec_crc16[%x]}", crc16, rec_crc16); } else { /*比较数组的长度和结构体的长度是否一致,如果不一致则数据解析错误,如果一致复制数组值到结构体中*/ if (len == sizeof (struct Ml307RecvData)) { rt_memset (ml307_ops.recv, 0, sizeof (struct Ml307RecvData)); // 清空结构体 rt_memcpy (ml307_ops.recv, recv_byte_buf, sizeof (struct Ml307RecvData)); ml307_connect_sever_flag = 1; rt_sem_release (ml307_recv_sem); } else { LOG_E ("ml307 recv data error {len [%d]!= sizeof(struct Ml307RecvData)[%d]}", len, sizeof (struct Ml307RecvData)); } } } } static void urc_device_reset (struct at_client *client, const char *data, rt_size_t size) { LOG_D ("device reset"); // ml307_conncet_tcp_flag = 0; } static void urc_tcp_connect_state (struct at_client *client, const char *data, rt_size_t size) { size_t err_code = 0, id; if (sscanf (data, "+MIPOPEN:%d,%d", &id, &err_code) == 2) { { switch (err_code) { case 0: ml307_conncet_tcp_flag = 1; rt_sem_release (ml307_connect_flag_sem); break; case 571: LOG_D ("PDP激活失败"); ml307_conncet_tcp_flag = 0; ml307_disconnect_pdp_flag = 1; rt_sem_release (ml307_disconnect_sem); break; default: LOG_D ("连接失败"); ml307_conncet_tcp_flag = 0; rt_sem_release (ml307_disconnect_sem); break; } // 用于返回连接的标志量在连接函数中 } } else { LOG_E ("ml307 tcp connect error, [%d]", __LINE__); } } static void urc_tcp_disconnect (struct at_client *client, const char *data, rt_size_t size) { size_t state = 0, id; LOG_D ("ml307 disconnect to tcp server"); if (sscanf (data, "+MIPURC: \"disconn\",%d,%d", &id, &state) == 2) { socket_id = id; if (id == socket_id) { ml307_conncet_tcp_flag = 0; switch (state) { case 1: LOG_D ("服务器断开连接"); rt_sem_release (ml307_disconnect_sem); break; case 2: // 连接异常 LOG_D ("连接异常"); rt_sem_release (ml307_disconnect_sem); break; case 3: // PDP去激活 LOG_D ("ml307 tcp server PDP deactivate"); rt_sem_release (ml307_disconnect_sem); break; default: break; } } } } void urc_sim_remove (struct at_client *client, const char *data, rt_size_t size) { LOG_D ("SIM removed"); ml307_conncet_tcp_flag = 0; } static const struct at_urc urc_table[] = { {"REBOOTING", "\r\n", urc_device_reset }, // 这个是软件复位时, {"+MIPOPEN:", "\r\n", urc_tcp_connect_state}, {"+MIPURC: \"disconn\"", "\r\n", urc_tcp_disconnect }, {"+MIPURC: \"rtcp\"", "\r\n", urc_tcp_recv }, // {"+MATREADY", "\r\n", urc_device_reset}, // {"+CPIN: SIM REMOVED", "\r\n", urc_sim_remove}, }; 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_ml307_disconnect_tcp (struct at_device *device) { #define ML307_CLOSE_REP_TIME (5 * AT_DEFAULT_TIMEOUT) at_response_t resp = at_create_resp (AT_CLIENT_RECV_BUFF_LEN, 0, ML307_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; } ml307_conncet_tcp_flag = 0; at_delete_resp (resp); return RT_EOK; } static int at_device_ml307_connect_tcp (struct at_device *device) { if (ml307_conncet_tcp_flag) return RT_EOK; flash_sever_info sever_info = {0}; rt_err_t ret = RT_ERROR; ASSERT (device); at_response_t resp = at_create_resp (256, 2, 10000); if (resp == RT_NULL) { LOG_E ("No memory for response structure!"); at_delete_resp (resp); return -RT_ENOMEM; } if (Flash_Get_Sever_Data (&sever_info) != RT_EOK) { LOG_E ("Get Sever Data Failed"); at_delete_resp (resp); return RT_ERROR; } LOG_D ("sever_info.server_url:%s sever_info.server_port:%s", sever_info.server_url, sever_info.server_port); if (at_obj_exec_cmd (device->client, resp, TCP_CONNECT_CMD, socket_id, (char *)sever_info.server_url, (char *)sever_info.server_port) == RT_EOK) { if (at_resp_get_line_by_kw (resp, "OK") != RT_NULL) { rt_thread_mdelay (1000); if (rt_sem_take (ml307_connect_flag_sem, 8000) == RT_EOK) { if (ml307_conncet_tcp_flag) { LOG_D ("ml307 connect to tcp server success"); at_delete_resp (resp); return RT_EOK; } else { LOG_E ("ml307 connect to tcp server fail"); } } } else if (at_resp_get_line_by_kw (resp, "+CME ERROR: 552") == RT_EOK) // 已经连接了 { ret = RT_EOK; } } at_delete_resp (resp); return ret; } int at_send_data (struct at_device *device, const char *data, rt_size_t send_len) { size_t len = 0, error_code; #define ML307_SEND_RESP_TIME (5000) at_response_t resp = at_create_resp (AT_CLIENT_RECV_BUFF_LEN, 0, ML307_SEND_RESP_TIME); if (resp == RT_NULL) { LOG_E ("no memory for ml307 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, send_len, data) == RT_EOK) { if (at_resp_parse_line_args_by_kw (resp, "+MIPSEND:", "+MIPSEND:%*d,%d", &len) > 0) { if (len == send_len) { LOG_D ("send data success, len:%d", len); at_delete_resp (resp); return RT_EOK; } } else if (at_resp_parse_line_args_by_kw (resp, "+CME ERROR:", "+CME ERROR: %d", &error_code) > 0) { ml307_conncet_tcp_flag = 0; LOG_E ("send data fail error_code: %d", error_code); at_delete_resp (resp); return -RT_ERROR; } } else if (at_resp_parse_line_args_by_kw (resp, "+CME ERROR:", "+CME ERROR: %d", &error_code) > 0) { ml307_conncet_tcp_flag = 0; LOG_E ("send data fail error_code: %d", error_code); } at_delete_resp (resp); return -RT_ERROR; } static int ml307_check_link_status(struct at_device *device) { at_response_t resp = RT_NULL; // struct at_device_ml307 *ml307 = RT_NULL; int result = -RT_ERROR; int link_stat = 0; RT_ASSERT(device); // ml307 = (struct at_device_ml307 *)device->user_data; resp = at_create_resp(96, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); return -RT_ERROR; } if(at_obj_exec_cmd(device->client, resp, "AT+MIPCALL?") < 0) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw(resp, "+MIPCALL:", "+MIPCALL: %d,%*d,%*s", &link_stat) > 0) { if (link_stat == 1) { result = RT_EOK; } } if(at_obj_exec_cmd(device->client, resp, "AT+CGACT?") < 0) { result = -RT_ERROR; goto __exit; } //+CGACT: 1,1 if (at_resp_parse_line_args_by_kw(resp, "+CGACT:", "+CGACT: %d,%*d", &link_stat) > 0) { result = link_stat; } __exit: if(resp) { at_delete_resp(resp); } return(result); } /* ============================= ml307 network interface operations ============================= */ /* set ml307 network interface device status and address information */ static int ml307_netdev_set_info (struct netdev *netdev) { #define ML307_IMEI_RESP_SIZE 32 #define ML307_IPADDR_RESP_SIZE 64 #define ML307_DNS_RESP_SIZE 96 #define ML307_INFO_RESP_TIMO rt_tick_from_millisecond (2000) #define ML307_CONNECT_TIME rt_tick_from_millisecond (2000) int result = RT_EOK; ip_addr_t addr; 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 (ML307_IMEI_RESP_SIZE, 0, ML307_INFO_RESP_TIMO); if (resp == RT_NULL) { LOG_E ("no memory for resp create."); result = -RT_ENOMEM; goto __exit; } device->class->device_ops->control (device, AT_DEVICE_CTRL_NET_CONN, RT_NULL); // 打开连接 /* set network interface device IP address */ { #define IP_ADDR_SIZE_MAX 16 char ipaddr[IP_ADDR_SIZE_MAX] = {0}; at_resp_set_info (resp, ML307_IPADDR_RESP_SIZE * 2, 2, ML307_INFO_RESP_TIMO); /* send "AT+CIFSR" commond to get IP address */ if (at_obj_exec_cmd (device->client, resp, "AT+CGPADDR=1") < 0) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw (resp, "+CGPADDR:", "+CGPADDR: %*d,\"%[^\"]", ipaddr) <= 0) { LOG_E ("ml307 device(%s) prase \"AT+CGPADDR=1\" commands resposne data error!", device->name); result = -RT_ERROR; goto __exit; } LOG_D ("ml307 device(%s) IP address: %s", device->name, ipaddr); /* set network interface address information */ inet_aton (ipaddr, &addr); netdev_low_level_set_ipaddr (netdev, &addr); } __exit: if (resp) { at_delete_resp (resp); } return result; } /** * @brief check ml307 network interface device status * * @param netdev: ml307 network interface device */ static void ml307_check_link_status_entry(void *parameter) { #define ML307_LINK_STATUS_OK 1 #define ML307_LINK_RESP_SIZE 128 #define ML307_LINK_RESP_TIMO (3 * RT_TICK_PER_SECOND) #define ML307_LINK_DELAY_TIME (3000 * RT_TICK_PER_SECOND) at_response_t resp = RT_NULL; 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; } resp = at_create_resp(ML307_LINK_RESP_SIZE, 0, ML307_LINK_RESP_TIMO); if (resp == RT_NULL) { LOG_E("no memory for response create."); return; } while(1) { link_status = ml307_check_link_status(device);//固定时间检查连接状态 if(link_status < 0) { rt_thread_mdelay(ML307_LINK_DELAY_TIME); continue; } /* check the network interface device link status */ if ((ML307_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev)) { netdev_low_level_set_link_status(netdev, (ML307_LINK_STATUS_OK == link_status)); } rt_thread_mdelay(ML307_LINK_DELAY_TIME); } } int ml307_netdev_check_link_status (struct netdev *netdev) { #define ML307_LINK_THREAD_TICK 20 #define ML307_LINK_THREAD_STACK_SIZE (2048) #define ML307_LINK_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2) rt_thread_t tid; char tname[RT_NAME_MAX] = {0}; if (netdev == RT_NULL) { return -RT_ERROR; } // RT_ASSERT(netdev); rt_snprintf (tname, RT_NAME_MAX, "%s", netdev->name); /* create ml307 link status polling thread */ tid = rt_thread_create (tname, ml307_check_link_status_entry, (void *)netdev, ML307_LINK_THREAD_STACK_SIZE, ML307_LINK_THREAD_PRIORITY, ML307_LINK_THREAD_TICK); if (tid != RT_NULL) { rt_thread_startup (tid); } return RT_EOK; } static int ml307_net_init (struct at_device *device); static int ml307_netdev_set_up (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_FALSE) { ml307_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 ml307_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) { ml307_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 ml307_netdev_set_dns_server (struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server) { #define ML307_DNS_RESP_LEN 8 #define ML307_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 ml307 device by netdev name(%s) failed.", netdev->name); return -RT_ERROR; } resp = at_create_resp (ML307_DNS_RESP_LEN, 0, ML307_DNS_RESP_TIMEO); if (resp == RT_NULL) { LOG_D ("ml307 set dns server failed, no memory for response object."); result = -RT_ENOMEM; goto __exit; } /* send "AT+CDNSCFG=[,]" commond to set dns servers */ if (at_obj_exec_cmd (device->client, resp, "AT+MDNSCFG=\"%s\"", inet_ntoa (*dns_server)) < 0) { 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 ml307_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 ML307_PING_RESP_SIZE 128 #define ML307_PING_IP_SIZE 16 #define ML307_PING_TIMEO (ML307_CON_REP_TIME) rt_err_t result = RT_EOK; int response = -1, recv_data_len, ping_time, ttl; char ip_addr[ML307_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 (ML307_PING_RESP_SIZE, 4, ML307_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 ml307_netdev_ops = { ml307_netdev_set_up, ml307_netdev_set_down, RT_NULL, ml307_netdev_set_dns_server, RT_NULL, #ifdef NETDEV_USING_PING ml307_netdev_ping, #endif RT_NULL, }; // 增加网卡设备 static struct netdev *ml307_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 = &ml307_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; } 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; } /* ============================= ml307 device operations ============================= */ #define AT_SEND_CMD(client, resp, resp_line, timeout, cmd) \ do { \ (resp) = at_resp_set_info ((resp), 128, (resp_line), rt_tick_from_millisecond (timeout)); \ if (at_obj_exec_cmd ((client), (resp), (cmd)) < 0) \ { \ result = -RT_ERROR; \ goto __exit; \ } \ } while (0) /* initialize for ml307 */ static void ml307_init_thread_entry (void *parameter) { #define INIT_RETRY 5 #define CPIN_RETRY 5 #define CSQ_RETRY 20 #define CEREG_RETRY 50 #define IPADDR_RETRY 10 #define COMMON_RETRY 10 #define CGATT_RETRY 10 #define ML307_AT_DEFAULT_TIMEOUT 5000 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 (256, 0, rt_tick_from_millisecond (ML307_AT_DEFAULT_TIMEOUT * 2)); if (resp == RT_NULL) { LOG_E ("no memory for resp create."); at_delete_resp (resp); return; } LOG_D ("start init %s device.", device->name); ml307_power_off (device); while (1) { /* power on the ml307 device */ // rt_thread_mdelay(1000); ml307_power_on (device); LOG_D ("power on %s device.", device->name); // rt_thread_mdelay(2000); /* wait ml307 startup finish, send AT every 500ms, if receive OK, SYNC success*/ if (at_client_obj_wait_connect (client, ML307_WAIT_CONNECT_TIME)) { result = -RT_ETIMEOUT; goto __exit; } if (at_obj_exec_cmd(device->client, resp, "AT+MCFG=\"simhot\",0") != RT_EOK) { result = -RT_ERROR; goto __exit; } /* disable echo */ AT_SEND_CMD (client, resp, 0, ML307_AT_DEFAULT_TIMEOUT, "ATE0"); /* get module version */ if (at_obj_exec_cmd (device->client, resp, "ATI") != 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)); } /*disable sleep mode */ if (at_obj_exec_cmd (device->client, resp, "AT+MLPMCFG=\"sleepmode\",0,1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /*设置包模式*/ if (at_obj_exec_cmd (device->client, resp, "AT+MIPCFG=\"encoding\",0,1,1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /*设置包模式*/ if (at_obj_exec_cmd (device->client, resp, "AT+MIPCFG=\"autofree\",0,1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /*设置心跳包*/ if (at_obj_exec_cmd (device->client, resp, "AT+MIPTKA=0,1,60,30,3") != RT_EOK) { result = -RT_ERROR; goto __exit; } /* Define PDP Context */ for (i = 0; i < COMMON_RETRY; i++) { if (at_obj_exec_cmd (client, resp, "AT+CGDCONT=1,\"IPV4V6\",\"cmnet\"") == RT_EOK) { LOG_D ("%s device Define PDP Context Success.", device->name); break; } rt_thread_mdelay (100); } if (i == COMMON_RETRY) { LOG_E ("%s device Define PDP Context failed.", device->name); result = -RT_ERROR; goto __exit; } // LOG_D("*(rt_uint16_t *)FLASH_IOT_IMEI_ADDR = %#X", *(rt_uint16_t *)FLASH_IOT_IMEI_ADDR); if ((*(rt_uint16_t *)FLASH_IOT_IMEI_ADDR == 0xE339) || (*(uint16_t *)FLASH_IOT_IMEI_ADDR == 0x39E3)) { #define ML307_NETDEV_HWADDR_LEN 8 #define ML307_IMEI_LEN 15 char imei[ML307_IMEI_LEN] = {0}; /* send "AT+GSN" commond to get device IMEI */ if (at_obj_exec_cmd (device->client, resp, "AT+GSN=1") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw (resp, "+GSN:", "+GSN:%s", imei) <= 0) { LOG_E ("%s device prase \"AT+GSN=1\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D ("%s device IMEI number: %s", device->name, imei); rt_memcpy (ml307.imei, imei, ML307_IMEI_LEN); Flash_Sys_Cfg (kIotImeiId, ml307.imei, ML307_IMEI_LEN); } else { rt_memset ((char *)ml307.imei, 0, ML307_IMEI_LEN); Get_IotImei ((char *)&ml307.imei[0], ML307_IMEI_LEN); } /* check SIM card */ for (i = 0; i < CPIN_RETRY; i++) { if (at_obj_exec_cmd (device->client, resp, "AT+CPIN?") == RT_EOK) { char code[8] = {0}; if (at_resp_parse_line_args_by_kw (resp, "+CPIN:", "+CPIN: %s", code) > 0) { if (rt_strcmp (code, "READY") == 0) { LOG_D ("%s device SIM card detection success.", device->name); break; } else { LOG_E ("%s device SIM card detection failed.", device->name); result = -RT_ERROR; goto __exit; } } } rt_thread_mdelay (3000); } if (i == CPIN_RETRY) { LOG_E ("%s device SIM card detection failed.", device->name); result = -RT_ERROR; goto __exit; } if (at_obj_exec_cmd (device->client, resp, "AT+CGATT=1") != RT_EOK) { result = -RT_ERROR; goto __exit; } char parsed_data[10] = {0}; for (i = 0; i < CGATT_RETRY; i++) { AT_SEND_CMD (client, resp, 0, ML307_AT_DEFAULT_TIMEOUT, "AT+CGATT?"); at_resp_parse_line_args_by_kw (resp, "+CGATT:", "+CGATT: %s", &parsed_data); if (!rt_strncmp (parsed_data, "1", 1)) { LOG_D ("%s device Packet domain attach.", device->name); break; } rt_thread_mdelay (1000); } /* set network interface device hardware iccid */ // LOG_D("*(rt_uint16_t *)FLASH_IOT_ICCID_ADDR = %#X", *(rt_uint16_t *)FLASH_IOT_ICCID_ADDR); if ((*(rt_uint16_t *)FLASH_IOT_ICCID_ADDR == 0xE339) || (*(uint16_t *)FLASH_IOT_ICCID_ADDR == 0x39E3)) { #define ML307_ICCID_LEN 20 char iccid[ML307_ICCID_LEN] = {0}; /* send "AT+ECICCID" commond to get device iccid */ if (at_obj_exec_cmd (device->client, resp, "AT+MCCID") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw (resp, "+MCCID:", "+MCCID:%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 (ml307.iccid, iccid, ML307_ICCID_LEN); Flash_Sys_Cfg (kIotIccidId, ml307.iccid, ML307_ICCID_LEN); } else { rt_memset ((char *)ml307.iccid, 0, ML307_ICCID_LEN); Get_IotIccid ((char *)&ml307.iccid[0], ML307_ICCID_LEN); } // LOG_D("*(rt_uint16_t *)FLASH_IOT_IMSI_ADDR = %#X", *(rt_uint16_t *)FLASH_IOT_IMSI_ADDR); /* set network interface device hardware imsi */ if ((*(rt_uint16_t *)FLASH_IOT_IMSI_ADDR == 0xE339) || (*(uint16_t *)FLASH_IOT_IMSI_ADDR == 0x39E3)) { #define ML307_IMSI_LEN 15 char imsi[ML307_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 (ml307.imsi, imsi, ML307_IMSI_LEN); Flash_Sys_Cfg (kIotImsiId, ml307.imsi, ML307_IMSI_LEN); } else { rt_memset ((char *)ml307.imsi, 0, ML307_IMSI_LEN); Get_IotImsi ((char *)&ml307.imsi[0], ML307_IMSI_LEN); } if (at_obj_exec_cmd (device->client, resp, "AT+CEREG=1") != RT_EOK) { 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) { 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) { LOG_E ("%s device GPRS is register failed", device->name); result = -RT_ERROR; goto __exit; } if (at_obj_exec_cmd(device->client, resp, "AT+MIPCALL=1,1") != RT_EOK) { result = -RT_ERROR; goto __exit; } #if defined(AT_DEBUG) /* check the GPRS network IP address */ for (i = 0; i < IPADDR_RETRY; i++) { if (at_obj_exec_cmd (client, resp, "AT+MIPCALL?") == RT_EOK) { #define IP_ADDR_SIZE_MAX 16 char ipaddr_str[8 * IP_ADDR_SIZE_MAX] = {0}; char ipaddr_v4[IP_ADDR_SIZE_MAX] = {0}; char ipaddr_v6[4 * IP_ADDR_SIZE_MAX] = {0}; /* parse response data "+CGPADDR: 1," */ if (at_resp_parse_line_args_by_kw (resp, "+MIPCALL:", "+MIPCALL: %*d,%*d,%s", ipaddr_str) > 0) { const char *ipaddr_v4_str = strstr (ipaddr_str, "\""); sscanf (ipaddr_v4_str, "\"%[^\"]", ipaddr_v4); const char *ipaddr_v6_str = strstr (ipaddr_str, "\",\""); sscanf (ipaddr_v6_str, "\",\"%[^\"]", ipaddr_v6); LOG_D ("%s device IP address: %s - %s", device->name, ipaddr_v4, ipaddr_v6); break; } } rt_thread_mdelay (1000); } if (i == IPADDR_RETRY) { LOG_E ("%s device GPRS is get IP address failed", device->name); result = -RT_ERROR; goto __exit; } #endif Time_Calibration (device); /* initialize successfully */ result = RT_EOK; break; __exit: if (result != RT_EOK) { /* power off the ml307 device */ ml307_power_off (device); rt_thread_mdelay (1000); LOG_I ("%s device initialize retry...", device->name); } } if (resp) { at_delete_resp (resp); } if (result == RT_EOK) { /* set network interface device status and address information */ ml307_netdev_set_info (device->netdev); /* check and create link staus sync thread */ ml307_netdev_check_link_status (device->netdev); LOG_I ("%s device network initialize success.", device->name); // while (Flash_Get_Calibration_State() == kNotCalibrated) // { // rt_thread_mdelay(1000); // we need wait for calibration finish // } rt_completion_done (&ml307_init_complate); // 通知初始化完成 } else { LOG_E ("%s device network initialize failed(%d).", device->name, result); } } //当网络状态更改为断网时,释放断连信号量,启动重连机制 static void ml307_netdev_status_changed_callback(struct netdev *netdev, enum netdev_cb_type type) { if (type == NETDEV_CB_STATUS_LINK_DOWN) { LOG_I("Network link down detected, triggering reconnect..."); // 释放断连信号量,用于触发重连线程开始工作 if (ml307_disconnect_sem != NULL) { rt_sem_release(ml307_disconnect_sem); } } } /* ml307 device network initialize */ static int ml307_net_init (struct at_device *device) { #ifdef AT_DEVICE_ML307_INIT_ASYN rt_thread_t tid; /* 初始化完成量对象 */ rt_completion_init (&ml307_init_complate); netdev_set_status_callback(device->netdev, ml307_netdev_status_changed_callback); tid = rt_thread_create ("ml307_net", ml307_init_thread_entry, (void *)device, ML307_THREAD_STACK_SIZE, ML307_THREAD_PRIORITY, 20); if (tid) { rt_thread_startup (tid); } else { LOG_E ("create %s device init thread failed.", device->name); return -RT_ERROR; } #else ml307_init_thread_entry (device); #endif /* AT_DEVICE_ML307_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 Ml307_Get_Signal_Info (struct at_device *device) { #define RETRY 20 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); ml307.rssi = signal_strength; break; } } } rt_thread_mdelay (1000); } if (i == RETRY) { LOG_E ("%s device signal strength check failed", device->name); result = -RT_ERROR; } /* 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; if (at_resp_parse_line_args_by_kw (resp, "+CESQ:", "+CESQ:%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%d", &rsrp) > 0) { if ((rsrp < 97) && (rsrp > 0)) { LOG_D ("%s device signal rsrp: %d", device->name, rsrp); ml307.rsrp = rsrp; break; } } } rt_thread_mdelay (1000); } if (i == RETRY) { LOG_E ("%s device signal data failed", device->name); result = -RT_ERROR; } at_delete_resp (resp); return result; } /* ml307 device network interface attach * - set network interface device link status */ static int ml307_init (struct at_device *device) { RT_ASSERT (device); struct at_device_ml307 *ml307 = (struct at_device_ml307 *)device->user_data; ml307->power_status = RT_FALSE; // default power is off. ml307->sleep_status = RT_FALSE; // default sleep is disabled. rt_device_t serial = rt_device_find (ml307->client_name); if (serial == RT_NULL) { LOG_E ("device(%s) initialize failed, get AT client(%s) failed.", ml307->device_name, ml307->client_name); return -RT_ERROR; } /* initialize AT client */ #if RT_VER_NUM >= 0x50100 at_client_init (ml307->client_name, ml307->recv_line_num, ml307->recv_line_num); #else at_client_init (ml307->client_name, ml307->recv_line_num); #endif device->client = at_client_get (ml307->client_name); if (device->client == RT_NULL) { LOG_E ("get AT client(%s) failed.", ml307->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 ml307_socket_init (device); #endif /* add ml307 device to the netdev list */ device->netdev = ml307_netdev_add (ml307->device_name); if (device->netdev == RT_NULL) { LOG_E ("add netdev(%s) failed.", ml307->device_name); return -RT_ERROR; } ml307_connect_flag_sem = rt_sem_create ("ml307_connect_flag_sem", 0, RT_IPC_FLAG_PRIO); /* initialize ml307 pin configuration */ if (ml307->pwr_en_pin != -1) { rt_pin_mode (ml307->pwr_en_pin, PIN_MODE_OUTPUT); rt_pin_write (ml307->pwr_en_pin, PIN_HIGH); // 打开3_8v供电 } if (ml307->power_pin != -1) { rt_pin_mode (ml307->power_pin, PIN_MODE_OUTPUT); } if (ml307->power_status_pin != -1) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_Init (GPIOB, &GPIO_InitStructure); // rt_pin_mode(ml307->power_status_pin, PIN_MODE_INPUT); } if (ml307->rst_pin != -1) { rt_pin_mode (ml307->rst_pin, PIN_MODE_OUTPUT); } /* initialize ml307 device network */ return ml307_netdev_set_up (device->netdev); } static int ml307_deinit (struct at_device *device) { RT_ASSERT (device); return ml307_netdev_set_down (device->netdev); } static int ml307_control (struct at_device *device, int cmd, void *arg) { int result = -RT_ERROR; RT_ASSERT (device); switch (cmd) { case AT_DEVICE_CTRL_NET_CONN: result = at_device_ml307_connect_tcp (device); break; case AT_DEVICE_CTRL_NET_DISCONN: result = at_device_ml307_disconnect_tcp (device); // 直接删除Socket break; case AT_DEVICE_CTRL_GET_SIGNAL: result = Ml307_Get_Signal_Info (device); break; case AT_DEVICE_CTRL_RESET: result = Ml307_Reset (device); break; case AT_DEVICE_CTRL_POWER_ON: result = ml307_power_on (device); break; case AT_DEVICE_CTRL_POWER_OFF: result = ml307_power_off (device); break; case AT_DEVICE_CTRL_SLEEP: // result = ml307_sleep(device); // break; case AT_DEVICE_CTRL_WAKEUP: // result = ml307_wakeup(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 ml307_device_ops = { ml307_init, ml307_deinit, ml307_control, }; int ml307_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 = &ml307_device_ops; return at_device_class_register (class, AT_DEVICE_CLASS_ML307); } // INIT_DEVICE_EXPORT(ml307_device_class_register); #endif //! IOT_MODULE_SWITCH #endif /* AT_DEVICE_USING_ML307 */