/* * @Author: mbw * @Date: 2024-11-30 15:46:21 * @LastEditors: mbw && 1600520629@qq.com * @LastEditTime: 2025-05-22 09:08:58 * @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}; 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) { socket_id = id; { switch (err_code) { case 0: ml307_conncet_tcp_flag = 1; 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; } rt_sem_release(ml307_connect_flag_sem); // 用于返回连接的标志量在连接函数中 } } } 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) { if (rt_sem_take(ml307_connect_flag_sem, 5000) == RT_EOK) { if (ml307_conncet_tcp_flag) { LOG_D("ml307 connect to tcp server success"); ml307_conncet_tcp_flag = 1; 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) { #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) { size_t len = 0; 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; } } } at_delete_resp(resp); return -RT_ERROR; } static int ml307_check_link_status(struct at_device *device) { at_response_t resp = RT_NULL; int result = -RT_ERROR; int link_stat = 0; RT_ASSERT(device); 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; } } else { LOG_E("AT+MIPCALL error."); result = -RT_ERROR; goto __exit; } 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_DELAY_TIME (60 * RT_TICK_PER_SECOND) #define ML307_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; } at_response_t resp = at_create_resp(ML307_IMEI_RESP_SIZE, 0, ML307_INFO_RESP_TIMO); if (resp == RT_NULL) { LOG_E("no memory for resp create."); return; } while (1) { link_status = ml307_check_link_status(device); if (link_status < 0) { rt_thread_mdelay(ML307_LINK_DELAY_TIME); at_exec_cmd(resp, "AT+MIPCALL=1,1"); continue; } rt_thread_delay(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) { LOG_E("input network interface device is NULL.\n"); 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; } /* 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,120,60,1") != 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; } { #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); } /* 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; } 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 */ { #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); } /* set network interface device hardware imsi */ { #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); } /* 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) if (at_obj_exec_cmd(device->client, resp, "AT+MIPCALL=0") != 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); } } /* 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); 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 */