diff --git a/at_socket_ec20.c b/at_socket_ec20.c index a6901a2..b758039 100644 --- a/at_socket_ec20.c +++ b/at_socket_ec20.c @@ -32,6 +32,8 @@ #include #include +#include + #if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200 #error "This AT Client version is older, please check and update latest AT Client!" #endif @@ -41,6 +43,8 @@ #ifdef AT_DEVICE_EC20 +#define EC20_NETDEV_NAME "ec20" + #define EC20_MODULE_SEND_MAX_SIZE 1460 #define EC20_WAIT_CONNECT_TIME 5000 #define EC20_THREAD_STACK_SIZE 1024 @@ -58,8 +62,6 @@ #define EC20_EVENT_SEND_FAIL (1L << 5) #define EC20_EVENT_DOMAIN_OK (1L << 6) - - /* AT+QICSGP command default*/ char *QICSGP_CHINA_MOBILE = "AT+QICSGP=1,1,\"CMNET\",\"\",\"\",0"; char *QICSGP_CHINA_UNICOM = "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",0"; @@ -214,11 +216,11 @@ static void at_tcp_ip_errcode_parse(int result)//TCP/IP_QIGETERROR case 560 : LOG_E("%d : Socket accept failed", result); break; case 561 : LOG_E("%d : Open PDP context failed", result); break; case 562 : LOG_E("%d : Close PDP context failed", result); break; - case 563 : LOG_E("%d : Socket identity has been used", result); break; + case 563 : LOG_W("%d : Socket identity has been used", result); break; case 564 : LOG_E("%d : DNS busy", result); break; case 565 : LOG_E("%d : DNS parse failed", result); break; case 566 : LOG_E("%d : Socket connect failed", result); break; - case 567 : LOG_E("%d : Socket has been closed", result); break; + case 567 : LOG_W("%d : Socket has been closed", result); break; case 568 : LOG_E("%d : Operation busy", result); break; case 569 : LOG_E("%d : Operation timeout", result); break; case 570 : LOG_E("%d : PDP context broken down", result); break; @@ -447,26 +449,18 @@ static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t opt static int ec20_socket_close(int socket) { int result = 0; - at_response_t resp = RT_NULL; - - resp = at_create_resp(64, 2, rt_tick_from_millisecond(2 * 1000)); - if (!resp) - { - LOG_E("No memory for response structure!"); - return -RT_ENOMEM; - } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/ - result = at_exec_cmd(resp, "AT+QICLOSE=%d,1", socket); + result = at_exec_cmd(RT_NULL, "AT+QICLOSE=%d,1", socket); if (result < 0) { - LOG_E("socket (%d) close failed, wait close OK timeout or ERROR.", socket); + return result; } -__exit: - if (resp) - { - at_delete_resp(resp); - } + rt_mutex_release(at_event_lock); + return result; } @@ -496,6 +490,9 @@ static int ec20_socket_connect(int socket, char *ip, int32_t port, enum at_socke rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); __retry: + + /* Clear socket connect event */ + at_socket_event_recv(SET_EVENT(socket, EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR); if (is_client) { @@ -528,14 +525,14 @@ __retry: } /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(10 * 1000), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { LOG_E("socket (%d) connect failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL, rt_tick_from_millisecond(1 * 1000), + if ((event_result = at_socket_event_recv(EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket); @@ -547,11 +544,9 @@ __retry: { if (!retryed) { - LOG_E("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket); - if (ec20_socket_close(socket) < 0) - { - goto __exit; - } + LOG_W("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket); + /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/ + at_exec_cmd(RT_NULL, "AT+QICLOSE=%d,1", socket); retryed = RT_TRUE; goto __retry; } @@ -569,7 +564,7 @@ __exit: static int at_get_send_size(int socket, size_t *size, size_t *acked, size_t *nacked) { - at_response_t resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000)); + at_response_t resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND); int result = 0; if (!resp) @@ -614,7 +609,7 @@ static int at_wait_send_finish(int socket, size_t settings_size) { return RT_EOK; } - rt_thread_delay(rt_tick_from_millisecond(50)); + rt_thread_mdelay(50); } return -RT_ETIMEOUT; @@ -641,7 +636,7 @@ static int ec20_socket_send(int socket, const char *buff, size_t bfsz, enum at_s RT_ASSERT(buff); - resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000)); + resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -650,6 +645,9 @@ static int ec20_socket_send(int socket, const char *buff, size_t bfsz, enum at_s rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* Clear socket send event */ + at_socket_event_recv(SET_EVENT(socket, EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR); + /* set current socket for send URC event */ cur_socket = socket; /* set AT client end sign to deal with '>' sign.*/ @@ -682,14 +680,13 @@ static int ec20_socket_send(int socket, const char *buff, size_t bfsz, enum at_s } /* waiting result event from AT URC */ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(300*3), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { - LOG_E("socket (%d) send failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL, rt_tick_from_millisecond(1 * 1000), + if ((event_result = at_socket_event_recv(EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket); @@ -740,18 +737,17 @@ __exit: */ static int ec20_domain_resolve(const char *name, char ip[16]) { -#define RESOLVE_RETRY 5 +#define RESOLVE_RETRY 3 int i, result; // char recv_ip[16] = { 0 }; at_response_t resp = RT_NULL; - RT_ASSERT(name); RT_ASSERT(ip); /* The maximum response time is 60 seconds, but it set to 10 seconds is convenient to use. */ - resp = at_create_resp(128, 0, rt_tick_from_millisecond(10 * 1000)); + resp = at_create_resp(128, 0, 10 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -759,38 +755,30 @@ static int ec20_domain_resolve(const char *name, char ip[16]) } rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* Clear EC20_EVENT_DOMAIN_OK */ at_socket_event_recv(EC20_EVENT_DOMAIN_OK, 0, RT_EVENT_FLAG_OR); - for(i = 0; i < RESOLVE_RETRY; i++) + + result = at_exec_cmd(resp, "AT+QIDNSGIP=1,\"%s\"", name); + if (result < 0) { - if (at_exec_cmd(resp, "AT+QIDNSGIP=1,\"%s\"", name) < 0) - { - LOG_E("Domain \"%s\" resolve return ERROR (%d).", name, i); - result = -RT_ERROR; - continue; - } - else - { - result = RT_EOK; - break; - } + goto __exit; } + if (result == RT_EOK) { for(i = 0; i < RESOLVE_RETRY; i++) { /* waiting result event from AT URC, the device default connection timeout is 60 seconds.*/ - if (at_socket_event_recv(EC20_EVENT_DOMAIN_OK, rt_tick_from_millisecond(10 * 1000), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(EC20_EVENT_DOMAIN_OK, 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { - LOG_E("Domain \"%s\" resolve failed, wait dns result timeout.", name); - result = -RT_ETIMEOUT; continue; } else { if (strlen(recv_ip) < 8) { - rt_thread_delay(rt_tick_from_millisecond(100)); + rt_thread_mdelay(100); /* resolve failed, maybe receive an URC CRLF */ result = -RT_ERROR; continue; @@ -804,8 +792,15 @@ static int ec20_domain_resolve(const char *name, char ip[16]) } } } + + /* response timeout */ + if (i == RESOLVE_RETRY) + { + result = -RT_ENOMEM; + } } + __exit: rt_mutex_release(at_event_lock); if (resp) @@ -831,41 +826,6 @@ static void ec20_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb) } } -static void urc_ping_func(const char *data, rt_size_t size) -{ - static int icmp_seq = 0; - int i, j = 0; - int result, recv_len, time, ttl; - int sent, rcvd, lost, min, max, avg; - char dst_ip[16] = { 0 }; - - RT_ASSERT(data); - - for (i=0;i,0" command to close socket */ at_exec_cmd(RT_NULL, "AT+QICLOSE=%d,0\r\n", socket); - rt_thread_delay(rt_tick_from_millisecond(100)); + rt_thread_mdelay(100); } static void urc_recv_func(const char *data, rt_size_t size) @@ -986,28 +946,25 @@ static void urc_dnsqip_func(const char *data, rt_size_t size) { int i = 0, j = 0; int result, ip_count, dns_ttl; - static uint8_t resolved = 0; RT_ASSERT(data && size); - for(i=0;i\n"); - return -RT_ERROR; - } - - resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - if (at_exec_cmd(resp, "AT+QPING=1,\"%s\"", argv[1]) < 0) - { - rt_kprintf("AT send ping commands error!\n"); - return -RT_ERROR; - } - - if (resp) - { - at_delete_resp(resp); - } - - return RT_EOK; -} - -int ec20_connect(int argc, char **argv) -{ - int32_t port; - - if (argc != 3) - { - rt_kprintf("Please input: at_connect \n"); - return -RT_ERROR; - } - sscanf(argv[2],"%d",&port); - ec20_socket_connect(0, argv[1], port, AT_SOCKET_TCP, 1); - - return RT_EOK; -} - -int ec20_close(int argc, char **argv) -{ - if (ec20_socket_close(0) < 0) - { - rt_kprintf("ec20_socket_close fail\n"); - } - else - { - rt_kprintf("ec20_socket_closeed\n"); - } - return RT_EOK; -} - -int ec20_send(int argc, char **argv) -{ - const char *buff = "1234567890\n"; - if (ec20_socket_send(0, buff, 11, AT_SOCKET_TCP) < 0) - { - rt_kprintf("ec20_socket_send fail\n"); - } - - return RT_EOK; -} - -int ec20_domain(int argc, char **argv) -{ - char ip[16]; - if (ec20_domain_resolve("baidu.com", ip) < 0) - { - rt_kprintf("ec20_socket_send fail\n"); - } - else - { - rt_kprintf("baidu.com : %s\n", ip); - } - - return RT_EOK; -} - -int ec20_ifconfig(void) -{ - at_response_t resp = RT_NULL; - char resp_arg[AT_CMD_MAX_LEN] = { 0 }; - rt_err_t result = RT_EOK; - - resp = at_create_resp(128, 2, rt_tick_from_millisecond(300)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - /* Query the status of the context profile */ - AT_SEND_CMD(resp, 0, 150 * 1000, "AT+QIACT?"); - at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", &resp_arg); - rt_kprintf("IP adress : %s\n", resp_arg); - -__exit: - if (resp) - { - at_delete_resp(resp); - } - - return result; -} - #ifdef FINSH_USING_MSH #include MSH_CMD_EXPORT_ALIAS(ec20_net_init, at_net_init, initialize AT network); -MSH_CMD_EXPORT_ALIAS(ec20_ping, at_ping, AT ping network host); -MSH_CMD_EXPORT_ALIAS(ec20_ifconfig, at_ifconfig, list the information of network interfaces); -MSH_CMD_EXPORT_ALIAS(ec20_connect, at_connect, AT connect network host); -MSH_CMD_EXPORT_ALIAS(ec20_close, at_close, AT close a socket); -MSH_CMD_EXPORT_ALIAS(ec20_send, at_send, AT send a pack); -MSH_CMD_EXPORT_ALIAS(ec20_domain, at_domain, AT domain resolve); #endif static const struct at_device_ops ec20_socket_ops = { @@ -1388,6 +1235,406 @@ static const struct at_device_ops ec20_socket_ops = { ec20_socket_set_event_cb, }; +/* set ec20 network interface device status and address information */ +static int ec20_netdev_set_info(struct netdev *netdev) +{ +#define EC20_IEMI_RESP_SIZE 32 +#define EC20_IPADDR_RESP_SIZE 64 +#define EC20_DNS_RESP_SIZE 96 +#define EC20_INFO_RESP_TIMO rt_tick_from_millisecond(300) + + int result = RT_EOK; + at_response_t resp = RT_NULL; + ip_addr_t addr; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* 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(EC20_IEMI_RESP_SIZE, 0, EC20_INFO_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("EC20 set netdev information failed, no memory for response object."); + result = -RT_ENOMEM; + goto __exit; + } + + /* set network interface device hardware address(IEMI) */ + { + #define EC20_NETDEV_HWADDR_LEN 8 + #define EC20_IEMI_LEN 15 + + char iemi[EC20_IEMI_LEN] = {0}; + int i = 0, j = 0; + + /* send "AT+GSN" commond to get device IEMI */ + if (at_exec_cmd(resp, "AT+GSN") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0) + { + LOG_E("Prase \"AT+GSN\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("EC20 IEMI number: %s", iemi); + + netdev->hwaddr_len = EC20_NETDEV_HWADDR_LEN; + /* get hardware address by IEMI */ + for (i = 0, j = 0; i < EC20_NETDEV_HWADDR_LEN && j < EC20_IEMI_LEN; i++, j+=2) + { + if (j != EC20_IEMI_LEN - 1) + { + netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0'); + } + else + { + netdev->hwaddr[i] = (iemi[j] - '0'); + } + } + } + + /* set network interface device IP address */ + { + #define IP_ADDR_SIZE_MAX 16 + char ipaddr[IP_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, EC20_IPADDR_RESP_SIZE, 0, EC20_INFO_RESP_TIMO); + + /* send "AT+QIACT?" commond to get IP address */ + if (at_exec_cmd(resp, "AT+QIACT?") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + /* parse response data "+QIACT: 1,,[,]" */ + if (at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", ipaddr) <= 0) + { + LOG_E("Prase \"AT+QIACT?\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("EC20 IP address: %s", ipaddr); + + /* set network interface address information */ + inet_aton(ipaddr, &addr); + netdev_low_level_set_ipaddr(netdev, &addr); + } + + /* set network interface device dns server */ + { + #define DNS_ADDR_SIZE_MAX 16 + char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, EC20_DNS_RESP_SIZE, 0, EC20_INFO_RESP_TIMO); + + /* send "AT+QIDNSCFG=1" commond to get DNS servers address */ + if (at_exec_cmd(resp, "AT+QIDNSCFG=1") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + /* parse response data "+QIDNSCFG: ,," */ + if (at_resp_parse_line_args_by_kw(resp, "+QIDNSCFG:", "+QIDNSCFG: 1,\"%[^\"]\",\"%[^\"]\"", + dns_server1, dns_server2) <= 0) + { + LOG_E("Prase \"AT+QIDNSCFG=1\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("EC20 primary DNS server address: %s", dns_server1); + LOG_D("EC20 secondary DNS server address: %s", dns_server2); + + inet_aton(dns_server1, &addr); + netdev_low_level_set_dns_server(netdev, 0, &addr); + + inet_aton(dns_server2, &addr); + netdev_low_level_set_dns_server(netdev, 1, &addr); + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static void ec20_check_link_status_entry(void *parameter) +{ +#define EC20_LINK_RESP_SIZE 64 +#define EC20_LINK_RESP_TIMO (3 * RT_TICK_PER_SECOND) +#define EC20_LINK_DELAY_TIME (30 * RT_TICK_PER_SECOND) + + int link_stat = 0; + at_response_t resp = RT_NULL; + struct netdev *netdev = (struct netdev *) parameter; + + resp = at_create_resp(EC20_LINK_RESP_SIZE, 0, EC20_LINK_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("EC20 set check link status failed, no memory for response object."); + return; + } + + while (1) + { + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send "AT+CGREG" commond to check netweork interface device link status */ + if (at_exec_cmd(resp, "AT+CGREG?") < 0) + { + if (netdev_is_link_up(netdev)) + { + netdev_low_level_set_link_status(netdev, RT_FALSE); + } + + rt_mutex_release(at_event_lock); + rt_thread_mdelay(EC20_LINK_DELAY_TIME); + continue; + } + else + { + at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %*d,%d", &link_stat); + + /* 1 Registered, home network,5 Registered, roaming */ + if (link_stat == 1 || link_stat == 5) + { + if (netdev_is_link_up(netdev) == RT_FALSE) + { + netdev_low_level_set_link_status(netdev, RT_TRUE); + } + } + else + { + if (netdev_is_link_up(netdev)) + { + netdev_low_level_set_link_status(netdev, RT_FALSE); + } + } + } + + rt_mutex_release(at_event_lock); + rt_thread_mdelay(EC20_LINK_DELAY_TIME); + } +} + +static int ec20_netdev_check_link_status(struct netdev *netdev) +{ +#define EC20_LINK_THREAD_STACK_SIZE 1024 +#define EC20_LINK_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2) +#define EC20_LINK_THREAD_TICK 20 + + rt_thread_t tid; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + /* create WIZnet link status Polling thread */ + tid = rt_thread_create("ec20_link", ec20_check_link_status_entry, (void *) netdev, + EC20_LINK_THREAD_STACK_SIZE, EC20_LINK_THREAD_PRIORITY, EC20_LINK_THREAD_TICK); + if (tid != RT_NULL) + { + rt_thread_startup(tid); + } + + return RT_EOK; +} + +static int ec20_netdev_set_up(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_TRUE); + LOG_D("EC20 network interface set up status."); + return RT_EOK; +} + +static int ec20_netdev_set_down(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_FALSE); + LOG_D("EC20 network interface set down status."); + return RT_EOK; +} + +static int ec20_netdev_set_dns_server(struct netdev *netdev, ip_addr_t *dns_server) +{ +#define EC20_DNS_RESP_LEN 8 +#define EC20_DNS_RESP_TIMEO rt_tick_from_millisecond(300) + + at_response_t resp = RT_NULL; + int result = RT_EOK; + + RT_ASSERT(netdev); + RT_ASSERT(dns_server); + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + resp = at_create_resp(EC20_DNS_RESP_LEN, 0, EC20_DNS_RESP_TIMEO); + if (resp == RT_NULL) + { + LOG_E("EC20 set dns server failed, no memory for response object."); + result = -RT_ENOMEM; + goto __exit; + } + + /* send "AT+QIDNSCFG=[,]" commond to set dns servers */ + if (at_exec_cmd(resp, "AT+QIDNSCFG=1,\"%s\"", inet_ntoa(dns_server)) < 0) + { + result = -RT_ERROR; + goto __exit; + } + + netdev_low_level_set_dns_server(netdev, 0, dns_server); + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static int ec20_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp) +{ +#define EC20_PING_RESP_SIZE 128 +#define EC20_PING_IP_SIZE 16 +#define EC20_PING_TIMEO (5 * RT_TICK_PER_SECOND) + + at_response_t resp = RT_NULL; + rt_err_t result = RT_EOK; + int response = -1, recv_data_len, ping_time, ttl; + char ip_addr[EC20_PING_IP_SIZE] = {0}; + + RT_ASSERT(netdev); + RT_ASSERT(host); + RT_ASSERT(ping_resp); + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + resp = at_create_resp(EC20_PING_RESP_SIZE, 4, EC20_PING_TIMEO); + if (resp == RT_NULL) + { + LOG_E("No memory for response structure!\n"); + return -RT_ENOMEM; + } + + /* send "AT+QPING=""[,[][,]]" commond to send ping request */ + if (at_exec_cmd(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); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +void ec20_netdev_netstat(struct netdev *netdev) +{ + // TODO + return; +} + +const struct netdev_ops ec20_netdev_ops = +{ + ec20_netdev_set_up, + ec20_netdev_set_down, + + RT_NULL, + ec20_netdev_set_dns_server, + RT_NULL, + + ec20_netdev_ping, + ec20_netdev_netstat, +}; + +static int ec20_netdev_add(const char *netdev_name) +{ +#define ETHERNET_MTU 1500 +#define HWADDR_LEN 6 + struct netdev *netdev = RT_NULL; + + netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return RT_NULL; + } + + netdev->mtu = ETHERNET_MTU; + netdev->ops = &ec20_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 + + return netdev_register(netdev, netdev_name, RT_NULL); +} + static int at_socket_device_init(void) { /* create current AT socket event */ @@ -1412,14 +1659,21 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); - + + /* Add ec20 network inetrface device to the netdev list */ + if (ec20_netdev_add(EC20_NETDEV_NAME) < 0) + { + LOG_E("EC20 network interface device(%d) add failed.", EC20_NETDEV_NAME); + return -RT_ENOMEM; + } + /* initialize EC20 network */ ec20_net_init(); /* set EC20 AT Socket options */ at_socket_device_register(&ec20_socket_ops); - return 0; + return RT_EOK; } INIT_APP_EXPORT(at_socket_device_init); diff --git a/at_socket_esp8266.c b/at_socket_esp8266.c index 1a88147..a7d64ba 100644 --- a/at_socket_esp8266.c +++ b/at_socket_esp8266.c @@ -31,6 +31,8 @@ #include +#include + #if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200 #error "This AT Client version is older, please check and update latest AT Client!" #endif @@ -56,8 +58,11 @@ #define ESP8266_EVENT_CONN_FAIL (1L << 4) #define ESP8266_EVENT_SEND_FAIL (1L << 5) +#define ESP8266_NETDEV_NAME "esp8266" + static int cur_socket; static int cur_send_bfsz; +static struct rt_delayed_work esp8266_net_work; static rt_event_t at_socket_event; static rt_mutex_t at_event_lock; static at_evt_cb_t at_evt_cb_set[] = { @@ -114,7 +119,7 @@ static int esp8266_socket_close(int socket) goto __exit; } - __exit: +__exit: rt_mutex_release(at_event_lock); if (resp) @@ -345,7 +350,7 @@ static int esp8266_domain_resolve(const char *name, char ip[16]) rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); - for(i = 0; i < RESOLVE_RETRY; i++) + for (i = 0; i < RESOLVE_RETRY; i++) { if (at_exec_cmd(resp, "AT+CIPDOMAIN=\"%s\"", name) < 0) { @@ -354,7 +359,7 @@ static int esp8266_domain_resolve(const char *name, char ip[16]) } /* parse the third line of response data, get the IP address */ - if(at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0) + if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0) { rt_thread_delay(rt_tick_from_millisecond(100)); /* resolve failed, maybe receive an URC CRLF */ @@ -510,12 +515,15 @@ static void urc_func(const char *data, rt_size_t size) { RT_ASSERT(data && size); - if(strstr(data, "WIFI CONNECTED")) + if (strstr(data, "WIFI CONNECTED")) { + netdev_low_level_set_link_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_TRUE); + rt_work_submit(&(esp8266_net_work.work), RT_TICK_PER_SECOND); LOG_I("ESP8266 WIFI is connected."); } - else if(strstr(data, "WIFI DISCONNECT")) + else if (strstr(data, "WIFI DISCONNECT")) { + netdev_low_level_set_link_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_FALSE); LOG_I("ESP8266 WIFI is disconnect."); } } @@ -543,6 +551,134 @@ static struct at_urc urc_table[] = { } \ } while(0); \ +static void exp8266_get_netdev_info(struct rt_work *work, void *work_data) +{ +#define AT_ADDR_LEN 32 + at_response_t resp = RT_NULL; + char ip[AT_ADDR_LEN], mac[AT_ADDR_LEN]; + char gateway[AT_ADDR_LEN], netmask[AT_ADDR_LEN]; + char dns_server1[AT_ADDR_LEN] = {0}, dns_server2[AT_ADDR_LEN] = {0}; + const char *resp_expr = "%*[^\"]\"%[^\"]\""; + const char *resp_dns = "+CIPDNS_CUR:%s"; + const char *resp_dhcp = "+CWDHCP_CUR:%d"; + ip_addr_t sal_ip_addr; + rt_uint8_t mac_addr[6] = {0}; + rt_uint8_t dhcp_stat = 0; + struct netdev *netdev = RT_NULL; + + netdev = (struct netdev *)work_data; + + rt_memset(ip, 0x00, sizeof(ip)); + rt_memset(mac, 0x00, sizeof(mac)); + rt_memset(gateway, 0x00, sizeof(gateway)); + rt_memset(netmask, 0x00, sizeof(netmask)); + + resp = at_create_resp(512, 0, rt_tick_from_millisecond(300)); + if (!resp) + { + LOG_E("No memory for response structure!"); + return; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* send mac addr query commond "AT+CIFSR" and wait response */ + if (at_exec_cmd(resp, "AT+CIFSR") < 0) + { + LOG_E("AT send \"AT+CIFSR\" commands error!"); + goto __exit; + } + + if (at_resp_parse_line_args(resp, 2, resp_expr, mac) <= 0) + { + LOG_E("Parse error, current line buff : %s", at_resp_get_line(resp, 2)); + goto __exit; + } + + /* send addr info query commond "AT+CIPSTA?" and wait response */ + if (at_exec_cmd(resp, "AT+CIPSTA?") < 0) + { + LOG_E("AT send \"AT+CIPSTA?\" commands error!"); + goto __exit; + } + + if (at_resp_parse_line_args(resp, 1, resp_expr, ip) <= 0 || + at_resp_parse_line_args(resp, 2, resp_expr, gateway) <= 0 || + at_resp_parse_line_args(resp, 3, resp_expr, netmask) <= 0) + { + LOG_E("Prase \"AT+CIPSTA?\" commands resposne data error!"); + goto __exit; + } + + /* set netdev info */ + inet_aton(ip, &sal_ip_addr); + netdev_low_level_set_ipaddr(netdev, &sal_ip_addr); + inet_aton(gateway, &sal_ip_addr); + netdev_low_level_set_gw(netdev, &sal_ip_addr); + inet_aton(netmask, &sal_ip_addr); + netdev_low_level_set_netmask(netdev, &sal_ip_addr); + sscanf(mac, "%x:%x:%x:%x:%x:%x", (rt_uint32_t *)&mac_addr[0], (rt_uint32_t *)&mac_addr[1], (rt_uint32_t *)&mac_addr[2], (rt_uint32_t *)&mac_addr[3], (rt_uint32_t *)&mac_addr[4], (rt_uint32_t *)&mac_addr[5]); + memcpy(netdev->hwaddr, (const void *)mac_addr, netdev->hwaddr_len); + + /* send dns server query commond "AT+CIPDNS_CUR?" and wait response */ + if (at_exec_cmd(resp, "AT+CIPDNS_CUR?") < 0) + { + LOG_E("AT send \"AT+CIPDNS_CUR?\" commands error!"); + goto __exit; + } + + if (at_resp_parse_line_args(resp, 1, resp_dns, dns_server1) <= 0 && + at_resp_parse_line_args(resp, 2, resp_dns, dns_server2) <= 0) + { + LOG_E("Prase \"AT+CIPDNS_CUR?\" commands resposne data error!"); + LOG_E("get dns server failed! Please check whether your firmware supports the \"AT+CIPDNS_CUR?\" command."); + goto __exit; + } + + if (strlen(dns_server1) > 0) + { + inet_aton(dns_server1, &sal_ip_addr); + netdev_low_level_set_dns_server(netdev, 0, &sal_ip_addr); + } + + if (strlen(dns_server2) > 0) + { + inet_aton(dns_server2, &sal_ip_addr); + netdev_low_level_set_dns_server(netdev, 1, &sal_ip_addr); + } + + /* send DHCP query commond " AT+CWDHCP_CUR?" and wait response */ + if (at_exec_cmd(resp, "AT+CWDHCP_CUR?") < 0) + { + LOG_E("AT send \"AT+CWDHCP_CUR?\" commands error!"); + goto __exit; + } + + /* parse response data, get the DHCP status */ + if (at_resp_parse_line_args_by_kw(resp, "+CWDHCP_CUR:", "+CWDHCP_CUR:%d", &dhcp_stat) < 0) + { + LOG_E("get DHCP status failed!"); + goto __exit; + } + + /* Bit0: SoftAP DHCP status, Bit1: Station DHCP status */ + if (dhcp_stat & 0x02) + { + netdev_low_level_set_dhcp_status(netdev, RT_TRUE); + } + else + { + netdev_low_level_set_dhcp_status(netdev, RT_FALSE); + } + +__exit: + rt_mutex_release(at_event_lock); + + if (resp) + { + at_delete_resp(resp); + } +} + static void esp8266_init_thread_entry(void *parameter) { at_response_t resp = RT_NULL; @@ -592,10 +728,12 @@ __exit: if (!result) { + netdev_low_level_set_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_TRUE); LOG_I("AT network initialize success!"); } else { + netdev_low_level_set_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_FALSE); LOG_E("AT network initialize failed (%d)!", result); } } @@ -605,7 +743,7 @@ int esp8266_net_init(void) #ifdef PKG_AT_INIT_BY_THREAD rt_thread_t tid; - tid = rt_thread_create("esp8266_net_init", esp8266_init_thread_entry, RT_NULL,ESP8266_THREAD_STACK_SIZE, ESP8266_THREAD_PRIORITY, 20); + tid = rt_thread_create("esp8266_net_init", esp8266_init_thread_entry, RT_NULL, ESP8266_THREAD_STACK_SIZE, ESP8266_THREAD_PRIORITY, 20); if (tid) { rt_thread_startup(tid); @@ -620,121 +758,93 @@ int esp8266_net_init(void) return RT_EOK; } +#ifdef FINSH_USING_MSH + #include + MSH_CMD_EXPORT_ALIAS(esp8266_net_init, at_net_init, initialize AT network); +#endif -int esp8266_ping(int argc, char **argv) +static const struct at_device_ops esp8266_socket_ops = { - at_response_t resp = RT_NULL; - static int icmp_seq; - int req_time; - - if (argc != 2) - { - rt_kprintf("Please input: at_ping \n"); - return -RT_ERROR; - } - - resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - for(icmp_seq = 1; icmp_seq <= 4; icmp_seq++) - { - if (at_exec_cmd(resp, "AT+PING=\"%s\"", argv[1]) < 0) - { - rt_kprintf("ping: unknown remote server host\n"); - at_delete_resp(resp); - return -RT_ERROR; - } - - if(at_resp_parse_line_args_by_kw(resp, "+", "+%d", &req_time) < 0) - { - continue; - } - - if (req_time) - { - rt_kprintf("32 bytes from %s icmp_seq=%d time=%d ms\n", argv[1], icmp_seq, req_time); - } - } - - if (resp) - { - at_delete_resp(resp); - } + esp8266_socket_connect, + esp8266_socket_close, + esp8266_socket_send, + esp8266_domain_resolve, + esp8266_socket_set_event_cb, +}; +static int esp8266_netdev_set_up(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_TRUE); + LOG_D("esp8266 network interface set up status."); return RT_EOK; } -int esp8266_ifconfig(int argc, char **argv) +static int esp8266_netdev_set_down(struct netdev *netdev) { -#define AT_ADDR_LEN 128 - int result = RT_EOK; - at_response_t resp = RT_NULL; - char ip[AT_ADDR_LEN], mac[AT_ADDR_LEN]; - char gateway[AT_ADDR_LEN], netmask[AT_ADDR_LEN]; - const char *resp_expr = "%*[^\"]\"%[^\"]\""; - - if (argc != 1) - { - rt_kprintf("Please input: at_ifconfig\n"); - return -RT_ERROR; - } - - rt_memset(ip, 0x00, sizeof(ip)); - rt_memset(mac, 0x00, sizeof(mac)); - rt_memset(gateway, 0x00, sizeof(gateway)); - rt_memset(netmask, 0x00, sizeof(netmask)); + netdev_low_level_set_status(netdev, RT_FALSE); + LOG_D("esp8266 network interface set down status."); + return RT_EOK; +} - resp = at_create_resp(512, 0, rt_tick_from_millisecond(300)); +static int esp8266_netdev_set_addr_info(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw) +{ +#define RESP_SIZE 128 +#define IPV4_ADDR_STRLEN_MAX 16 + at_response_t resp = RT_NULL; + int result = RT_EOK; + char esp8266_ip_addr[IPV4_ADDR_STRLEN_MAX] = {0}; + char esp8266_gw_addr[IPV4_ADDR_STRLEN_MAX] = {0}; + char esp8266_netmask_addr[IPV4_ADDR_STRLEN_MAX] = {0}; + + RT_ASSERT(netdev); + RT_ASSERT(ip_addr || netmask || gw); + + resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300)); if (!resp) { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); - if (at_exec_cmd(resp, "AT+CIFSR") < 0) - { - rt_kprintf("AT send \"AT+CIFSR\" commands error!\n"); - result = -RT_ERROR; + LOG_E("No memory for response structure!"); + result = -RT_ENOMEM; goto __exit; } - if (at_resp_parse_line_args(resp, 2, resp_expr, mac) <= 0) - { - rt_kprintf("Parse error, current line buff : %s\n", at_resp_get_line(resp, 2)); - result = -RT_ERROR; - goto __exit; - } + /* Convert numeric IP address into decimal dotted ASCII representation. */ + if (ip_addr) + rt_memcpy(esp8266_ip_addr, inet_ntoa(*ip_addr), IPV4_ADDR_STRLEN_MAX); + else + rt_memcpy(esp8266_ip_addr, inet_ntoa(netdev->ip_addr), IPV4_ADDR_STRLEN_MAX); - if (at_exec_cmd(resp, "AT+CIPSTA?") < 0) - { - rt_kprintf("AT send \"AT+CIPSTA?\" commands error!\n"); - result = -RT_ERROR; - goto __exit; - } - - if (at_resp_parse_line_args(resp, 1, resp_expr, ip) <= 0 || - at_resp_parse_line_args(resp, 2, resp_expr, gateway) <= 0 || - at_resp_parse_line_args(resp, 3, resp_expr, netmask) <= 0) - { - rt_kprintf("Prase \"AT+CIPSTA?\" commands resposne data error!"); - result = -RT_ERROR; - goto __exit; - } + if (gw) + rt_memcpy(esp8266_gw_addr, inet_ntoa(*gw), IPV4_ADDR_STRLEN_MAX); + else + rt_memcpy(esp8266_gw_addr, inet_ntoa(netdev->gw), IPV4_ADDR_STRLEN_MAX); - rt_kprintf("network interface: esp8266\n"); - rt_kprintf("MAC: %s\n", mac); - rt_kprintf("ip address: %s\n", ip); - rt_kprintf("gw address: %s\n", gateway); - rt_kprintf("net mask : %s\n", netmask); + if (netmask) + rt_memcpy(esp8266_netmask_addr, inet_ntoa(*netmask), IPV4_ADDR_STRLEN_MAX); + else + rt_memcpy(esp8266_netmask_addr, inet_ntoa(netdev->netmask), IPV4_ADDR_STRLEN_MAX); + + /* send addr info set commond "AT+CIPSTA_CUR=[,,]" and wait response */ + if (at_exec_cmd(resp, "AT+CIPSTA_CUR=\"%s\",\"%s\",\"%s\"", esp8266_ip_addr, esp8266_gw_addr, esp8266_netmask_addr) < 0) + { + LOG_E("esp8266 set addr info failed."); + result = -RT_ERROR; + } + else + { + /* Update netdev information */ + if (ip_addr) + netdev_low_level_set_ipaddr(netdev, ip_addr); + + if (gw) + netdev_low_level_set_gw(netdev, gw); + + if (netmask) + netdev_low_level_set_netmask(netdev, netmask); + + LOG_D("esp8266 set addr info successfully."); + } __exit: - rt_mutex_release(at_event_lock); - if (resp) { at_delete_resp(resp); @@ -743,20 +853,273 @@ __exit: return result; } -#ifdef FINSH_USING_MSH -#include -MSH_CMD_EXPORT_ALIAS(esp8266_net_init, at_net_init, initialize AT network); -MSH_CMD_EXPORT_ALIAS(esp8266_ping, at_ping, AT ping network host); -MSH_CMD_EXPORT_ALIAS(esp8266_ifconfig, at_ifconfig, list the information of network interfaces); +static int esp8266_netdev_set_dns_server(struct netdev *netdev, ip_addr_t *dns_server) +{ +#define RESP_SIZE 128 + at_response_t resp = RT_NULL; + int result = RT_EOK; + + RT_ASSERT(netdev); + RT_ASSERT(dns_server); + + resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300)); + if (!resp) + { + LOG_E("No memory for response structure!"); + return -RT_ENOMEM; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send dns server set commond "AT+CIPDNS_CUR=[,,]" and wait response */ + if (at_exec_cmd(resp, "AT+CIPDNS_CUR=1,\"%s\"", inet_ntoa(dns_server)) < 0) + { + LOG_E("set dns server(%s) failed", inet_ntoa(dns_server)); + result = -RT_ERROR; + } + else + { + netdev_low_level_set_dns_server(netdev, 0, dns_server); + LOG_D("esp8266 set dns server successfully."); + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static int esp8266_netdev_set_dhcp(struct netdev *netdev, rt_bool_t is_enabled) +{ +#define ESP8266_STATION 1 +#define RESP_SIZE 128 + + at_response_t resp = RT_NULL; + int result = RT_EOK; + + RT_ASSERT(netdev); + + resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300)); + if (!resp) + { + LOG_E("No memory for response structure!"); + return -RT_ENOMEM; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send dhcp set commond "AT+CWDHCP_CUR=," and wait response */ + if (at_exec_cmd(resp, "AT+CWDHCP_CUR=%d,%d", ESP8266_STATION, is_enabled) < 0) + { + LOG_E("set dhcp status(%d) failed", is_enabled); + result = -RT_ERROR; + goto __exit; + } + else + { + netdev_low_level_set_dhcp_status(netdev, is_enabled); + LOG_D("esp8266 set dhcp successfully."); + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static int esp8266_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp) +{ +#define ESP8266_PING_IP_SIZE 16 + + at_response_t resp = RT_NULL; + rt_err_t result = RT_EOK; + int req_time; + char ip_addr[ESP8266_PING_IP_SIZE] = {0}; + + RT_ASSERT(netdev); + RT_ASSERT(host); + RT_ASSERT(ping_resp); + + resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000)); + if (!resp) + { + LOG_E("No memory for response structure!"); + return -RT_ENOMEM; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send domain commond "AT+CIPDOMAIN=" and wait response */ + if (at_exec_cmd(resp, "AT+CIPDOMAIN=\"%s\"", host) < 0) + { + LOG_E("ping: send commond AT+CIPDOMAIN= failed"); + result = -RT_ERROR; + goto __exit; + } + + /* parse the third line of response data, get the IP address */ + if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", ip_addr) < 0) + { + LOG_E("ping: get the IP address failed"); + result = -RT_ERROR; + goto __exit; + } + + /* send ping commond "AT+PING=" and wait response */ + if (at_exec_cmd(resp, "AT+PING=\"%s\"", host) < 0) + { + LOG_E("ping: unknown remote server host"); + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, "+", "+%d", &req_time) < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (req_time) + { + inet_aton(ip_addr, &(ping_resp->ip_addr)); + ping_resp->data_len = data_len; + ping_resp->ttl = 0; + ping_resp->ticks = req_time; + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +void esp8266_netdev_netstat(struct netdev *netdev) +{ +#define ESP8266_NETSTAT_RESP_SIZE 320 +#define ESP8266_NETSTAT_TYPE_SIZE 4 +#define ESP8266_NETSTAT_IPADDR_SIZE 17 +#define ESP8266_NETSTAT_EXPRESSION "+CIPSTATUS:%*d,\"%[^\"]\",\"%[^\"]\",%d,%d,%*d" + + at_response_t resp = RT_NULL; + rt_err_t result = RT_EOK; + int remote_ip, remote_port, local_port, i; + char *type = RT_NULL; + char *ipaddr = RT_NULL; + + type = rt_calloc(1, ESP8266_NETSTAT_TYPE_SIZE); + ipaddr = rt_calloc(1, ESP8266_NETSTAT_IPADDR_SIZE); + if ((type && ipaddr) == RT_NULL) + { + LOG_E("No memory for response structure!"); + goto __exit; + } + + resp = at_create_resp(ESP8266_NETSTAT_RESP_SIZE, 0, rt_tick_from_millisecond(5000)); + if (!resp) + { + LOG_E("No memory for response structure!"); + goto __exit; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send network connection information commond "AT+CIPSTATUS" and wait response */ + if (at_exec_cmd(resp, "AT+CIPSTATUS") < 0) + { + LOG_E("netstat: send commond AT+CIPSTATUS failed"); + result = -RT_ERROR; + goto __exit; + } + + for (i = 1; i <= resp->line_counts; i++) + { + if (strstr(at_resp_get_line(resp, i), "+CIPSTATUS")) + { + /* parse the third line of response data, get the network connection information */ + if (at_resp_parse_line_args(resp, i, ESP8266_NETSTAT_EXPRESSION, type, ipaddr, &remote_port, &local_port) < 0) + goto __exit; + else + { + LOG_RAW("%s: %s:%d ==> %s:%d\n", type, inet_ntoa(netdev->ip_addr), local_port, ipaddr, remote_port); + } + } + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + if (type) + { + rt_free(type); + } + + if (ipaddr) + { + rt_free(ipaddr); + } + + rt_mutex_release(at_event_lock); +} + +const struct netdev_ops esp8266_netdev_ops = +{ + esp8266_netdev_set_up, + esp8266_netdev_set_down, + + esp8266_netdev_set_addr_info, + esp8266_netdev_set_dns_server, + esp8266_netdev_set_dhcp, + + esp8266_netdev_ping, + esp8266_netdev_netstat, +}; + +static struct netdev *esp8266_netdev_add(const char *netdev_name) +{ +#define ETHERNET_MTU 1500 +#define HWADDR_LEN 6 + struct netdev *netdev = RT_NULL; + + RT_ASSERT(netdev_name); + + netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return RT_NULL; + } + + netdev->mtu = ETHERNET_MTU; + netdev->ops = &esp8266_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 -static const struct at_device_ops esp8266_socket_ops = { - esp8266_socket_connect, - esp8266_socket_close, - esp8266_socket_send, - esp8266_domain_resolve, - esp8266_socket_set_event_cb, -}; + netdev_register(netdev, netdev_name, RT_NULL); + + return netdev; +} static int at_socket_device_init(void) { @@ -783,6 +1146,12 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); + /* Add esp8266 to the netdev list */ + esp8266_netdev_add(ESP8266_NETDEV_NAME); + + /* initialize esp8266 net workqueue */ + rt_delayed_work_init(&esp8266_net_work, exp8266_get_netdev_info, (void *)netdev_get_by_name(ESP8266_NETDEV_NAME)); + /* initialize esp8266 network */ esp8266_net_init(); diff --git a/at_socket_m26.c b/at_socket_m26.c index 2ae84ea..ee5d88e 100644 --- a/at_socket_m26.c +++ b/at_socket_m26.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include @@ -40,6 +42,8 @@ #ifdef AT_DEVICE_M26 +#define M26_NETDEV_NAME "m26" + #define M26_MODULE_SEND_MAX_SIZE 1460 #define M26_WAIT_CONNECT_TIME 5000 #define M26_THREAD_STACK_SIZE 1024 @@ -100,6 +104,9 @@ static int m26_socket_close(int socket) rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); cur_socket = socket; + /* Clear socket close event */ + at_socket_event_recv(SET_EVENT(socket, M26_EVNET_CLOSE_OK), 0, RT_EVENT_FLAG_OR); + if (at_exec_cmd(RT_NULL, "AT+QICLOSE=%d", socket) < 0) { result = -RT_ERROR; @@ -147,6 +154,9 @@ static int m26_socket_connect(int socket, char *ip, int32_t port, enum at_socket __retry: + /* Clear socket connect event */ + at_socket_event_recv(SET_EVENT(socket, M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR); + if (is_client) { switch (type) @@ -175,14 +185,14 @@ __retry: } /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(10 * 1000), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { LOG_E("socket (%d) connect failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL, rt_tick_from_millisecond(1 * 1000), + if ((event_result = at_socket_event_recv(M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket); @@ -216,7 +226,7 @@ __exit: static int at_get_send_size(int socket, size_t *size, size_t *acked, size_t *nacked) { - at_response_t resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000)); + at_response_t resp = at_create_resp(64, 0, 5 * RT_TICK_PER_SECOND); int result = 0; if (!resp) @@ -288,7 +298,7 @@ static int m26_socket_send(int socket, const char *buff, size_t bfsz, enum at_so RT_ASSERT(buff); - resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000)); + resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -297,6 +307,9 @@ static int m26_socket_send(int socket, const char *buff, size_t bfsz, enum at_so rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* Clear socket send event */ + at_socket_event_recv(SET_EVENT(socket, M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR); + /* set current socket for send URC event */ cur_socket = socket; /* set AT client end sign to deal with '>' sign.*/ @@ -329,14 +342,14 @@ static int m26_socket_send(int socket, const char *buff, size_t bfsz, enum at_so } /* waiting result event from AT URC */ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(300*3), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { LOG_E("socket (%d) send failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL, rt_tick_from_millisecond(1 * 1000), + if ((event_result = at_socket_event_recv(M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket); @@ -397,7 +410,7 @@ static int m26_domain_resolve(const char *name, char ip[16]) RT_ASSERT(ip); /* The maximum response time is 14 seconds, affected by network status */ - resp = at_create_resp(128, 4, rt_tick_from_millisecond(14 * 1000)); + resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -417,14 +430,14 @@ static int m26_domain_resolve(const char *name, char ip[16]) /* parse the third line of response data, get the IP address */ if(at_resp_parse_line_args_by_kw(resp, ".", "%s", recv_ip) < 0) { - rt_thread_delay(rt_tick_from_millisecond(100)); + rt_thread_mdelay(100); /* resolve failed, maybe receive an URC CRLF */ continue; } if (strlen(recv_ip) < 8) { - rt_thread_delay(rt_tick_from_millisecond(100)); + rt_thread_mdelay(100); /* resolve failed, maybe receive an URC CRLF */ continue; } @@ -567,39 +580,6 @@ static void urc_recv_func(const char *data, rt_size_t size) } } -static void urc_ping_func(const char *data, rt_size_t size) -{ - static int icmp_seq = 0; - int result, recv_len, time, ttl; - char dst_ip[16] = { 0 }; - - RT_ASSERT(data); - - sscanf(data, "+QPING: %d,%[^,],%d,%d,%d", &result, dst_ip, &recv_len, &time, &ttl); - - switch(result) - { - case 0: - rt_kprintf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n", recv_len, dst_ip, icmp_seq++, ttl, time); - break; - case 1: - rt_kprintf("ping request timeout!\n"); - break; - case 2: - icmp_seq = 0; - break; - case 3: - rt_kprintf("ping: TCP/IP protocol stack is busy\n"); - break; - case 4: - rt_kprintf("ping: unknown remote server host\n"); - break; - default: - break; - } - -} - static void urc_func(const char *data, rt_size_t size) { RT_ASSERT(data); @@ -619,7 +599,6 @@ static const struct at_urc urc_table[] = { {"", ", CLOSE OK\r\n", urc_close_func}, {"", ", CLOSED\r\n", urc_close_func}, {"+RECEIVE:", "\r\n", urc_recv_func}, - {"+QPING:", "\r\n", urc_ping_func}, }; #define AT_SEND_CMD(resp, resp_line, timeout, cmd) \ @@ -632,6 +611,9 @@ static const struct at_urc urc_table[] = { } \ } while(0); \ +static int m26_netdev_set_info(struct netdev *netdev); +static int m26_netdev_check_link_status(struct netdev *netdev); + /* init for M26 or MC20 */ static void m26_init_thread_entry(void *parameter) { @@ -656,6 +638,7 @@ static void m26_init_thread_entry(void *parameter) /* wait M26 startup finish */ if (at_client_wait_connect(M26_WAIT_CONNECT_TIME)) { + LOG_E("AT device connection error."); result = -RT_ETIMEOUT; goto __exit; } @@ -671,14 +654,14 @@ static void m26_init_thread_entry(void *parameter) /* check SIM card */ for (i = 0; i < CPIN_RETRY; i++) { - at_exec_cmd(at_resp_set_info(resp, 128, 2, rt_tick_from_millisecond(5000)), "AT+CPIN?"); + at_exec_cmd(at_resp_set_info(resp, 128, 2, 5 * RT_TICK_PER_SECOND), "AT+CPIN?"); if (at_resp_get_line_by_kw(resp, "READY")) { LOG_D("SIM card detection success"); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CPIN_RETRY) { @@ -687,7 +670,7 @@ static void m26_init_thread_entry(void *parameter) goto __exit; } /* waiting for dirty data to be digested */ - rt_thread_delay(rt_tick_from_millisecond(10)); + rt_thread_mdelay(10); /* check signal strength */ for (i = 0; i < CSQ_RETRY; i++) { @@ -698,7 +681,7 @@ static void m26_init_thread_entry(void *parameter) LOG_D("Signal strength: %s", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CSQ_RETRY) { @@ -716,7 +699,7 @@ static void m26_init_thread_entry(void *parameter) LOG_D("GSM network is registered (%s)", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CREG_RETRY) { @@ -734,7 +717,7 @@ static void m26_init_thread_entry(void *parameter) LOG_D("GPRS network is registered (%s)", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CGREG_RETRY) { @@ -779,13 +762,15 @@ __exit: if (!result) { + m26_netdev_set_info(netdev_get_by_name(M26_NETDEV_NAME)); + m26_netdev_check_link_status(netdev_get_by_name(M26_NETDEV_NAME)); + LOG_I("AT network initialize success!"); } else { LOG_E("AT network initialize failed (%d)!", result); } - } int m26_net_init(void) @@ -809,83 +794,9 @@ int m26_net_init(void) return RT_EOK; } -int m26_ping(int argc, char **argv) -{ - at_response_t resp = RT_NULL; - - if (argc != 2) - { - rt_kprintf("Please input: at_ping \n"); - return -RT_ERROR; - } - - resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - if (at_exec_cmd(resp, "AT+QPING=\"%s\"", argv[1]) < 0) - { - rt_kprintf("AT send ping commands error!\n"); - return -RT_ERROR; - } - - if (resp) - { - at_delete_resp(resp); - } - - return RT_EOK; -} - -int m26_ifconfig(void) -{ - at_response_t resp = RT_NULL; - char resp_arg[AT_CMD_MAX_LEN] = { 0 }; - const char * resp_expr = "%s"; - rt_err_t result = RT_EOK; - - resp = at_create_resp(64, 2, rt_tick_from_millisecond(300)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - if (at_exec_cmd(resp, "AT+QILOCIP") < 0) - { - rt_kprintf("AT send ip commands error!\n"); - result = RT_ERROR; - goto __exit; - } - - if (at_resp_parse_line_args(resp, 2, resp_expr, resp_arg) == 1) - { - rt_kprintf("IP address : %s\n", resp_arg); - } - else - { - rt_kprintf("Parse error, current line buff : %s\n", at_resp_get_line(resp, 2)); - result = RT_ERROR; - goto __exit; - } - -__exit: - if (resp) - { - at_delete_resp(resp); - } - - return result; -} - #ifdef FINSH_USING_MSH #include MSH_CMD_EXPORT_ALIAS(m26_net_init, at_net_init, initialize AT network); -MSH_CMD_EXPORT_ALIAS(m26_ping, at_ping, AT ping network host); -MSH_CMD_EXPORT_ALIAS(m26_ifconfig, at_ifconfig, list the information of network interfaces); #endif static const struct at_device_ops m26_socket_ops = { @@ -896,6 +807,396 @@ static const struct at_device_ops m26_socket_ops = { m26_socket_set_event_cb, }; + +/* set m26 network interface device status and address information */ +static int m26_netdev_set_info(struct netdev *netdev) +{ +#define M26_IEMI_RESP_SIZE 32 +#define M26_IPADDR_RESP_SIZE 32 +#define M26_DNS_RESP_SIZE 96 +#define M26_INFO_RESP_TIMO rt_tick_from_millisecond(300) + + int result = RT_EOK; + at_response_t resp = RT_NULL; + ip_addr_t addr; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* set network interface device up status */ + netdev_low_level_set_status(netdev, RT_TRUE); + netdev_low_level_set_dhcp_status(netdev, RT_TRUE); + + resp = at_create_resp(M26_IEMI_RESP_SIZE, 0, M26_INFO_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("M26 set IP address failed, no memory for response object."); + result = -RT_ENOMEM; + goto __exit; + } + + /* set network interface device hardware address(IEMI) */ + { + #define M26_NETDEV_HWADDR_LEN 8 + #define M26_IEMI_LEN 15 + + char iemi[M26_IEMI_LEN] = {0}; + int i = 0, j = 0; + + /* send "AT+GSN" commond to get device IEMI */ + if (at_exec_cmd(resp, "AT+GSN") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0) + { + LOG_E("Prase \"AT+GSN\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("M26 IEMI number: %s", iemi); + + netdev->hwaddr_len = M26_NETDEV_HWADDR_LEN; + /* get hardware address by IEMI */ + for (i = 0, j = 0; i < M26_NETDEV_HWADDR_LEN && j < M26_IEMI_LEN; i++, j+=2) + { + if (j != M26_IEMI_LEN - 1) + { + netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0'); + } + else + { + netdev->hwaddr[i] = (iemi[j] - '0'); + } + } + } + + /* set network interface device IP address */ + { + #define IP_ADDR_SIZE_MAX 16 + char ipaddr[IP_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, M26_IPADDR_RESP_SIZE, 2, M26_INFO_RESP_TIMO); + + /* send "AT+QILOCIP" commond to get IP address */ + if (at_exec_cmd(resp, "AT+QILOCIP") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0) + { + LOG_E("Prase \"AT+QILOCIP\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("M26 IP address: %s", ipaddr); + + /* set network interface address information */ + inet_aton(ipaddr, &addr); + netdev_low_level_set_ipaddr(netdev, &addr); + } + + /* set network interface device dns server */ + { + #define DNS_ADDR_SIZE_MAX 16 + char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, M26_DNS_RESP_SIZE, 0, M26_INFO_RESP_TIMO); + + /* send "AT+QIDNSCFG?" commond to get DNS servers address */ + if (at_exec_cmd(resp, "AT+QIDNSCFG?") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 || + at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0) + { + LOG_E("Prase \"AT+QIDNSCFG?\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("M26 primary DNS server address: %s", dns_server1); + LOG_D("M26 secondary DNS server address: %s", dns_server2); + + inet_aton(dns_server1, &addr); + netdev_low_level_set_dns_server(netdev, 0, &addr); + + inet_aton(dns_server2, &addr); + netdev_low_level_set_dns_server(netdev, 1, &addr); + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static void check_link_status_entry(void *parameter) +{ +#define M26_LINK_STATUS_OK 0 +#define M26_LINK_RESP_SIZE 64 +#define M26_LINK_RESP_TIMO (3 * RT_TICK_PER_SECOND) +#define M26_LINK_DELAY_TIME (30 * RT_TICK_PER_SECOND) + + struct netdev *netdev = (struct netdev *)parameter; + at_response_t resp = RT_NULL; + int link_status; + + resp = at_create_resp(M26_LINK_RESP_SIZE, 0, M26_LINK_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("m26 set check link status failed, no memory for response object."); + return; + } + + while (1) + { + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send "AT+QNSTATUS" commond to check netweork interface device link status */ + if (at_exec_cmd(resp, "AT+QNSTATUS") < 0) + { + rt_mutex_release(at_event_lock); + rt_thread_mdelay(M26_LINK_DELAY_TIME); + + continue; + } + + link_status = -1; + at_resp_parse_line_args_by_kw(resp, "+QNSTATUS:", "+QNSTATUS: %d", &link_status); + + /* check the network interface device link status */ + if ((M26_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev)) + { + netdev_low_level_set_link_status(netdev, (M26_LINK_STATUS_OK == link_status)); + } + + rt_mutex_release(at_event_lock); + rt_thread_mdelay(M26_LINK_DELAY_TIME); + } +} + +static int m26_netdev_check_link_status(struct netdev *netdev) +{ +#define M26_LINK_THREAD_STACK_SIZE 512 +#define M26_LINK_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2) +#define M26_LINK_THREAD_TICK 20 + + rt_thread_t tid; + char tname[RT_NAME_MAX]; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + rt_memset(tname, 0x00, sizeof(tname)); + rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name); + + tid = rt_thread_create(tname, check_link_status_entry, (void *)netdev, + M26_LINK_THREAD_STACK_SIZE, M26_LINK_THREAD_PRIORITY, M26_LINK_THREAD_TICK); + if (tid) + { + rt_thread_startup(tid); + } + + return RT_EOK; +} + +static int m26_netdev_set_up(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_TRUE); + LOG_D("The network interface device(%s) set up status", netdev->name); + + return RT_EOK; +} + +static int m26_netdev_set_down(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_FALSE); + LOG_D("The network interface device(%s) set down status", netdev->name); + return RT_EOK; +} + +static int m26_netdev_set_dns_server(struct netdev *netdev, ip_addr_t *dns_server) +{ +#define M26_DNS_RESP_LEN 8 +#define M26_DNS_RESP_TIMEO rt_tick_from_millisecond(300) + + at_response_t resp = RT_NULL; + int result = RT_EOK; + + RT_ASSERT(netdev); + RT_ASSERT(dns_server); + + resp = at_create_resp(M26_DNS_RESP_LEN, 0, M26_DNS_RESP_TIMEO); + if (resp == RT_NULL) + { + LOG_E("m26 set dns server failed, no memory for response object."); + return -RT_ENOMEM; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send "AT+QIDNSCFG=[,]" commond to set dns servers */ + if (at_exec_cmd(resp, "AT+QIDNSCFG=\"%s\"", inet_ntoa(dns_server)) < 0) + { + result = -RT_ERROR; + goto __exit; + } + + netdev_low_level_set_dns_server(netdev, 0, dns_server); + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static int m26_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp) +{ +#define M26_PING_RESP_SIZE 128 +#define M26_PING_IP_SIZE 16 +#define M26_PING_TIMEO (5 * RT_TICK_PER_SECOND) + + int result = RT_EOK; + at_response_t resp = RT_NULL; + char ip_addr[M26_PING_IP_SIZE] = {0}; + int response, recv_data_len, time, ttl; + + RT_ASSERT(netdev); + RT_ASSERT(host); + RT_ASSERT(ping_resp); + + resp = at_create_resp(M26_PING_RESP_SIZE, 5, M26_PING_TIMEO); + if (resp == RT_NULL) + { + LOG_E("m26 set dns server failed, no memory for response object."); + return -RT_ENOMEM; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send "AT+QPING=""[,[][,]]" commond to send ping request */ + if (at_exec_cmd(resp, "AT+QPING=\"%s\",%d,1", host, M26_PING_TIMEO / 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, &time, &ttl) <= 0) + { + LOG_E("Prase \"AT+QPING\" commands resposne data error!"); + 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 = time; + ping_resp->ttl = ttl; + result = RT_EOK; + break; + case 1: + result = -RT_ETIMEOUT; + break; + default: + result = -RT_ERROR; + break; + } + + __exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +void m26_netdev_netstat(struct netdev *netdev) +{ + // TODO netstat support +} + +const struct netdev_ops m26_netdev_ops = +{ + m26_netdev_set_up, + m26_netdev_set_down, + + RT_NULL, /* not support set ip, netmask, gatway address */ + m26_netdev_set_dns_server, + RT_NULL, /* not support set DHCP status */ + + m26_netdev_ping, + m26_netdev_netstat, +}; + +static int m26_netdev_add(const char *netdev_name) +{ +#define M26_NETDEV_MTU 1500 + + struct netdev *netdev = RT_NULL; + + RT_ASSERT(netdev_name); + + netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return RT_NULL; + } + + netdev->mtu = M26_NETDEV_MTU; + netdev->ops = &m26_netdev_ops; + +#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 + + return netdev_register(netdev, netdev_name, RT_NULL); +} + static int at_socket_device_init(void) { /* create current AT socket event */ @@ -921,6 +1222,13 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); + /* add network interface device to netdev list */ + if (m26_netdev_add(M26_NETDEV_NAME) < 0) + { + LOG_E("M26 network interface device(%d) add failed.", M26_NETDEV_NAME); + return -RT_ENOMEM; + } + /* initialize m26 network */ m26_net_init(); diff --git a/at_socket_rw007.c b/at_socket_rw007.c index 726bfbf..8fd83b9 100644 --- a/at_socket_rw007.c +++ b/at_socket_rw007.c @@ -29,6 +29,7 @@ #include #include +#include #include #if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200 @@ -40,6 +41,8 @@ #ifdef AT_DEVICE_RW007 +#define RW007_NETDEV_NAME "rw007" + #define RW007_MODULE_SEND_MAX_SIZE 2048 #define RW007_WAIT_CONNECT_TIME 5000 #define RW007_THREAD_STACK_SIZE 1024 @@ -682,6 +685,43 @@ static const struct at_device_ops rw007_socket_ops = { rw007_socket_set_event_cb, }; +static int rw007_netdev_add(const char *netdev_name) +{ +#define ETHERNET_MTU 1500 +#define HWADDR_LEN 8 + struct netdev *netdev = RT_NULL; + int result = 0; + + RT_ASSERT(netdev_name); + + netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return RT_NULL; + } + + /* TODO: improve netdev adaptation */ + netdev->mtu = ETHERNET_MTU; + netdev->hwaddr_len = HWADDR_LEN; + netdev->ops = RT_NULL; + +#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 + + result = netdev_register(netdev, netdev_name, RT_NULL); + + /*TODO: improve netdev adaptation */ + 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); + netdev->flags |= NETDEV_FLAG_INTERNET_UP; + + return result; +} + static int at_socket_device_init(void) { /* create current AT socket event */ @@ -707,6 +747,13 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); + /* add network interface device to netdev list */ + if (rw007_netdev_add(RW007_NETDEV_NAME) < 0) + { + LOG_E("RW007 network interface device(%d) add failed.", RW007_NETDEV_NAME); + return -RT_ENOMEM; + } + /* initialize rw007 network */ rw007_net_init(); diff --git a/at_socket_sim76xx.c b/at_socket_sim76xx.c index cb6dd28..3e10458 100755 --- a/at_socket_sim76xx.c +++ b/at_socket_sim76xx.c @@ -31,6 +31,7 @@ #include #include +#include #include #if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200 @@ -42,6 +43,8 @@ #ifdef AT_DEVICE_SIM76XX +#define SIM76XX_NETDEV_NAME "sim76xx" + #define SIM76XX_MODULE_SEND_MAX_SIZE 1500 #define SIM76XX_WAIT_CONNECT_TIME 5000 #define SIM76XX_THREAD_STACK_SIZE 1024 @@ -129,7 +132,6 @@ static int sim76xx_socket_close(int socket) at_response_t resp = RT_NULL; int result = RT_EOK; int activated; - uint8_t s; uint8_t lnk_stat[10]; resp = at_create_resp(128, 0, rt_tick_from_millisecond(500)); @@ -1132,6 +1134,42 @@ static const struct at_device_ops sim76xx_socket_ops = { sim76xx_socket_set_event_cb, }; +static int sim76xx_netdev_add(const char *netdev_name) +{ +#define ETHERNET_MTU 1500 +#define HWADDR_LEN 8 + struct netdev *netdev = RT_NULL; + int result = 0; + + RT_ASSERT(netdev_name); + + netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return RT_NULL; + } + + netdev->mtu = ETHERNET_MTU; + netdev->hwaddr_len = HWADDR_LEN; + netdev->ops = RT_NULL; + +#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 + + result = netdev_register(netdev, netdev_name, RT_NULL); + + /*TODO: improve netdev adaptation */ + 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); + netdev->flags |= NETDEV_FLAG_INTERNET_UP; + + return result; +} + static int at_socket_device_init(void) { /* create current AT socket event */ @@ -1157,6 +1195,13 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); + /* add network interface device to netdev list */ + if (sim76xx_netdev_add(SIM76XX_NETDEV_NAME) < 0) + { + LOG_E("SIM76xx network interface device(%d) add failed.", SIM76XX_NETDEV_NAME); + return -RT_ENOMEM; + } + /* initialize sim76xx pin config */ rt_pin_mode(AT_DEVICE_POWER_PIN, PIN_MODE_OUTPUT); rt_pin_mode(AT_DEVICE_STATUS_PIN, PIN_MODE_INPUT); diff --git a/at_socket_sim800c.c b/at_socket_sim800c.c index 3da3f32..c9e0337 100644 --- a/at_socket_sim800c.c +++ b/at_socket_sim800c.c @@ -21,6 +21,7 @@ * Date Author Notes * 2018-06-12 malongwei first version */ + #include #include @@ -28,6 +29,8 @@ #include #include +#include + #include #include @@ -40,6 +43,7 @@ #ifdef AT_DEVICE_SIM800C +#define SIM800C_NETDEV_NAME "sim800c" #define SIM800C_MODULE_SEND_MAX_SIZE 1000 #define SIM800C_WAIT_CONNECT_TIME 5000 @@ -107,6 +111,9 @@ static int sim800c_socket_close(int socket) rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); cur_socket = socket; + /* Clear socket close event */ + at_socket_event_recv(SET_EVENT(socket, SIM800C_EVNET_CLOSE_OK), 0, RT_EVENT_FLAG_OR); + if (at_exec_cmd(RT_NULL, "AT+CIPCLOSE=%d", socket) < 0) { result = -RT_ERROR; @@ -154,6 +161,9 @@ static int sim800c_socket_connect(int socket, char *ip, int32_t port, enum at_so __retry: + /* Clear socket connect event */ + at_socket_event_recv(SET_EVENT(socket, SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR); + if (is_client) { switch (type) @@ -179,19 +189,18 @@ __retry: LOG_E("Not supported connect type : %d.", type); result = -RT_ERROR; goto __exit; - break; } } /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(10 * 1000), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { LOG_E("socket (%d) connect failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL, rt_tick_from_millisecond(1 * 1000), + if ((event_result = at_socket_event_recv(SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket); @@ -244,7 +253,7 @@ static int sim800c_socket_send(int socket, const char *buff, size_t bfsz, enum a RT_ASSERT(buff); - resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000)); + resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -253,6 +262,9 @@ static int sim800c_socket_send(int socket, const char *buff, size_t bfsz, enum a rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + /* Clear socket connect event */ + at_socket_event_recv(SET_EVENT(socket, SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR); + /* set current socket for send URC event */ cur_socket = socket; /* set AT client end sign to deal with '>' sign.*/ @@ -285,14 +297,14 @@ static int sim800c_socket_send(int socket, const char *buff, size_t bfsz, enum a } /* waiting result event from AT URC */ - if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(5 * 1000), RT_EVENT_FLAG_OR) < 0) + if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0) { LOG_E("socket (%d) send failed, wait connect result timeout.", socket); result = -RT_ETIMEOUT; goto __exit; } /* waiting OK or failed result */ - if ((event_result = at_socket_event_recv(SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL, rt_tick_from_millisecond(5 * 1000), + if ((event_result = at_socket_event_recv(SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL, 5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0) { LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket); @@ -353,7 +365,7 @@ static int sim800c_domain_resolve(const char *name, char ip[16]) RT_ASSERT(ip); /* The maximum response time is 14 seconds, affected by network status */ - resp = at_create_resp(128, 4, rt_tick_from_millisecond(14 * 1000)); + resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND); if (!resp) { LOG_E("No memory for response structure!"); @@ -362,25 +374,38 @@ static int sim800c_domain_resolve(const char *name, char ip[16]) rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); - for(i = 0; i < RESOLVE_RETRY; i++) + for (i = 0; i < RESOLVE_RETRY; i++) { + int err_code = 0; + if (at_exec_cmd(resp, "AT+CDNSGIP=\"%s\"", name) < 0) { result = -RT_ERROR; goto __exit; } - /* parse the third line of response data, get the IP address */ - if(at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0) + /* domain name prase error options */ + if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP: 0", "+CDNSGIP: 0,%d", &err_code) > 0) { - rt_thread_delay(rt_tick_from_millisecond(100)); + /* 3 - network error, 8 - dns common error */ + if (err_code == 3 || err_code == 8) + { + result = -RT_ERROR; + goto __exit; + } + } + + /* parse the third line of response data, get the IP address */ + if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0) + { + rt_thread_mdelay(100); /* resolve failed, maybe receive an URC CRLF */ continue; } if (strlen(recv_ip) < 8) { - rt_thread_delay(rt_tick_from_millisecond(100)); + rt_thread_mdelay(100); /* resolve failed, maybe receive an URC CRLF */ continue; } @@ -560,7 +585,7 @@ static void sim800c_power_on(void) rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH); while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_LOW) { - rt_thread_delay(rt_tick_from_millisecond(10)); + rt_thread_mdelay(10); } rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW); } @@ -572,11 +597,14 @@ static void sim800c_power_off(void) rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH); while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_HIGH) { - rt_thread_delay(rt_tick_from_millisecond(10)); + rt_thread_mdelay(10); } rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW); } +static int sim800c_netdev_set_info(struct netdev *netdev); +static int sim800c_netdev_check_link_status(struct netdev *netdev); + /* init for SIM800C */ static void sim800c_init_thread_entry(void *parameter) { @@ -596,9 +624,9 @@ static void sim800c_init_thread_entry(void *parameter) { result = RT_EOK; rt_memset(parsed_data, 0, sizeof(parsed_data)); - rt_thread_delay(rt_tick_from_millisecond(500)); + rt_thread_mdelay(500); sim800c_power_on(); - rt_thread_delay(rt_tick_from_millisecond(2000)); + rt_thread_mdelay(2000); resp = at_create_resp(128, 0, rt_tick_from_millisecond(300)); if (!resp) { @@ -625,14 +653,14 @@ static void sim800c_init_thread_entry(void *parameter) /* check SIM card */ for (i = 0; i < CPIN_RETRY; i++) { - at_exec_cmd(at_resp_set_info(resp, 128, 2, rt_tick_from_millisecond(5000)), "AT+CPIN?"); + at_exec_cmd(at_resp_set_info(resp, 128, 2, 5 * RT_TICK_PER_SECOND), "AT+CPIN?"); if (at_resp_get_line_by_kw(resp, "READY")) { LOG_D("SIM card detection success"); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CPIN_RETRY) { @@ -641,7 +669,7 @@ static void sim800c_init_thread_entry(void *parameter) goto __exit; } /* waiting for dirty data to be digested */ - rt_thread_delay(rt_tick_from_millisecond(10)); + rt_thread_mdelay(10); /* check the GSM network is registered */ for (i = 0; i < CREG_RETRY; i++) @@ -653,7 +681,7 @@ static void sim800c_init_thread_entry(void *parameter) LOG_D("GSM network is registered (%s)", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CREG_RETRY) { @@ -671,7 +699,7 @@ static void sim800c_init_thread_entry(void *parameter) LOG_D("GPRS network is registered (%s)", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CGREG_RETRY) { @@ -690,7 +718,7 @@ static void sim800c_init_thread_entry(void *parameter) LOG_D("Signal strength: %s", parsed_data); break; } - rt_thread_delay(rt_tick_from_millisecond(1000)); + rt_thread_mdelay(1000); } if (i == CSQ_RETRY) { @@ -759,7 +787,13 @@ static void sim800c_init_thread_entry(void *parameter) LOG_E("AT network initialize failed (%d)!", result); sim800c_power_off(); } + + rt_thread_mdelay(1000); } + + /* set network interface device status and address information */ + sim800c_netdev_set_info(netdev_get_by_name(SIM800C_NETDEV_NAME)); + sim800c_netdev_check_link_status(netdev_get_by_name(SIM800C_NETDEV_NAME)); } int sim800c_net_init(void) @@ -783,61 +817,9 @@ int sim800c_net_init(void) return RT_EOK; } -int sim800c_ping(int argc, char **argv) -{ - LOG_E("This device does not support Ping!"); - return RT_EOK; -} - -int sim800c_ifconfig(void) -{ - at_response_t resp = RT_NULL; - char resp_arg[AT_CMD_MAX_LEN] = { 0 }; - const char * resp_expr = "%s"; - rt_err_t result = RT_EOK; - - resp = at_create_resp(64, 2, rt_tick_from_millisecond(300)); - if (!resp) - { - rt_kprintf("No memory for response structure!\n"); - return -RT_ENOMEM; - } - - rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); - if (at_exec_cmd(resp, "AT+CIFSR") < 0) - { - rt_kprintf("AT send ip commands error!\n"); - result = RT_ERROR; - goto __exit; - } - - if (at_resp_parse_line_args(resp, 2, resp_expr, resp_arg) == 1) - { - rt_kprintf("IP address : %s\n", resp_arg); - } - else - { - rt_kprintf("Parse error, current line buff : %s\n", at_resp_get_line(resp, 2)); - result = RT_ERROR; - goto __exit; - } - -__exit: - rt_mutex_release(at_event_lock); - - if (resp) - { - at_delete_resp(resp); - } - - return result; -} - #ifdef FINSH_USING_MSH #include MSH_CMD_EXPORT_ALIAS(sim800c_net_init, at_net_init, initialize AT network); -MSH_CMD_EXPORT_ALIAS(sim800c_ping, at_ping, AT ping network host); -MSH_CMD_EXPORT_ALIAS(sim800c_ifconfig, at_ifconfig, list the information of network interfaces); #endif static const struct at_device_ops sim800c_socket_ops = { @@ -848,6 +830,400 @@ static const struct at_device_ops sim800c_socket_ops = { sim800c_socket_set_event_cb, }; +/* set sim800c network interface device status and address information */ +static int sim800c_netdev_set_info(struct netdev *netdev) +{ +#define SIM800C_IEMI_RESP_SIZE 32 +#define SIM800C_IPADDR_RESP_SIZE 32 +#define SIM800C_DNS_RESP_SIZE 96 +#define SIM800C_INFO_RESP_TIMO rt_tick_from_millisecond(300) + + int result = RT_EOK; + at_response_t resp = RT_NULL; + ip_addr_t addr; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* 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(SIM800C_IEMI_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("SIM800C set IP address failed, no memory for response object."); + result = -RT_ENOMEM; + goto __exit; + } + + /* set network interface device hardware address(IEMI) */ + { + #define SIM800C_NETDEV_HWADDR_LEN 8 + #define SIM800C_IEMI_LEN 15 + + char iemi[SIM800C_IEMI_LEN] = {0}; + int i = 0, j = 0; + + /* send "AT+GSN" commond to get device IEMI */ + if (at_exec_cmd(resp, "AT+GSN") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0) + { + LOG_E("Prase \"AT+GSN\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("SIM800C IEMI number: %s", iemi); + + netdev->hwaddr_len = SIM800C_NETDEV_HWADDR_LEN; + /* get hardware address by IEMI */ + for (i = 0, j = 0; i < SIM800C_NETDEV_HWADDR_LEN && j < SIM800C_IEMI_LEN; i++, j+=2) + { + if (j != SIM800C_IEMI_LEN - 1) + { + netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0'); + } + else + { + netdev->hwaddr[i] = (iemi[j] - '0'); + } + } + } + + /* set network interface device IP address */ + { + #define IP_ADDR_SIZE_MAX 16 + char ipaddr[IP_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, SIM800C_IPADDR_RESP_SIZE, 2, SIM800C_INFO_RESP_TIMO); + + /* send "AT+CIFSR" commond to get IP address */ + if (at_exec_cmd(resp, "AT+CIFSR") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0) + { + LOG_E("Prase \"AT+CIFSR\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("SIM800C IP address: %s", ipaddr); + + /* set network interface address information */ + inet_aton(ipaddr, &addr); + netdev_low_level_set_ipaddr(netdev, &addr); + } + + /* set network interface device dns server */ + { + #define DNS_ADDR_SIZE_MAX 16 + char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0}; + + at_resp_set_info(resp, SIM800C_DNS_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO); + + /* send "AT+CDNSCFG?" commond to get DNS servers address */ + if (at_exec_cmd(resp, "AT+CDNSCFG?") < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 || + at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0) + { + LOG_E("Prase \"AT+CDNSCFG?\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + LOG_D("SIM800C primary DNS server address: %s", dns_server1); + LOG_D("SIM800C secondary DNS server address: %s", dns_server2); + + inet_aton(dns_server1, &addr); + netdev_low_level_set_dns_server(netdev, 0, &addr); + + inet_aton(dns_server2, &addr); + netdev_low_level_set_dns_server(netdev, 1, &addr); + } + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static void check_link_status_entry(void *parameter) +{ +#define SIM800C_LINK_STATUS_OK 1 +#define SIM800C_LINK_RESP_SIZE 64 +#define SIM800C_LINK_RESP_TIMO (3 * RT_TICK_PER_SECOND) +#define SIM800C_LINK_DELAY_TIME (30 * RT_TICK_PER_SECOND) + + struct netdev *netdev = (struct netdev *)parameter; + at_response_t resp = RT_NULL; + int result_code, link_status; + + resp = at_create_resp(SIM800C_LINK_RESP_SIZE, 0, SIM800C_LINK_RESP_TIMO); + if (resp == RT_NULL) + { + LOG_E("sim800c set check link status failed, no memory for response object."); + return; + } + + while (1) + { + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + /* send "AT+CGREG?" commond to check netweork interface device link status */ + if (at_exec_cmd(resp, "AT+CGREG?") < 0) + { + rt_mutex_release(at_event_lock); + rt_thread_mdelay(SIM800C_LINK_DELAY_TIME); + + continue; + } + + link_status = -1; + at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %d,%d", &result_code, &link_status); + + /* check the network interface device link status */ + if ((SIM800C_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev)) + { + netdev_low_level_set_link_status(netdev, (SIM800C_LINK_STATUS_OK == link_status)); + } + + rt_mutex_release(at_event_lock); + rt_thread_mdelay(SIM800C_LINK_DELAY_TIME); + } +} + +static int sim800c_netdev_check_link_status(struct netdev *netdev) +{ +#define SIM800C_LINK_THREAD_STACK_SIZE 512 +#define SIM800C_LINK_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2) +#define SIM800C_LINK_THREAD_TICK 20 + + rt_thread_t tid; + char tname[RT_NAME_MAX]; + + if (netdev == RT_NULL) + { + LOG_E("Input network interface device is NULL.\n"); + return -RT_ERROR; + } + + rt_memset(tname, 0x00, sizeof(tname)); + rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name); + + tid = rt_thread_create(tname, check_link_status_entry, (void *)netdev, + SIM800C_LINK_THREAD_STACK_SIZE, SIM800C_LINK_THREAD_PRIORITY, SIM800C_LINK_THREAD_TICK); + if (tid) + { + rt_thread_startup(tid); + } + + return RT_EOK; +} + +static int sim800c_netdev_set_up(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_TRUE); + LOG_D("The network interface device(%s) set up status", netdev->name); + + return RT_EOK; +} + +static int sim800c_netdev_set_down(struct netdev *netdev) +{ + netdev_low_level_set_status(netdev, RT_FALSE); + LOG_D("The network interface device(%s) set down status", netdev->name); + return RT_EOK; +} + +static int sim800c_netdev_set_dns_server(struct netdev *netdev, ip_addr_t *dns_server) +{ +#define SIM800C_DNS_RESP_LEN 8 +#define SIM800C_DNS_RESP_TIMEO rt_tick_from_millisecond(300) + + at_response_t resp = RT_NULL; + int result = RT_EOK; + + RT_ASSERT(netdev); + RT_ASSERT(dns_server); + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + resp = at_create_resp(SIM800C_DNS_RESP_LEN, 0, SIM800C_DNS_RESP_TIMEO); + if (resp == RT_NULL) + { + LOG_E("sim800c set dns server failed, no memory for response object."); + result = -RT_ENOMEM; + goto __exit; + } + + /* send "AT+CDNSCFG=[,]" commond to set dns servers */ + if (at_exec_cmd(resp, "AT+CDNSCFG=\"%s\"", inet_ntoa(dns_server)) < 0) + { + result = -RT_ERROR; + goto __exit; + } + + netdev_low_level_set_dns_server(netdev, 0, dns_server); + +__exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +static int sim800c_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp) +{ +#define SIM800C_PING_RESP_SIZE 128 +#define SIM800C_PING_IP_SIZE 16 +#define SIM800C_PING_TIMEO (5 * RT_TICK_PER_SECOND) + +#define SIM800C_PING_ERR_TIME 600 +#define SIM800C_PING_ERR_TTL 255 + + int result = RT_EOK; + at_response_t resp = RT_NULL; + char ip_addr[SIM800C_PING_IP_SIZE] = {0}; + int response, time, ttl, i; + + RT_ASSERT(netdev); + RT_ASSERT(host); + RT_ASSERT(ping_resp); + + for (i = 0; i < rt_strlen(host) && !isalpha(host[i]); i++); + + if (i < strlen(host)) + { + /* check domain name is usable */ + if (sim800c_domain_resolve(host, ip_addr) < 0) + { + return -RT_ERROR; + } + rt_memset(ip_addr, 0x00, SIM800C_PING_IP_SIZE); + } + + rt_mutex_take(at_event_lock, RT_WAITING_FOREVER); + + resp = at_create_resp(SIM800C_PING_RESP_SIZE, 0, SIM800C_PING_TIMEO); + if (resp == RT_NULL) + { + LOG_E("sim800c set dns server failed, no memory for response object."); + result = -RT_ERROR; + goto __exit; + } + + /* send "AT+CIPPING=[,[,[,[,]]]]" commond to send ping request */ + if (at_exec_cmd(resp, "AT+CIPPING=%s,1,%d,%d,64", host, data_len, SIM800C_PING_TIMEO / (RT_TICK_PER_SECOND / 10)) < 0) + { + result = -RT_ERROR; + goto __exit; + } + + if (at_resp_parse_line_args_by_kw(resp, "+CIPPING:", "+CIPPING:%d,\"%[^\"]\",%d,%d", + &response, ip_addr, &time, &ttl) <= 0) + { + LOG_E("Prase \"AT+CIPPING\" commands resposne data error!"); + result = -RT_ERROR; + goto __exit; + } + + /* the ping request timeout expires, the response time settting to 600 and ttl setting to 255 */ + if (time == SIM800C_PING_ERR_TIME && ttl == SIM800C_PING_ERR_TTL) + { + result = -RT_ETIMEOUT; + goto __exit; + } + + inet_aton(ip_addr, &(ping_resp->ip_addr)); + ping_resp->data_len = data_len; + /* reply time, in units of 100 ms */ + ping_resp->ticks = time * 100; + ping_resp->ttl = ttl; + + __exit: + if (resp) + { + at_delete_resp(resp); + } + + rt_mutex_release(at_event_lock); + + return result; +} + +void sim800c_netdev_netstat(struct netdev *netdev) +{ + // TODO netstat support +} + +const struct netdev_ops sim800c_netdev_ops = +{ + sim800c_netdev_set_up, + sim800c_netdev_set_down, + + RT_NULL, /* not support set ip, netmask, gatway address */ + sim800c_netdev_set_dns_server, + RT_NULL, /* not support set DHCP status */ + + sim800c_netdev_ping, + sim800c_netdev_netstat, +}; + +static int sim800c_netdev_add(const char *netdev_name) +{ +#define SIM800C_NETDEV_MTU 1500 + struct netdev *netdev = RT_NULL; + + RT_ASSERT(netdev_name); + + netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev)); + if (netdev == RT_NULL) + { + return -RT_ENOMEM; + } + + netdev->mtu = SIM800C_NETDEV_MTU; + netdev->ops = &sim800c_netdev_ops; + +#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 + + return netdev_register(netdev, netdev_name, RT_NULL); +} + static int at_socket_device_init(void) { /* create current AT socket event */ @@ -873,6 +1249,13 @@ static int at_socket_device_init(void) /* register URC data execution function */ at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0])); + /* add network interface device to netdev list */ + if (sim800c_netdev_add(SIM800C_NETDEV_NAME) < 0) + { + LOG_E("SIM800C network interface device(%d) add failed.", SIM800C_NETDEV_NAME); + return -RT_ENOMEM; + } + /* initialize sim800c network */ rt_pin_mode(AT_DEVICE_POWER_PIN, PIN_MODE_OUTPUT); rt_pin_mode(AT_DEVICE_STATUS_PIN, PIN_MODE_INPUT);