/* * File : at_device_me3616.c * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Change Logs: * Date Author Notes * 2019-12-30 qiyongzhong first version */ #include #include #include #define LOG_TAG "at.dev.me3616" #include #ifdef AT_DEVICE_USING_ME3616 #ifndef ME3616_DEEP_SLEEP_EN #define ME3616_DEEP_SLEEP_EN 0//module support deep sleep mode #endif #define ME3616_WAIT_CONNECT_TIME 5000 #define ME3616_THREAD_STACK_SIZE 2048 #define ME3616_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX/2) static int me3616_power_on(struct at_device *device) { struct at_device_me3616 *me3616 = RT_NULL; me3616 = (struct at_device_me3616 *)device->user_data; me3616->power_status = RT_TRUE; /* not nead to set pin configuration for me3616 device power on */ if (me3616->power_pin == -1) { return(RT_EOK); } rt_pin_write(me3616->power_pin, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(me3616->power_pin, PIN_LOW); LOG_D("power on success."); return(RT_EOK); } static int me3616_power_off(struct at_device *device) { at_response_t resp = RT_NULL; struct at_device_me3616 *me3616 = RT_NULL; resp = at_create_resp(64, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); return(-RT_ERROR); } at_obj_exec_cmd(device->client, resp, "AT+ZTURNOFF");//command response does not have "\r\n" after "OK" /*if (at_obj_exec_cmd(device->client, resp, "AT+ZTURNOFF") != RT_EOK) { LOG_D("power off fail."); at_delete_resp(resp); return(-RT_ERROR); }*/ at_delete_resp(resp); me3616 = (struct at_device_me3616 *)device->user_data; me3616->power_status = RT_FALSE; LOG_D("power off success."); return(RT_EOK); } static int me3616_sleep(struct at_device *device) { at_response_t resp = RT_NULL; struct at_device_me3616 *me3616 = RT_NULL; me3616 = (struct at_device_me3616 *)device->user_data; if ( ! me3616->power_status)//power off { return(RT_EOK); } if (me3616->sleep_status)//is sleep status { return(RT_EOK); } resp = at_create_resp(64, 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+CPSMS=1,,,\"00111110\",\"00000001\"") != RT_EOK) { LOG_D("enable sleep fail."); at_delete_resp(resp); return(-RT_ERROR); } #if ME3616_DEEP_SLEEP_EN if (at_obj_exec_cmd(device->client, resp, "AT+ZSLR") != RT_EOK) { LOG_D("startup entry into sleep fail."); at_delete_resp(resp); return(-RT_ERROR); } #endif at_delete_resp(resp); me3616->sleep_status = RT_TRUE; LOG_D("sleep success."); return(RT_EOK); } static int me3616_wakeup(struct at_device *device) { at_response_t resp = RT_NULL; struct at_device_me3616 *me3616 = RT_NULL; me3616 = (struct at_device_me3616 *)device->user_data; if ( ! me3616->power_status)//power off { LOG_E("the power is off and the wake-up cannot be performed"); return(-RT_ERROR); } if ( ! me3616->sleep_status)//no sleep status { return(RT_EOK); } resp = at_create_resp(64, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); return(-RT_ERROR); } #if ME3616_DEEP_SLEEP_EN if (me3616->power_pin != -1) { rt_pin_write(me3616->power_pin, PIN_HIGH); rt_thread_mdelay(100); rt_pin_write(me3616->power_pin, PIN_LOW); rt_thread_mdelay(200); } #endif if (at_obj_exec_cmd(device->client, resp, "AT+CPSMS=0") != RT_EOK) { LOG_D("wake up fail."); at_delete_resp(resp); return(-RT_ERROR); } at_delete_resp(resp); me3616->sleep_status = RT_FALSE; LOG_D("wake up success."); return(RT_EOK); } static int me3616_check_link_status(struct at_device *device) { at_response_t resp = RT_NULL; struct at_device_me3616 *me3616 = RT_NULL; int result = -RT_ERROR; RT_ASSERT(device); me3616 = (struct at_device_me3616 *)device->user_data; if ( ! me3616->power_status)//power off { LOG_D("the power is off."); return(-RT_ERROR); } #if ME3616_DEEP_SLEEP_EN if (me3616->sleep_status)//is sleep status { if (me3616->power_pin != -1) { rt_pin_write(me3616->power_pin, PIN_HIGH); rt_thread_mdelay(100); rt_pin_write(me3616->power_pin, PIN_LOW); rt_thread_mdelay(200); } } #endif resp = at_create_resp(64, 0, rt_tick_from_millisecond(300)); if (resp == RT_NULL) { LOG_E("no memory for resp create."); return(-RT_ERROR); } result = -RT_ERROR; if (at_obj_exec_cmd(device->client, resp, "AT+CGREG?") == RT_EOK) { int link_stat = 0; if (at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %*d,%d", &link_stat) > 0) { if (link_stat == 1 || link_stat == 5) { result = RT_EOK; } } } #if ME3616_DEEP_SLEEP_EN if (me3616->sleep_status)//is sleep status { if (at_obj_exec_cmd(device->client, resp, "AT+ZSLR") != RT_EOK) { LOG_D("startup entry into sleep fail."); } } #endif at_delete_resp(resp); return(result); } /* ============================= me3616 network interface operations ============================= */ /* set me3616 network interface device status and address information */ static int me3616_netdev_set_info(struct netdev *netdev) { #define ME3616_INFO_RESP_SIZE 128 #define ME3616_INFO_RESP_TIMO rt_tick_from_millisecond(300) 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(ME3616_INFO_RESP_SIZE, 0, ME3616_INFO_RESP_TIMO); if (resp == RT_NULL) { LOG_E("no memory for resp create."); result = -RT_ENOMEM; goto __exit; } /* set network interface device hardware address(IMEI) */ { #define ME3616_NETDEV_HWADDR_LEN 8 #define ME3616_IMEI_LEN 15 char imei[ME3616_IMEI_LEN] = {0}; int i = 0, j = 0; /* send "AT+GSN" commond to get device IMEI */ if (at_obj_exec_cmd(device->client, resp, "AT+GSN") != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args(resp, 2, "%s", imei) <= 0) { LOG_E("%s device prase \"AT+GSN\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D("%s device IMEI number: %s", device->name, imei); netdev->hwaddr_len = ME3616_NETDEV_HWADDR_LEN; /* get hardware address by IMEI */ for (i = 0, j = 0; i < ME3616_NETDEV_HWADDR_LEN && j < ME3616_IMEI_LEN; i++, j+=2) { if (j != ME3616_IMEI_LEN - 1) { netdev->hwaddr[i] = (imei[j] - '0') * 10 + (imei[j + 1] - '0'); } else { netdev->hwaddr[i] = (imei[j] - '0'); } } } /* set network interface device IP address */ { #define IP_ADDR_SIZE_MAX 16 char ipaddr[IP_ADDR_SIZE_MAX] = {0}; /* send "AT+CGPADDR=1" commond to get IP address */ if (at_obj_exec_cmd(device->client, resp, "AT+CGPADDR=1") != RT_EOK) { result = -RT_ERROR; goto __exit; } /* parse response data "+CGPADDR: 1," */ if (at_resp_parse_line_args_by_kw(resp, "+CGPADDR:", "+CGPADDR: %*d,\"%s\"", ipaddr) <= 0) { LOG_E("%s device \"AT+CGPADDR=1\" cmd error.", device->name); result = -RT_ERROR; goto __exit; } LOG_D("%s device 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; } static void me3616_check_link_status_entry(void *parameter) { #define ME3616_LINK_DELAY_TIME (60 * RT_TICK_PER_SECOND) rt_bool_t is_link_up; 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) { is_link_up = (me3616_check_link_status(device) == RT_EOK); netdev_low_level_set_link_status(netdev, is_link_up); rt_thread_delay(ME3616_LINK_DELAY_TIME); } } static int me3616_netdev_check_link_status(struct netdev *netdev) { #define ME3616_LINK_THREAD_TICK 20 #define ME3616_LINK_THREAD_STACK_SIZE (1024 + 512) #define ME3616_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", netdev->name); /* create me3616 link status polling thread */ tid = rt_thread_create(tname, me3616_check_link_status_entry, (void *)netdev, ME3616_LINK_THREAD_STACK_SIZE, ME3616_LINK_THREAD_PRIORITY, ME3616_LINK_THREAD_TICK); if (tid != RT_NULL) { rt_thread_startup(tid); } return RT_EOK; } static int me3616_net_init(struct at_device *device); static int me3616_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) { me3616_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 me3616_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) { me3616_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; } #ifdef NETDEV_USING_PING static int me3616_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp) { #define ME3616_PING_RESP_SIZE 256 #define ME3616_PING_IP_SIZE 16 #define ME3616_PING_TIMEO (10 * RT_TICK_PER_SECOND) rt_err_t result = RT_EOK; int response = -1, recv_data_len, ping_time, ttl; char ip_addr[ME3616_PING_IP_SIZE] = {0}; at_response_t resp = RT_NULL; struct at_device *device = RT_NULL; 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(ME3616_PING_RESP_SIZE, 0, ME3616_PING_TIMEO); if (resp == RT_NULL) { LOG_E("no memory for resp create"); return -RT_ENOMEM; } if (at_obj_exec_cmd(device->client, resp, "AT+EDNS=\"%s\"", host) != RT_EOK) { result = -RT_ERROR; goto __exit; } if (at_resp_parse_line_args_by_kw(resp, "IPV4:", "IPV4:%s\r", ip_addr) <= 0) { result = -RT_ERROR; goto __exit; } at_resp_set_info(resp, ME3616_PING_RESP_SIZE, 8, timeout); /* send "AT+PING=[-l/L ] [-n/N ][-w/W