BLE_TYQ_BJQ_CH32V303/bsp/src/at_device_ml307.c

1477 lines
44 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: mbw
* @Date: 2024-11-30 15:46:21
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-06-05 14:38:32
* @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 <stdio.h>
#include <string.h>
#include "bsp_flash.h"
#include <at_device_ml307.h>
#include "bsp_ml307.h"
#include "user_sys.h"
#include "bsp_rtc.h"
#include "bsp_led.h"
#define LOG_TAG "at.dev.ml307"
#include <at_log.h>
#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",<connect_id>,<recv_length>,<data>*/
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;
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)
{
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;
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=<pri_dns>[,<sec_dns>]" 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=<contextID>"<host>"[,[<timeout>][,<pingnum>]]" 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,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;
}
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);
}
/* 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,<IP_address>" */
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 */