JT-DT-YD4N02B_4G_RTT_MRS/bsp/src/at_device_nt26k.c

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