From 9ada9cdc52c22fabb658680d3869d3ab6ab87f61 Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Mon, 19 Aug 2024 10:26:57 +0800 Subject: [PATCH] update booster from booster project --- booster/dictionary.c | 3 booster/at-esp32.c | 388 ++++++ booster/dictionary.h | 3 booster/logger.h | 123 - booster/ringbuf.h | 12 booster/logger.c | 503 ++----- booster/ringbuf.c | 17 booster/test/test_logger.c | 45 booster/esp32.c | 166 ++ booster/README.md | 4 booster/linux_list.h | 524 ++++---- booster/test/makefile | 63 booster/util_proc.c | 26 booster/comport.h | 52 booster/esp32.h | 35 booster/atcmd.c | 300 ++++ booster/comport.c | 411 ++--- booster/util_proc.h | 26 booster/list.h | 723 +++++++++++ booster/atcmd.h | 93 + /dev/null | 42 booster/at-esp32.h | 140 ++ booster/makefile | 25 booster/iniparser.h | 4 booster/iniparser.c | 6 25 files changed, 2,697 insertions(+), 1,037 deletions(-) diff --git a/booster/README.md b/booster/README.md new file mode 100644 index 0000000..2b4e7a9 --- /dev/null +++ b/booster/README.md @@ -0,0 +1,4 @@ +## booster + +LingYun embedded C program basic library + diff --git a/booster/at-esp32.c b/booster/at-esp32.c new file mode 100644 index 0000000..df460c4 --- /dev/null +++ b/booster/at-esp32.c @@ -0,0 +1,388 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: at-esp32.c + * Description: This file is ESP32 AT command low level API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + +#include "logger.h" +#include "at-esp32.h" + +/*+------------------------+ + *| Baisc AT command | + *+------------------------+*/ + +static inline int check_at_ready(comport_t *comport) +{ + int times = 6; + int ready = 0; + + while( times-- ) + { + if( 0 == send_atcmd_check_ok(comport, "AT", 500) ) + { + ready = 1; + break; + } + } + + return ready; +} + +/* AT command: AT+RST */ +int esp32_reset(comport_t *comport) +{ + int rv; + + rv = send_atcmd(comport, "AT+RST", 5000, "ready", AT_ERRSTR, NULL, 0); + if( rv < 0) + { + log_error("send AT command to reset ESP32 failed, rv=%d\n", rv); + return -1; + } + + if( check_at_ready(comport) ) + { + log_info("send AT to reset ESP32 and AT command ready\n"); + return 0; + } + else + { + log_info("send AT to reset ESP32 but AT command not ready\n"); + return -3; + } +} + +/* AT command: AT+RESTORE */ +int esp32_restore(comport_t *comport) +{ + int rv; + + //rv = send_atcmd_check_ok(comport, "AT+RESTORE", 5000); + rv = send_atcmd(comport, "AT+RESTORE", 5000, "ready", AT_ERRSTR, NULL, 0); + if( rv < 0) + { + log_error("send AT command to restore ESP32 failed, rv=%d\n", rv); + return -1; + } + + if( check_at_ready(comport) ) + { + log_info("send AT command to resstore ESP32 ready\n"); + return 0; + } + else + { + log_error("send AT command to restore ESP32 but AT not ready\n"); + return -3; + } +} + +/* AT command: ATE1 or ATE0 */ +int esp32_set_echo(comport_t *comport, int enable) +{ + char *at = enable? "ATE1" : "ATE0"; + + return send_atcmd_check_ok(comport, at, 500); +} + +/* AT command: AT+GMR */ +int esp32_get_firmware(comport_t *comport, char *version, int size) +{ + if( !version || size<=0 ) + return -1; + + return send_atcmd_check_value(comport, "AT+GMR", 2000, version, size); +} + +/* AT command: AT+SYSSTORE */ +int esp32_set_sysstore(comport_t *comport, int enable) +{ + char at[ATCMD_LEN]={'\0'}; + + snprintf(at, sizeof(at), "AT+SYSSTORE=%d", enable?1:0); + + return send_atcmd_check_ok(comport, at, 1000); +} + +/*+------------------------+ + *| WiFi AT command | + *+------------------------+*/ + +/* AT command: AT+CWMODE */ +int esp32_set_wmode(comport_t *comport, workmode_t mode, int autoconn) +{ + char at[ATCMD_LEN]={'\0'}; + + snprintf(at, sizeof(at), "AT+CWMODE=%d,%d", mode, autoconn?1:0); + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSTAMAC/CIPAPMAC */ +int esp32_get_macaddr(comport_t *comport, workmode_t mode, char *mac) +{ + if( !mac ) + return -1; + + if( MODE_SOFTAP == mode ) + return send_atcmd_check_request(comport, "AT+CIPAPMAC?", 3000, mac, MAC_LEN); + else + return send_atcmd_check_request(comport, "AT+CIPSTAMAC?", 3000, mac, MAC_LEN); +} + +/* AT command: AT+CIPSTA/AT+CIPAP */ +int esp32_set_ipaddr(comport_t *comport, workmode_t mode, char *ip, char *gateway) +{ + char at[ATCMD_LEN]={'\0'}; + + if( !ip || !gateway ) + return -1; + + if( MODE_SOFTAP == mode ) + snprintf(at, sizeof(at), "AT+CIPAP=\"%s\",\"%s\"", ip, gateway); + else + snprintf(at, sizeof(at), "AT+CIPSTA=\"%s\",\"%s\"", ip, gateway); + + return send_atcmd_check_ok(comport, at, 2000); +} + +/* AT command: AT+CIPSTA/AT+CIPAP */ +int esp32_get_ipaddr(comport_t *comport, workmode_t mode, char *ip, char *gateway) +{ + char *at = MODE_SOFTAP==mode? "AT+CIPAP?" : "AT+CIPSTA?"; + char buf[ATCMD_REPLY_LEN]; + int rv; + + if( !ip || !gateway ) + return -1; + + rv = send_atcmd_check_value(comport, at, 3000, buf, sizeof(buf)); + if( rv < 0) + { + log_error("AT command query IP address failed, rv=%d\n", rv); + return rv; + } + + rv = parser_request_value(buf, "ip", ip, IP_LEN); + if( rv < 0 ) + { + log_error("Parser query IP address failed, rv=%d\n", rv); + return rv; + } + + rv = parser_request_value(buf, "gateway", gateway, IP_LEN); + if( rv < 0 ) + { + log_error("Parser query gateway address failed, rv=%d\n", rv); + return rv; + } + + return 0; +} + +/* AT command: AT+CWDHCP */ +int esp32_set_dhcp(comport_t *comport, workmode_t mode, int enable) +{ + char at[ATCMD_LEN]={'\0'}; + + snprintf(at, sizeof(at), "AT+CWDHCP=%d,%d", enable?1:0, mode); + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CWAUTOCONN */ +int esp32_set_autoconn(comport_t *comport, int enable) +{ + char at[ATCMD_LEN]={'\0'}; + + snprintf(at, sizeof(at), "AT+CWAUTOCONN=%d", enable?1:0); + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CWLAP */ +int esp32_list_ap(comport_t *comport, char *buf, int size) +{ + if( !buf || size<=0 ) + return -1; + + return send_atcmd_check_value(comport, "AT+CWLAP", 8000, buf, size); +} + +/* AT command: AT+CWJAP */ +int esp32_connect_ap(comport_t *comport, char *ssid, char *pwd) +{ + char at[ATCMD_LEN]={'\0'}; + + if( !ssid || !pwd ) + return -1; + + snprintf(at, sizeof(at), "AT+CWJAP=\"%s\",\"%s\"", ssid, pwd); + return send_atcmd_check_ok(comport, at, 15000); +} + +/* AT command: AT+CWQAP */ +int esp32_disconn_ap(comport_t *comport) +{ + return send_atcmd_check_ok(comport, "AT+CWQAP", 5000); +} + + +/* AT command: AT+CWSTATE? status value: + * - 0: ESP32 station has not started any Wi-Fi connection. + * - 1: ESP32 station has connected to an AP, but does not get an IPv4 address yet. + * - 2: ESP32 station has connected to an AP, and got an IPv4 address. + * - 3: ESP32 station is in Wi-Fi connecting or reconnecting state. + * - 4: ESP32 station is in Wi-Fi disconnected state + */ +int esp32_join_status(comport_t *comport, int *status, char *ssid) +{ + char buf[ATCMD_REPLY_LEN]; + int rv; + + if( !status || !ssid ) + return -1; + + rv = send_atcmd_check_request(comport, "AT+CWSTATE?", 3000, buf, sizeof(buf)); + if( rv < 0) + { + log_error("AT command query join status failed, rv=%d\n", rv); + return rv; + } + + sscanf(buf, "%d,%s", status, ssid); + + return 0; +} + +/* AT command: AT+PING */ +int esp32_ping(comport_t *comport, char *host, int timeout) +{ + char at[ATCMD_LEN]={'\0'}; + + if( !host ) + return -1; + + snprintf(at, sizeof(at), "AT+PING=\"%s\"", host); + return send_atcmd_check_ok(comport, at, timeout); +} + +/* AT command: AT+CWSAP */ +int esp32_set_softap(comport_t *comport, char *ssid, char *pwd, int channel, encmode_t encmode) +{ + char at[ATCMD_LEN]={'\0'}; + + if( !ssid || !pwd ) + return -1; + + snprintf(at, sizeof(at), "AT+CWSAP=\"%s\",\"%s\",%d,%d", ssid, pwd, channel, encmode); + return send_atcmd_check_ok(comport, at, 5000); +} + +/* AT command: AT+CWLIF */ +int esp32_list_client(comport_t *comport, char *buf, int size) +{ + if( !buf || size<=0 ) + return -1; + + return send_atcmd_check_value(comport, "AT+CWLIF", 8000, buf, size); +} + +/*+------------------------+ + *| Socket AT command | + *+------------------------+*/ + +/* AT command: AT+CIPMUX */ +int esp32_set_socket_mux(comport_t *comport, int enable) +{ + char at[ATCMD_LEN]={'\0'}; + + snprintf(at, sizeof(at), "AT+CIPMUX=%d", enable?1:0); + + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSERVERMAXCONN */ +int esp32_set_socket_clients(comport_t *comport, int max) +{ + char at[ATCMD_LEN]={'\0'}; + + if( max <= 0 ) + return -1; + + snprintf(at, sizeof(at), "AT+CIPSERVERMAXCONN=%d", max); + + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSTO, timeout unit second */ +int esp32_set_socket_timeout(comport_t *comport, int timeout) +{ + char at[ATCMD_LEN]={'\0'}; + + if( timeout <= 0 ) + return -1; + + snprintf(at, sizeof(at), "AT+CIPSTO=%d", timeout); + + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSERVER */ +int esp32_set_tcp_server(comport_t *comport, int port) +{ + char at[ATCMD_LEN]={'\0'}; + + if( port <= 0 ) + return -1; + + snprintf(at, sizeof(at), "AT+CIPSERVER=1,%d,\"TCP\"", port); + + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSERVER */ +int esp32_del_tcp_server(comport_t *comport, int port) +{ + char at[ATCMD_LEN]={'\0'}; + + if( port <= 0 ) + return -1; + + snprintf(at, sizeof(at), "AT+CIPSERVER=0,%d,\"TCP\"", port); + + return send_atcmd_check_ok(comport, at, 1500); +} + +/* AT command: AT+CIPSTART */ +int esp32_set_tcp_client(comport_t *comport, int mux, char *host, int port) +{ + char at[ATCMD_LEN]={'\0'}; + char buf[ATCMD_REPLY_LEN]={'\0'}; + int keepalive = 60; /* unit second */ + int rv,linkid = 0; + + if( !host || port <= 0 ) + return -1; + + rv = esp32_set_socket_mux(comport, mux); + if(rv < 0) + return rv; + + if( mux ) + snprintf(at, sizeof(at), "AT+CIPSTART=1,\"TCP\",\"%s\",%d,%d", host, port, keepalive); + else + snprintf(at, sizeof(at), "AT+CIPSTART=\"TCP\",\"%s\",%d,%d", host, port, keepalive); + + rv = send_atcmd_check_value(comport, at, 1500, buf, sizeof(buf)); + if(rv < 0) + return rv; + + sscanf(buf, "%d,", &linkid); + + return linkid; +} diff --git a/booster/at-esp32.h b/booster/at-esp32.h new file mode 100644 index 0000000..40d44e0 --- /dev/null +++ b/booster/at-esp32.h @@ -0,0 +1,140 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: at-esp32.h + * Description: This file is ESP32 AT command low level API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + +#ifndef _AT_ESP32_H_ +#define _AT_ESP32_H_ + +#include "atcmd.h" + +enum +{ + DISABLE = 0, /* common disable */ + ENABLE, /* common enable */ +}; + +#define MAC_LEN 18 /* 11:22:33:44:55:66 */ +#define IP_LEN 16 /* 255.255.255.255 */ + +/*+------------------------+ + *| Baisc AT command | + *+------------------------+*/ + +/* AT command: AT+RST */ +extern int esp32_reset(comport_t *comport); + +/* AT command: AT+RESTORE */ +extern int esp32_restore(comport_t *comport); + +/* AT command: ATE1 or ATE0 */ +extern int esp32_set_echo(comport_t *comport, int enable); + +/* AT command: AT+GMR */ +extern int esp32_get_firmware(comport_t *comport, char *version, int size); + +/* AT command: AT+SYSSTORE */ +extern int esp32_set_sysstore(comport_t *comport, int enable); + + +/*+------------------------+ + *| WiFi AT command | + *+------------------------+*/ +typedef enum +{ + MODE_DISABLE=0, /* Wi-Fi RF will be disabled */ + MODE_STATION, /* Station mode */ + MODE_SOFTAP, /* SoftAP mode */ + MODE_WDS, /* Wireless Distribution System: Both Station & SoftAP mode */ +} workmode_t; + +/* AT command: AT+CWMODE */ +extern int esp32_set_wmode(comport_t *comport, workmode_t mode, int autoconn); + +/* AT command: AT+CWDHCP */ +extern int esp32_set_dhcp(comport_t *comport, workmode_t mode, int enable); + +/* AT command: AT+CWAUTOCONN */ +extern int esp32_set_autoconn(comport_t *comport, int enable); + +/* AT command: AT+CIPSTAMAC/CIPAPMAC */ +extern int esp32_get_macaddr(comport_t *comport, workmode_t mode, char *mac); + +/* AT command: AT+CIPSTA/CIPAP */ +extern int esp32_get_ipaddr(comport_t *comport, workmode_t mode, char *ip, char *gateway); + +/* AT command: AT+CIPSTA/AT+CIPAP */ +extern int esp32_set_ipaddr(comport_t *comport, workmode_t mode, char *ip, char *gateway); + +/* AT command: AT+CWLAP */ +extern int esp32_list_ap(comport_t *comport, char *buf, int size); + +/* AT command: AT+CWJAP */ +extern int esp32_connect_ap(comport_t *comport, char *ssid, char *pwd); + +/* AT command: AT+CWQAP */ +extern int esp32_disconn_ap(comport_t *comport); + +/* AT command: AT+CWSTATE? , status value: + * - 0: ESP32 station has not started any Wi-Fi connection. + * - 1: ESP32 station has connected to an AP, but does not get an IPv4 address yet. + * - 2: ESP32 station has connected to an AP, and got an IPv4 address. + * - 3: ESP32 station is in Wi-Fi connecting or reconnecting state. + * - 4: ESP32 station is in Wi-Fi disconnected state + */ +extern int esp32_join_status(comport_t *comport, int *status, char *ssid); + +/* AT command: AT+PING */ +extern int esp32_ping(comport_t *comport, char *host, int timeout); + +/* AT command: AT+CWSAP */ +typedef enum +{ + MODE_OPEN, + /* WEP not support */ + MODE_WPAPSK = 2, + MODE_WPA2PSK, + MODE_WPA_WPA2PSK, +} encmode_t; +extern int esp32_set_softap(comport_t *comport, char *ssid, char *pwd, int channel, encmode_t encmode); + +/* AT command: AT+CWLIF */ +extern int esp32_list_client(comport_t *comport, char *buf, int size); + + +/*+------------------------+ + *| Socket AT command | + *+------------------------+*/ + +/* AT command: CIPMUX */ +extern int esp32_set_socket_mux(comport_t *comport, int enable); + +/* AT command: AT+CIPSERVERMAXCONN */ +extern int esp32_set_socket_clients(comport_t *comport, int max); + +/* AT command: AT+CIPSTO, timeout unit second */ +extern int esp32_set_socket_timeout(comport_t *comport, int timeout); + +/* AT command: AT+CIPSERVER */ +extern int esp32_set_tcp_server(comport_t *comport, int port); + +/* AT command: AT+CIPSERVER */ +extern int esp32_del_tcp_server(comport_t *comport, int port); + +/* AT command: AT+CIPSTART */ +extern int esp32_set_tcp_client(comport_t *comport, int mux, char *host, int port); + +/*+------------------------+ + *| BLE AT command | + *+------------------------+*/ +// RFU + +#endif /* ----- #ifndef _AT_ESP32_H_ ----- */ diff --git a/booster/atcmd.c b/booster/atcmd.c new file mode 100644 index 0000000..7308f1b --- /dev/null +++ b/booster/atcmd.c @@ -0,0 +1,300 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: atcmd.c + * Description: This file is lowlevel AT command send and parser API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + +#include <ctype.h> +#include "logger.h" +#include "atcmd.h" + +/* Description: this function used to send an AT command from serial port and wait for reply message from + * the communication module, and it will return once get expet/error string or timeout. + * + * Arugments: + * $comport: the serial port which connected to GPRS/3G/4G/NB-IoT/WiFi/BLE/Zigbee/LoRa... + * $at: the AT command need to be sent, without "\r\n" + * $timeout: wait for module reply for AT command timeout value, unit micro seconds(ms) + * $exepct: the expect string reply from communication module + * $error: the error string reply from communication module + * $reply: the module reply message output buffer + * $size: the output buffer ($reply) size + * + * Return value: <0: Function error 0: Got error string 1: Got expect string 2: Receive util timeout + * + */ + +int send_atcmd(comport_t *comport, char *at, unsigned long timeout, char *expect, char *error, char *reply, int size) +{ + int i, rv = 0; + int res = ATRES_TIMEOUT; + int bytes = 0; + char buf[ATCMD_REPLY_LEN] = {'\0'}; + char atcmd[ATCMD_LEN] = {'\0'}; + + if( !comport || !at ) + { + log_error("Invalid input arguments\n"); + return -1; + } + + if( comport->fd <= 0 ) + { + log_error("comport[%s] not opened\n"); + return -2; + } + + /* flushes both data received but not read, and data written but not transmitted in serial port */ + tcflush(comport->fd, TCIOFLUSH); + + snprintf(atcmd, sizeof(atcmd), "%s%s", at, AT_SUFFIX); + rv=comport_send( comport, atcmd, strlen(atcmd) ); + if(rv < 0) + { + log_error("send AT command \"%s\" to \"%s\" failed, rv=%d\n", at, comport->devname, rv); + return -3; + } + + res = ATRES_TIMEOUT; + memset( buf, 0, sizeof(buf) ); + + for(i=0; i<timeout/10; i++) + { + if( bytes >= sizeof(buf) ) + break; + + rv=comport_recv( comport, buf+bytes, sizeof(buf)-bytes, 10); + if(rv < 0) + { + log_error("send AT command \'%s\' to \'%s\' failed, rv=%d\n", at, comport->devname, rv); + return -3; + } + + bytes += rv; + + if( expect && strstr(buf, expect) ) + { + log_debug("send AT command \"%s\" and got reply \"OK\"\n", at); + res = ATRES_EXPECT; + break; + } + + if( error && strstr(buf, error) ) + { + log_debug("send AT command \"%s\" and got reply \"ERROR\"\n", at); + res = ATRES_ERROR; + break; + } + } + + if( bytes > 0 ) + log_trace("AT command reply:%s", buf); + + if( reply && size>0 ) + { + bytes = strlen(buf)>size ? size : strlen(buf); + memset(reply, 0, size); + strncpy(reply, buf, bytes); + + log_debug("copy out AT command \"%s\" reply message: \n%s", at, reply); + } + + return res; +} + + +/* + * Description: Send AT command which will only reply by "OK" or "ERROR", such as AT: + * Reply: \r\nOK\r\n + * Return Value: 0: OK -X: Failure + */ +int send_atcmd_check_ok(comport_t *comport, char *at, unsigned long timeout) +{ + int rv; + + if( !comport || !at ) + { + log_error("Invalid input arguments\n"); + return -1; + } + + rv=send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, NULL, 0); + if( ATRES_EXPECT == rv ) + { + return 0; + } + else + { + return -2; + } +} + + +/* + * Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM: + * Reply: \r\nEC20F\r\nOK\r\n + * + * Return Value: 0: OK -X: Failure + */ +int send_atcmd_check_value(comport_t *comport, char *at, unsigned long timeout, char *reply, int size) +{ + int rv, len; + char buf[ATCMD_REPLY_LEN]; + char *ptr_start = buf; + char *ptr_end; + + if( !comport || !at || !reply || size<=0 ) + { + log_error("Invalid input arguments\n"); + return -1; + } + + rv = send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, buf, ATCMD_REPLY_LEN); + if( rv <= 0 ) + { + return -2; + } + + /* Skip the echo back command line */ + if( !strncmp(buf, at, strlen(at)) ) + { + ptr_start=strchr(buf, '\n'); + if( !ptr_start ) + { + log_error("reply message got wrong\n"); + return -3; + } + + ptr_start++; /* skip '\n' */ + } + + /* find end reply string "\r\nOK\r\n" */ + ptr_end = strstr(ptr_start, AT_OKSTR); + if( ptr_end ) + { + len = ptr_end - ptr_start; + } + else + { + len = strlen(buf) - (ptr_start-buf); + } + + memset(reply, 0, size); + + len = len>size ? size : len; + memcpy(reply, ptr_start, len); + + return 0; +} + +/* + * Description: Parser the $value from $key like "xxx: " line, such as AT+CSQ: + * Reply: \r\n+CSQ: 26,99\r\nOK\r\n + * + * Return Value: 0: OK -X: Failure + */ +int parser_request_value(char *buf, char *key, char *value, int size) +{ + char *ptr; + int i = 0; + + if( !buf || !key || !value || size<=0 ) + { + log_error("Invalid input arguments\n"); + return -1; + } + + ptr = strstr(buf, key); + if( !ptr ) + { + log_debug("Not found key \"%s\" in %s\n", key, buf); + return -2; + } + + ptr=strchr(ptr, ':'); /* found ':' before the value */ + if( !ptr ) + { + log_debug("Not found ':' before value\n"); + return -3; + } + ptr++; /* skip ':' */ + + if( *ptr == '\"' ) /* skip " */ + ptr++; + + memset(value, 0, size); + while(*ptr!='\r' && i<size-1) + { + if( !isspace(*ptr) && *ptr!='\"') /* skip space,\r,\n ... */ + value[i++] = *ptr; + ptr ++; + } + + ptr++; /* skip */ + + return 0; +} + +/* + * Description: Send AT command which will reply by the value with a prefix "+CMD: " line, such as AT+CSQ: + * Reply: \r\n+CSQ: 26,99\r\nOK\r\n + * + * Return Value: 0: OK -X: Failure + */ +int send_atcmd_check_request(comport_t *comport, char *at, unsigned long timeout, char *reply, int size) +{ + int i = 0; + int rv; + char buf[ATCMD_REPLY_LEN]; + char *ptr; + + if( !comport || !at || !reply || size<=0 ) + { + log_error("Invalid input arguments\n"); + return -1; + } + + rv = send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, buf, ATCMD_REPLY_LEN); + if( rv <= 0 ) + { + return -2; + } + + ptr=strchr(buf, '+'); /* found '+' before the value */ + if( !ptr ) + { + log_error("reply message got wrong\n"); + return -3; + } + ptr++; /* skip '+' */ + + + ptr=strchr(buf, ':'); /* found ':' before the value */ + if( !ptr ) + { + log_error("reply message got wrong\n"); + return -3; + } + ptr++; /* skip ':' */ + + if( *ptr == '\"' ) /* skip " */ + ptr++; + + memset(reply, 0, size); + while(*ptr!='\r' && i<size-1) + { + if( !isspace(*ptr) && *ptr!='\"') /* skip space,\r,\n ... */ + reply[i++] = *ptr; + ptr ++; + } + + return 0; +} + diff --git a/booster/atcmd.h b/booster/atcmd.h new file mode 100644 index 0000000..0d7853e --- /dev/null +++ b/booster/atcmd.h @@ -0,0 +1,93 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: atcmd.h + * Description: This file is lowlevel AT command send and parser API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + + +#ifndef _ATCMD_H_ +#define _ATCMD_H_ + +#include "comport.h" + +/* AT command common reply message max length */ +#define ATCMD_REPLY_LEN 1024 /* Max AT command reply message length */ +#define ATCMD_LEN 256 /* Max AT command length */ + +/* AT command reply message got expect or error string */ +#define AT_OKSTR "\r\nOK\r\n" /* expect string always be OK */ +#define AT_ERRSTR "\r\nERROR\r\n" /* error string always be ERROR */ + +/* AT command should be end by $AT_SUFFIX */ +#define AT_SUFFIX "\r\n" + +/* send_atcmd)( return value status */ +enum +{ + ATRES_ERROR, /* AT command reply got error string, such as "ERROR\r\n" */ + ATRES_EXPECT, /* AT command reply got expect string, such as "OK\r\n" */ + ATRES_TIMEOUT, /* AT command not get error/expect string, receive util timeout */ +}; + +/* Description: this function used to send an AT command from serial port and wait for reply message from + * the communication module, and it will return once get expet/error string or timeout. + * + * Arugments: + * $comport: the serial port which connected to GPRS/3G/4G/NB-IoT/WiFi/BLE/Zigbee/LoRa... + * $at: the AT command need to be sent, without "\r\n" + * $timeout: wait for module reply for AT command timeout value, unit micro seconds(ms) + * $exepct: the expect string reply from communication module + * $error: the error string reply from communication module + * $reply: the module reply message output buffer + * $size: the output buffer ($reply) size + * + * Return value: <0: Function error 0: Got error string 1: Got expect string 2: Receive util timeout + * + */ +int send_atcmd(comport_t *comport, char *at, unsigned long timeout, char *expect, char *error, char *reply, int size); + + +/* + * Description: Send AT command which will only reply by "OK" or "ERROR", such as AT: + * Reply: \r\nOK\r\n + * + * Return Value: 0: OK -X: ERROR + */ +int send_atcmd_check_ok(comport_t *comport, char *at, unsigned long timeout); + + +/* + * Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM: + * Reply: \r\nEC20F\r\nOK\r\n + * + * Return Value: 0: OK -X: ERROR + */ +int send_atcmd_check_value(comport_t *comport, char *at, unsigned long timeout, char *reply, int size); + +/* + * Description: Parser the $value from $key like "xxx: " line, such as AT+CSQ: + * Reply: \r\n+CSQ: 26,99\r\nOK\r\n + * + * Return Value: 0: OK -X: Failure + */ +int parser_request_value(char *buf, char *key, char *value, int size); + + +/* + * Description: Send AT command which will reply by the value with a prefix "+CMD: " line, such as AT+CSQ: + * Reply: \r\n+CSQ: 26,99\r\nOK\r\n + * + * Return Value: 0: OK -X: ERROR + */ +int send_atcmd_check_request(comport_t *comport, char *at, unsigned long timeout, char *repy, int size); + + +#endif /* ----- #ifndef _ATCMD_H_ ----- */ + diff --git a/booster/comport.c b/booster/comport.c index f6d9d10..4a31278 100644 --- a/booster/comport.c +++ b/booster/comport.c @@ -1,25 +1,34 @@ /********************************************************************************* - * Copyright: (C) 2018 Guo Wenxue <guowenxue@gmail.com> + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * - * Filename: cp_comport.c - * Description: It's the comport operate library. + * Filename: comport.c + * Description: This file is linux comport common API functions * - * Version: 2.0.0(10/17/2018~) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ -#include "comport.h" +#include "comport.h" -static void set_settings(comport_t *comport, const char *settings); +#define CONFIG_PRINT_LOGGER +//#define CONFIG_PRINT_STDOUT -#ifdef COM_DEBUG -void disp_settings(comport_t *comport); +#if ( defined CONFIG_PRINT_LOGGER ) +#include "logger.h" +#define dbg_print(format,args...) log_error(format, ##args) + +#elif ( defined CONFIG_PRINT_STDOUT ) +#define dbg_print(format,args...) printf(format, ##args) + +#else +#define dbg_print(format,args...) do{} while(0); #endif +static inline void set_settings(comport_t * comport, const char *settings); /* * description: Open the serial port @@ -40,64 +49,58 @@ if( !comport || !devname ) { - COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + dbg_print("invalid input arugments\n"); return -1; } + /*+-----------------------+ + *| open the serial port | + *+-----------------------+*/ + memset(comport, 0, sizeof(*comport)); - strncpy(comport->devname, devname, DEVNAME_LEN); + strncpy(comport->devname, devname, sizeof(comport->devname)); comport->baudrate = baudrate; comport->fd = -1; - comport->frag_size = 128; - + comport->fragsize = CONFIG_DEF_FRAGSIZE; set_settings(comport, settings); -#ifdef COM_DEBUG - disp_settings(comport); -#endif - /* Not a TTY device */ - if( !strstr(comport->devname, "tty")) + if( !strstr(comport->devname, "tty") ) { - COM_PRINT("Open Not tty device \"%s\"\n", comport->devname); + dbg_print("comport device \"%s\" is not tty device\n", comport->devname); return -2; } comport->fd = open(comport->devname, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (comport->fd < 0) + if( comport->fd<0 ) { - rv = -3; - goto CleanUp; + dbg_print("comport open \"%s\" failed:%s\n", comport->devname, strerror(errno)); + return -3; } - COM_PRINT("Open device \"%s\"\n", comport->devname); - if ((-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) - && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK))) + if( (-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) + && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK)) ) { /* Flush input and output */ - if (-1 == tcflush(comport->fd, TCIOFLUSH)) - { - rv = -4; - goto CleanUp; - } + tcflush(comport->fd, TCIOFLUSH); } else { - rv = -5; + rv = -4; goto CleanUp; } if (0 != tcgetattr(comport->fd, &old_cfg)) { - rv = -6; // Failed to get Com settings + rv = -5; goto CleanUp; } + + /*+-----------------------+ + *| configure serial port | + *+-----------------------+*/ + memset(&new_cfg, 0, sizeof(new_cfg)); - - /*=====================================*/ - /* Configure comport */ - /*=====================================*/ - new_cfg.c_cflag &= ~CSIZE; new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); @@ -123,11 +126,11 @@ /* Set the parity */ switch (comport->parity) { - case 0x01: // Odd + case 0x01: /* Odd */ new_cfg.c_cflag |= (PARENB | PARODD); new_cfg.c_cflag |= (INPCK | ISTRIP); break; - case 0x02: // Even + case 0x02: /* Even */ new_cfg.c_cflag |= PARENB; new_cfg.c_cflag &= ~PARODD;; new_cfg.c_cflag |= (INPCK | ISTRIP); @@ -153,16 +156,16 @@ /* Set flow control */ switch (comport->flowctrl) { - case 1: // Software control + case 1: /* Software control */ case 3: new_cfg.c_cflag &= ~(CRTSCTS); new_cfg.c_iflag |= (IXON | IXOFF); break; - case 2: // Hardware control - new_cfg.c_cflag |= CRTSCTS; // Also called CRTSCTS + case 2: /* Hardware control */ + new_cfg.c_cflag |= CRTSCTS; new_cfg.c_iflag &= ~(IXON | IXOFF); break; - default: // NONE + default: /* NONE */ new_cfg.c_cflag &= ~(CRTSCTS); new_cfg.c_iflag &= ~(IXON | IXOFF); break; @@ -171,53 +174,54 @@ /* Set baudrate */ switch (comport->baudrate) { - /* Upper is not POSIX(bits/termios-baud.h) */ - case 4000000: - tmp = B4000000; - break; - case 3500000: - tmp = B3500000; - break; - case 3000000: - tmp = B3000000; - break; - case 2500000: - tmp = B2500000; - break; - case 2000000: - tmp = B2000000; - break; - case 1500000: - tmp = B1500000; - break; - case 1152000: - tmp = B1152000; - break; - case 1000000: - tmp = B1000000; - break; - case 921600: - tmp = B921600; - break; - case 576000: - tmp = B576000; - break; - case 500000: - tmp = B500000; - break; - case 460800: - tmp = B460800; - break; - case 230400: - tmp = B230400; - break; + /* Upper is not POSIX(bits/termios-baud.h) */ + case 4000000: + tmp = B4000000; + break; + case 3500000: + tmp = B3500000; + break; + case 3000000: + tmp = B3000000; + break; + case 2500000: + tmp = B2500000; + break; + case 2000000: + tmp = B2000000; + break; + case 1500000: + tmp = B1500000; + break; + case 1152000: + tmp = B1152000; + break; + case 1000000: + tmp = B1000000; + break; + case 921600: + tmp = B921600; + break; + case 576000: + tmp = B576000; + break; + case 500000: + tmp = B500000; + break; + case 460800: + tmp = B460800; + break; + case 230400: + tmp = B230400; + break; case 115200: tmp = B115200; break; case 57600: tmp = B57600; break; - /* Below is POSIX(bits/termios.h) */ + + /* Below is POSIX(bits/termios.h) */ case 38400: tmp = B38400; break; @@ -276,19 +280,15 @@ tcflush(comport->fd, TCIFLUSH); if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg)) { - rv = -7; // Failed to set device com port settings + rv = -6; // Failed to set device com port settings goto CleanUp; } - - COM_PRINT("Connected device \"%s\".\n", comport->devname); rv = comport->fd; CleanUp: - COM_PRINT("Open device \"%s\" %s.\n", comport->devname, rv>0 ? "successfully" : "failure"); return rv; } - /* @@ -300,13 +300,12 @@ { if( !comport ) { - COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + dbg_print("invalid input arugments\n"); return ; } if ( comport->fd >= 0 ) { - COM_PRINT("Close device \"%s\"\n", comport->devname); close(comport->fd); } @@ -315,165 +314,127 @@ } /* - * description: write $send_bytes bytes data from $buf to $comport + * description: write $data_bytes $data to $comport * return value: 0: write ok <0: write failure */ -int comport_send(comport_t *comport, char *buf, int send_bytes) +int comport_send(comport_t *comport, char *data, int data_bytes) { + char *ptr; + int left, bytes = 0; int rv = 0; - char *ptr, left_bytes; - int send = 0; - if ( !comport || !buf || send_bytes<=0 ) + if( !comport || !data || data_bytes<=0 ) { - COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); - rv = -1; - goto CleanUp; + dbg_print("invalid input arugments\n"); + return -1; } - if ( comport->fd < 0 ) // Comport not opened ? + if( comport->fd < 0 ) { - rv = -3; - COM_PRINT("Serail not connected.\n"); - goto CleanUp; + dbg_print("Serail port not opened\n"); + return -2; } - //printf("Send %s with %d bytes.\n", buf, send_bytes); + ptr = data; + left = data_bytes; - - left_bytes = send_bytes; - ptr = buf; - - while( left_bytes > 0 ) + while( left > 0 ) { /* Large data, then slice them to frag and send */ - send = left_bytes>comport->frag_size ? comport->frag_size : left_bytes; - - rv = write(comport->fd, ptr, send); - if( rv<0 ) - { - rv = -4; - goto CleanUp; - } - - left_bytes -= rv; - ptr += rv; + bytes = left>comport->fragsize ? comport->fragsize : left; + + rv = write(comport->fd, ptr, bytes); + if( rv<0 ) + { + rv = -3; + break; + } + + left -= rv; + ptr += rv; } - rv = 0; - -CleanUp: return rv; } /* - * description: read data from $comport in $timeout <ms> to $buf no more than $bufsize bytes + * description: read data from $comport in $timeout <ms> to $buf no more than $buf_size bytes * return value: the actual read data bytes, <0: read failure */ -int comport_recv(comport_t *comport, char *buf, int bufsize, unsigned long timeout) +int comport_recv(comport_t *comport, char *buf, int buf_size, unsigned long timeout) { - int rv = 0; - int iRet; fd_set rdfds, exfds; - struct timeval stTime; + struct timeval to, *to_ptr = NULL; + int ret, rv = 0; + int bytes = 0; - if ( !comport || !buf || bufsize<=0 ) + if ( !comport || !buf || buf_size<=0 ) { - COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); - rv = -1; - goto CleanUp; + dbg_print("invalid input arugments\n"); + return -1; } if ( comport->fd < 0 ) { - COM_PRINT("%s() comport not connected.\n", __FUNCTION__); - rv = -2; - goto CleanUp; + dbg_print("Serail port not opened\n"); + return -2; } + + memset(buf, 0, buf_size); FD_ZERO(&rdfds); FD_ZERO(&exfds); FD_SET(comport->fd, &rdfds); FD_SET(comport->fd, &exfds); - if (0xFFFFFFFF != timeout) + if( TIMEOUT_NONE != timeout ) { - stTime.tv_sec = (time_t) (timeout / 1000); - stTime.tv_usec = (long)(1000 * (timeout % 1000)); - - iRet = select(comport->fd + 1, &rdfds, 0, &exfds, &stTime); - if (0 == iRet) - { - rv = 0; - goto CleanUp; - } - else if (0 < iRet) - { - if (0 != FD_ISSET(comport->fd, &exfds)) - { - rv = -6; - COM_PRINT("Error checking recv status.\n"); - goto CleanUp; - } - - if (0 == FD_ISSET(comport->fd, &rdfds)) - { - rv = 0; - COM_PRINT("No incoming data.\n"); - goto CleanUp; - } - } - else - { - if (EINTR == errno) - { - COM_PRINT("catch interrupt signal.\n"); - rv = 0; - } - else - { - COM_PRINT("Check recv status failure.\n"); - rv = -7; - } - - goto CleanUp; - } + to.tv_sec = (time_t) (timeout / 1000); + to.tv_usec = (long)(1000 * (timeout % 1000)); + to_ptr = &to; } - usleep(10000); /* sleep for 10ms for data incoming */ - - // Get data from Com port - iRet = read(comport->fd, buf, bufsize); - if (0 > iRet) + while( 1 ) { - if (EINTR == errno) - rv = 0; // Interrupted signal catched - else - rv = -3; // Failed to read Com port - - goto CleanUp; - } - -#if 0 - { - int i=0; - printf("Receive %d bytes data: \n", iRet); - for(i=0; i<iRet; i++) + /* check got data arrive or not */ + ret = select(comport->fd+1, &rdfds, 0, &exfds, to_ptr); + if( ret<0 ) { - printf("0x%02x ", buf[i]); + /* EINTR means catch interrupt signal */ + dbg_print("comport select() failed: %s\n", strerror(errno)); + rv = EINTR==errno ? 0 : -3; + break; } - printf("\n"); + else if( 0 == ret ) /* timeout */ + { + break; + } + + /* read data from comport */ + ret = read(comport->fd, buf+bytes, buf_size-bytes); + if(ret <= 0) + { + dbg_print("comport read() failed: %s\n", strerror(errno)); + break; + } + + bytes += ret; + if( bytes >= buf_size ) + break; + + /* try to read data in 1ms again, if no data arrive it will break */ + to.tv_sec = 0; + to.tv_usec = 10000; + to_ptr = &to; } -#endif - rv = iRet; + if( !rv ) + rv = bytes; -CleanUp: return rv; - } @@ -484,11 +445,11 @@ * Output Args: NONE * Return Value: NONE *************************************************************************************/ -void set_settings(comport_t * comport, const char *settings) +static inline void set_settings(comport_t * comport, const char *settings) { if( !settings || !comport ) { - COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + dbg_print("invalid input arugments\n"); return ; } @@ -556,50 +517,4 @@ break; } } - - - -#ifdef COM_DEBUG -void disp_settings(comport_t *comport) -{ - COM_PRINT("Device:\t\t\t\"%s\"\n", comport->devname); - COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate); - COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit); - - switch (comport->parity) - { - case 0: - COM_PRINT("Parity:\t\t\t\'N\'\n"); - break; - case 1: - COM_PRINT("Parity:\t\t\t\'O\'\n"); - break; - case 2: - COM_PRINT("Parity:\t\t\t\'E\'\n"); - break; - case 3: - COM_PRINT("Parity:\t\t\t\'S\'\n"); - break; - } - COM_PRINT("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit); - switch (comport->flowctrl) - { - case 0: - COM_PRINT("FlowCtrl:\t\t\'N\'\n"); - break; - case 1: - COM_PRINT("FlowCtrl:\t\t\'S\'\n"); - break; - case 2: - COM_PRINT("FlowCtrl:\t\t\'H\'\n"); - break; - case 3: - COM_PRINT("FlowCtrl:\t\t\'B\'\n"); - break; - } - COM_PRINT("\n"); - return; -} -#endif - diff --git a/booster/comport.h b/booster/comport.h index 755e02e..2754d43 100644 --- a/booster/comport.h +++ b/booster/comport.h @@ -1,17 +1,18 @@ /********************************************************************************* - * Copyright: (C) 2018 LingYun IoT System Studio + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * - * Filename: comport.h - * Description: This head file is for the common TTY/Serial port operator library + * Filename: comport.c + * Description: This file is linux comport common API functions * - * Version: 1.0.0(10/17/2018~) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ -#ifndef __COMPORT_H_ -#define __COMPORT_H_ + +#ifndef _COMPORT_H_ +#define _COMPORT_H_ #include <stdio.h> #include <stdlib.h> @@ -27,36 +28,25 @@ #include <sys/stat.h> #include <sys/select.h> - -#ifndef DEVNAME_LEN -#define DEVNAME_LEN 32 -#endif - -//#define COM_DEBUG -#ifdef COM_DEBUG -#define COM_PRINT(format,args...) printf(format, ##args) -#else -#define COM_PRINT(format,args...) do{} while(0); -#endif - +#define CONFIG_DEF_FRAGSIZE 128 typedef struct comport_s { - char devname[DEVNAME_LEN]; + char devname[32]; unsigned char databit, parity, stopbit, flowctrl; long baudrate; int fd; - int frag_size; + int fragsize; /* frag size when do large data send */ } comport_t; /* - * description: Open the comport specified by $comport + * description: Open the comport and returned by $comport * - * input args: $comport: corresponding comport point + * input args: $comport: corresponding comport handler * $devname: The comport device name path, such as '/dev/ttyS3' - * $baudrate: The baudrate, such as 115200 - * $settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' + * $baudrate: The baudrate, such as 115200 + * $settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' * * return value: The comport opened file description, <0 means failure */ @@ -64,21 +54,21 @@ /* * description: close comport - * input args: $comport: corresponding comport point + * input args: $comport: corresponding comport handler */ extern void comport_close(comport_t *comport); /* - * description: write $send_bytes bytes data from $buf to $comport + * description: write $bytes $data to $comport * return value: 0: write ok <0: write failure */ -extern int comport_send(comport_t *comport, char *buf, int send_bytes); +extern int comport_send(comport_t *comport, char *data, int data_bytes); /* - * description: read data from $comport in $timeout <ms> to $buf no more than $bufsize bytes + * description: read data from $comport in $timeout <ms> to $buf no more than $buf_size bytes * return value: the actual read data bytes, <0: read failure */ -extern int comport_recv(comport_t *comport, char *buf, int bufsize, unsigned long timeout); - +#define TIMEOUT_NONE 0 +extern int comport_recv(comport_t *comport, char *buf, int buf_size, unsigned long timeout); #endif diff --git a/booster/dictionary.c b/booster/dictionary.c index cb7ccd4..0fd5000 100644 --- a/booster/dictionary.c +++ b/booster/dictionary.c @@ -3,6 +3,7 @@ @file dictionary.c @author N. Devillard @brief Implements a dictionary for string variables. + @url https://github.com/ndevilla/iniparser This module implements a simple dictionary object, i.e. a list of string/string associations. This object is useful to store e.g. @@ -140,7 +141,7 @@ /** @brief Create a new dictionary object. @param size Optional initial size of the dictionary. - @return 1 newly allocated dictionary objet. + @return 1 newly allocated dictionary object. This function allocates a new dictionary object of given size and returns it. If you do not know in advance (roughly) the number of entries in the diff --git a/booster/dictionary.h b/booster/dictionary.h index d04b6ce..87d31d9 100644 --- a/booster/dictionary.h +++ b/booster/dictionary.h @@ -4,6 +4,7 @@ @file dictionary.h @author N. Devillard @brief Implements a dictionary for string variables. + @url https://github.com/ndevilla/iniparser This module implements a simple dictionary object, i.e. a list of string/string associations. This object is useful to store e.g. @@ -73,7 +74,7 @@ /** @brief Create a new dictionary object. @param size Optional initial size of the dictionary. - @return 1 newly allocated dictionary objet. + @return 1 newly allocated dictionary object. This function allocates a new dictionary object of given size and returns it. If you do not know in advance (roughly) the number of entries in the diff --git a/booster/esp32.c b/booster/esp32.c new file mode 100644 index 0000000..242c4d3 --- /dev/null +++ b/booster/esp32.c @@ -0,0 +1,166 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: esp32.c + * Description: This file is ESP32 high level logic API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + +#include "logger.h" +#include "esp32.h" + +int esp32_init_module(comport_t *comport) +{ + int rv; + char version[256] = {0}; + + if( !comport ) + return -1; + + rv = esp32_reset(comport); + if( rv < 0) + { + log_error("Reset ESP32 WiFi module failed: %d\n", rv); + return rv; + } + + esp32_set_echo(comport, DISABLE); + + esp32_set_sysstore(comport, ENABLE); + + rv = esp32_get_firmware(comport, version, sizeof(version)); + if( rv < 0) + { + log_error("Query ESP32 firmware version failed: %d\n", rv); + return rv; + } + + log_info("ESP32 firmware version:\n%s\n", version); + + return 0; +} + +int esp32_setup_softap(comport_t *comport, char *ssid, char *pwd) +{ + esp32_set_wmode(comport, MODE_SOFTAP, ENABLE); + + esp32_set_ipaddr(comport, MODE_SOFTAP, DEF_SOFTAP_IPADDR, DEF_SOFTAP_IPADDR); + + esp32_set_dhcp(comport, MODE_SOFTAP, ENABLE); + + esp32_set_softap(comport, ssid, pwd, 11, MODE_WPA2PSK); + + return 0; +} + +int esp32_join_network(comport_t *comport, char *ssid, char *pwd) +{ + int rv, status = 0; + int times=10; + char buf[128] = {0}; + + if( !comport ) + return -1; + + esp32_join_status(comport, &status, buf); + if( 2==status && !strcmp(buf, ssid) ) + { + log_info("ESP32 connected to \"%s\" already\n", ssid); + return 0; + } + + esp32_set_wmode(comport, MODE_STATION, ENABLE); + + esp32_set_dhcp(comport, MODE_STATION, ENABLE); + + rv = esp32_connect_ap(comport, ssid, pwd); + if( rv < 0 ) + { + log_error("connect to AP \"%s\" failed, rv=%d", ssid, rv); + return rv; + } + + while(times--) + { + rv = esp32_join_status(comport, &status, buf); + if( 2 == status ) + { + log_info("ESP32 connected to \"%s\" already\n", ssid); + return 0; + } + rv = -3; + } + + return rv; +} + + +int esp32_check_network(comport_t *comport) +{ + int rv, times=5; + char ip[IP_LEN] = {0}; + char gateway[IP_LEN] = {0}; + + memset(ip, 0, sizeof(ip)); + memset(gateway, 0, sizeof(gateway)); + rv = esp32_get_ipaddr(comport, MODE_STATION, ip, gateway); + if( rv<0 ) + return rv; + + if( !strlen(ip) || !strlen(gateway) ) + return -3; + + log_info("IP address: %s, netmask: %s\n", ip, gateway); + + while( times-- ) + { + if( !(rv=esp32_ping(comport, gateway, 5000)) ) + { + rv = 0; + break; + } + } + + return 0; +} + +int esp32_setup_tcp_server(comport_t *comport, int port) +{ + int rv; + + rv = esp32_set_socket_mux(comport, ENABLE); + if(rv<0) + return rv; + + rv = esp32_set_socket_clients(comport, 2); + if(rv<0) + return rv; + + rv = esp32_set_tcp_server(comport, port); + if(rv<0) + return rv; + + rv = esp32_set_socket_timeout(comport, 600); + if(rv<0) + return rv; + + return 0; +} + +int esp32_setup_tcp_client(comport_t *comport, char *host, int port) +{ + int rv; + + rv = esp32_set_tcp_client(comport, DISABLE, host, port); + if(rv<0) + return rv; + + + return 0; +} + diff --git a/booster/esp32.h b/booster/esp32.h new file mode 100644 index 0000000..1052679 --- /dev/null +++ b/booster/esp32.h @@ -0,0 +1,35 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. + * All rights reserved. + * + * Filename: esp32.h + * Description: This file is ESP32 high level logic API functions + * + * Version: 1.0.0(11/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" + * + ********************************************************************************/ + +#ifndef _ESP32_H_ +#define _ESP32_H_ + +#include "at-esp32.h" + +#define DEF_SOFTAP_IPADDR "192.168.8.1" +#define DEF_SOFTAP_SSID "Router_ESP32" +#define DEF_SOFTAP_PWD "12345678" + +extern int esp32_init_module(comport_t *comport); + +extern int esp32_setup_softap(comport_t *comport, char *ssid, char *pwd); + +extern int esp32_join_network(comport_t *comport, char *ssid, char *pwd); + +extern int esp32_check_network(comport_t *comport); + +extern int esp32_setup_tcp_server(comport_t *comport, int port); + +extern int esp32_setup_tcp_client(comport_t *comport, char *host, int port); + +#endif /* ----- #ifndef _ESP32_H_ ----- */ diff --git a/booster/iniparser.c b/booster/iniparser.c index 8694dd4..3a446e5 100644 --- a/booster/iniparser.c +++ b/booster/iniparser.c @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------*/ /** - @file iniparser.c v4.1 + @file iniparser.c @author N. Devillard - @url https://github.com/ndevilla/iniparser @brief Parser for ini files. + @url https://github.com/ndevilla/iniparser */ /*--------------------------------------------------------------------------*/ /*---------------------------- Includes ------------------------------------*/ @@ -719,7 +719,7 @@ char line [ASCIILINESZ+1] ; char section [ASCIILINESZ+1] ; char key [ASCIILINESZ+1] ; - char tmp [(ASCIILINESZ * 2) + 1] ; + char tmp [(ASCIILINESZ * 2) + 2] ; char val [ASCIILINESZ+1] ; int last=0 ; diff --git a/booster/iniparser.h b/booster/iniparser.h index 1fdfe58..6a137c5 100644 --- a/booster/iniparser.h +++ b/booster/iniparser.h @@ -1,10 +1,10 @@ /*-------------------------------------------------------------------------*/ /** - @file iniparser.h v4.1 + @file iniparser.h @author N. Devillard - @url https://github.com/ndevilla/iniparser @brief Parser for ini files. + @url https://github.com/ndevilla/iniparser */ /*--------------------------------------------------------------------------*/ diff --git a/booster/linux_list.h b/booster/linux_list.h index 9ac0720..b927b14 100644 --- a/booster/linux_list.h +++ b/booster/linux_list.h @@ -66,18 +66,18 @@ */ struct list_head { - struct list_head *next, *prev; + struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) + struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } /* @@ -87,13 +87,13 @@ * the prev/next entries already! */ static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) + struct list_head *prev, + struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } /** @@ -106,7 +106,7 @@ */ static inline void list_add(struct list_head *new, struct list_head *head) { - __list_add(new, head, head->next); + __list_add(new, head, head->next); } /** @@ -119,7 +119,7 @@ */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { - __list_add(new, head->prev, head); + __list_add(new, head->prev, head); } /* @@ -131,8 +131,8 @@ */ static inline void __list_del(struct list_head *prev, struct list_head *next) { - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; } /** @@ -143,9 +143,9 @@ */ static inline void list_del(struct list_head *entry) { - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; } /** @@ -156,19 +156,19 @@ * If @old was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, - struct list_head *new) + struct list_head *new) { - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; } static inline void list_replace_init(struct list_head *old, - struct list_head *new) + struct list_head *new) { - list_replace(old, new); - INIT_LIST_HEAD(old); + list_replace(old, new); + INIT_LIST_HEAD(old); } /** @@ -177,8 +177,8 @@ */ static inline void list_del_init(struct list_head *entry) { - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); } /** @@ -188,8 +188,8 @@ */ static inline void list_move(struct list_head *list, struct list_head *head) { - __list_del(list->prev, list->next); - list_add(list, head); + __list_del(list->prev, list->next); + list_add(list, head); } /** @@ -198,10 +198,10 @@ * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, - struct list_head *head) + struct list_head *head) { - __list_del(list->prev, list->next); - list_add_tail(list, head); + __list_del(list->prev, list->next); + list_add_tail(list, head); } /** @@ -210,9 +210,9 @@ * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, - const struct list_head *head) + const struct list_head *head) { - return list->next == head; + return list->next == head; } /** @@ -221,7 +221,7 @@ */ static inline int list_empty(const struct list_head *head) { - return head->next == head; + return head->next == head; } /** @@ -239,8 +239,8 @@ */ static inline int list_empty_careful(const struct list_head *head) { - struct list_head *next = head->next; - return (next == head) && (next == head->prev); + struct list_head *next = head->next; + return (next == head) && (next == head->prev); } /** @@ -249,19 +249,19 @@ */ static inline int list_is_singular(const struct list_head *head) { - return !list_empty(head) && (head->next == head->prev); + return !list_empty(head) && (head->next == head->prev); } static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) + struct list_head *head, struct list_head *entry) { - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; } /** @@ -269,7 +269,7 @@ * @list: a new list to add all removed entries * @head: a list with entries * @entry: an entry within head, could be the head itself - * and if so we won't cut the list + * and if so we won't cut the list * * This helper moves the initial part of @head, up to and * including @entry, from @head to @list. You should @@ -279,31 +279,31 @@ * */ static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) + struct list_head *head, struct list_head *entry) { - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); } static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) + struct list_head *prev, + struct list_head *next) { - struct list_head *first = list->next; - struct list_head *last = list->prev; + struct list_head *first = list->next; + struct list_head *last = list->prev; - first->prev = prev; - prev->next = first; + first->prev = prev; + prev->next = first; - last->next = next; - next->prev = last; + last->next = next; + next->prev = last; } /** @@ -312,10 +312,10 @@ * @head: the place to add it in the first list. */ static inline void list_splice(const struct list_head *list, - struct list_head *head) + struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head, head->next); + if (!list_empty(list)) + __list_splice(list, head, head->next); } /** @@ -324,10 +324,10 @@ * @head: the place to add it in the first list. */ static inline void list_splice_tail(struct list_head *list, - struct list_head *head) + struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head->prev, head); + if (!list_empty(list)) + __list_splice(list, head->prev, head); } /** @@ -338,12 +338,12 @@ * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, - struct list_head *head) + struct list_head *head) { - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } } /** @@ -355,47 +355,47 @@ * The list at @list is reinitialised */ static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) + struct list_head *head) { - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } } /** * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ - container_of(ptr, type, member) + container_of(ptr, type, member) /** * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) + list_entry((ptr)->next, type, member) /** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. */ #define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) /** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. @@ -403,170 +403,170 @@ * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) + for (pos = (head)->next; pos != (head); pos = pos->next) /** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) /** * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. */ #define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) + for (pos = (head)->prev, n = pos->prev; \ + prefetch(pos->prev), pos != (head); \ + pos = n, n = pos->prev) /** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) + ((pos) ? : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Start to iterate over list of given type backwards, continuing after * the current position. */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) /* * Double linked lists with a single pointer list head. @@ -576,11 +576,11 @@ */ struct hlist_head { - struct hlist_node *first; + struct hlist_node *first; }; struct hlist_node { - struct hlist_node *next, **pprev; + struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT { .first = NULL } @@ -588,134 +588,134 @@ #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) static inline void INIT_HLIST_NODE(struct hlist_node *h) { - h->next = NULL; - h->pprev = NULL; + h->next = NULL; + h->pprev = NULL; } static inline int hlist_unhashed(const struct hlist_node *h) { - return !h->pprev; + return !h->pprev; } static inline int hlist_empty(const struct hlist_head *h) { - return !h->first; + return !h->first; } static inline void __hlist_del(struct hlist_node *n) { - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; } static inline void hlist_del_init(struct hlist_node *n) { - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; } /* next must be != NULL */ static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) + struct hlist_node *next) { - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; } static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) + struct hlist_node *next) { - next->next = n->next; - n->next = next; - next->pprev = &n->next; + next->next = n->next; + n->next = next; + next->pprev = &n->next; - if(next->next) - next->next->pprev = &next->next; + if(next->next) + next->next->pprev = &next->next; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) /** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) #endif diff --git a/booster/list.h b/booster/list.h new file mode 100644 index 0000000..2a333f4 --- /dev/null +++ b/booster/list.h @@ -0,0 +1,723 @@ +/********************************************************************************* + * Copyright: (C) 2020 LingYun IoT System Studio + * All rights reserved. + * + * Filename: list.h + * Description: This file is copied from Linux kernel, which provide link list API. + * + * Version: 1.0.0(08/09/2020) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "08/09/2020 02:24:34 AM" + * + ********************************************************************************/ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include <linux/stddef.h> + + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +/* + * Architectures might want to move the poison pointer offset + * into some well-recognized area such as 0xdead000000000000, + * that is also not mappable by user-space exploits: + */ +#ifdef CONFIG_ILLEGAL_POINTER_VALUE +# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL) +#else +# define POISON_POINTER_DELTA 0 +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) + +#ifndef ARCH_HAS_PREFETCH +#define ARCH_HAS_PREFETCH +static inline void prefetch(const void *x) {;} +#endif + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + prefetch(pos->prev), pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + + +#endif + + diff --git a/booster/logger.c b/booster/logger.c index a821e1e..364fa72 100644 --- a/booster/logger.c +++ b/booster/logger.c @@ -1,383 +1,250 @@ /********************************************************************************* - * Copyright: (C) 2020 LingYun IoT System Studio + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * * Filename: logger.c - * Description: This file is the linux infrastructural logger system library + * Description: This file is common logger API functions * - * Version: 1.0.0(08/08/2020~) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "08/08/2020 04:24:01 PM" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <pthread.h> + #include "logger.h" -#define PRECISE_TIME_FACTOR 1000 +typedef void (*log_LockFn)(void *udata, int lock); -static unsigned long log_rollback_size = LOG_ROLLBACK_NONE; +static struct { + char file[32]; /* logger file name */ + FILE *fp; /* logger file pointer */ + long size; /* logger file max size */ + int level; /* logger level */ + log_LockFn lockfn; /* lock function */ + void *udata; /* lock data */ +} L; -/* This library is not thread safe */ -static logger_t *logger = NULL; +static const char *level_names[] = { + "ERROR", + "WARN", + "INFO", + "DEBUG", + "TRACE" +}; -char *log_str[LOG_LEVEL_MAX + 1] = { "", "E", "W", "N", "D", "I", "M" }; +static const char *level_colors[] = { + "\x1b[31m", + "\x1b[33m", + "\x1b[32m", + "\x1b[36m", + "\x1b[94m" +}; -#define LOG_TIME_FMT "%Y-%m-%d %H:%M:%S" - -static void log_signal_handler(int sig) +static inline void time_to_str(char *buf) { - if(!logger) - return ; + struct timeval tv; + struct tm *tm; + int len; - if (sig == SIGHUP) + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + + len = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, (int)tv.tv_usec); + + buf[len] = '\0'; +} + +static void mutex_lock(void *udata, int lock) +{ + int err; + pthread_mutex_t *l = (pthread_mutex_t *) udata; + + if (lock) { - signal(SIGHUP, log_signal_handler); - log_err("SIGHUP received - reopenning log file [%s]", logger->file); - log_reopen(); + if ( (err = pthread_mutex_lock(l)) != 0 ) + log_error("Unable to lock log lock: %s", strerror(err)); + } + else + { + if ( (err = pthread_mutex_unlock(l) != 0) ) + log_error("Unable to unlock log lock: %s", strerror(err)); } } -static void logger_banner(char *prefix) +int log_open(char *fname, int level, int size, int lock) { - if(!logger) - return ; + FILE *fp; - fprintf(logger->fp, "%s log \"%s\" on level [%s] size [%lu] KiB, log system version %s\n", - prefix, logger->file, log_str[logger->level], log_rollback_size / 1024, LOG_VERSION_STR); -#ifdef LOG_FILE_LINE - fprintf(logger->fp, " [ Date ] [ Time ] [ Level ] [ File/Line ] [ Message ]\n"); -#else - fprintf(logger->fp, " [ Date ] [ Time ] [ Level ] [ Message ]\n"); -#endif - fprintf(logger->fp, "-------------------------------------------------------------\n"); -} + L.level = level; + L.size = size*1024; -static void check_and_rollback(void) -{ - if(!logger) - return ; - - if (log_rollback_size != LOG_ROLLBACK_NONE) + if( !fname || !strcmp(fname, "console") || !strcmp(fname, "stderr") ) { - long _curOffset = ftell(logger->fp); - - if ((_curOffset != -1) && (_curOffset >= log_rollback_size)) + strcpy(L.file, "console"); + L.fp = stderr; + L.size = 0; /* console don't need rollback */ + } + else + { + if ( !(fp = fopen(fname, "a+")) ) { - char cmd[512]; - - snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", logger->file, logger->file); - system(cmd); - - if (-1 == fseek(logger->fp, 0L, SEEK_SET)) - fprintf(logger->fp, "log rollback fseek failed \n"); - - rewind(logger->fp); - - truncate(logger->file, 0); - logger_banner("Already rollback"); + fprintf(stderr, "%s() failed: %s\n", __func__, strerror(errno)); + return -2; } + L.fp = fp; + strncpy(L.file, fname, sizeof(L.file)); } -} -/* log_size unit is KB */ -int log_open(logger_t *log, char *log_file, int level, int log_size) -{ - struct sigaction act; - char *filemode; - - if(!log) + if( lock ) { - printf("ERROR: Invalid input arguments\n"); - return -1; + static pthread_mutex_t log_lock; + + pthread_mutex_init(&log_lock, NULL); + L.udata = (void *)&log_lock; + L.lockfn = mutex_lock; } - /* set static global $logger point to argument $log */ - logger = log; + fprintf(L.fp, "\n"); + log_info("logger system(%s) start: file:\"%s\", level:%s, maxsize:%luKiB\n\n", + LOG_VERSION, L.file, level_names[level], size); - - /* use standard error as output */ - if( !log_file || log_file[0]=='\0' || !strcmp(log_file, LOG_STDERR)) - { - strncpy(logger->file, LOG_STDERR, FILENAME_LEN); - logger->flag |= FLAG_LOGGER_CONSOLE; - logger->level = level; - logger->fp = stderr; - - log_rollback_size = LOG_ROLLBACK_NONE; - goto OUT; - } - - strncpy(logger->file, log_file, FILENAME_LEN); - logger->flag |= FLAG_LOGGER_FILE; - logger->level = level; - logger->size = log_size; - - log_rollback_size = log_size <= 0 ? LOG_ROLLBACK_NONE : log_size*1024; /* Unit KiB */ - - filemode = (log_rollback_size==LOG_ROLLBACK_NONE) ? "a+" : "w+"; - - logger->fp = fopen(logger->file, filemode); - if ( !logger->fp ) - { - fprintf(stderr, "Open log file \"%s\" in %s failure: %s\n", logger->file, filemode, strerror(errno)); - return -2; - } - - act.sa_handler = log_signal_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGHUP, &act, NULL); - - OUT: - logger_banner("Initialize"); return 0; } void log_close(void) { - if (!logger || !logger->fp ) - return; + if( L.fp && L.fp!=stderr ) + fclose(L.fp); - logger_banner("\nTerminate"); - logger_raw("\n\n\n\n"); + if (L.udata ) + pthread_mutex_destroy( L.udata); +} - fflush(logger->fp); +static void log_rollback(void) +{ + char cmd[128]={0}; + long fsize; - fclose(logger->fp); - logger->fp = NULL; + /* don't need rollback */ + if(L.size <= 0 ) + return ; + + fsize = ftell(L.fp); + if( fsize < L.size ) + return ; + + /* backup current log file */ + snprintf(cmd, sizeof(cmd), "cp %s %s.bak", L.file, L.file); + system(cmd); + + /* rollback file */ + fseek(L.fp, 0, SEEK_SET); + truncate(L.file, 0); + + fprintf(L.fp, "\n"); + log_info("logger system(%s) rollback: file:\"%s\", level:%s, maxsize:%luKiB\n\n", + LOG_VERSION, L.file, level_names[L.level], L.size/1024); return ; } -int log_reopen(void) +void _log_write(int level, const char *file, int line, const char *fmt, ...) { - int rc = 0; - char *filemode; + va_list args; + char time_string[100]; - if( !logger ) - return -1; - - if (logger->flag & FLAG_LOGGER_CONSOLE ) - { - fflush(logger->fp); - logger->fp = stderr; - return 0; - } - - if (logger->fp) - { - log_close(); - filemode = log_rollback_size==LOG_ROLLBACK_NONE ? "a+" : "w+"; - logger->fp = fopen(logger->file, filemode); - - if (logger->fp == NULL) - rc = -2; - } - else - { - rc = -3; - } - - if (!rc) - { - logger_banner("\nReopen"); - } - return rc; -} - - -void logger_raw(const char *fmt, ...) -{ - va_list argp; - - if (!logger || !logger->fp) + if ( !L.fp || level>L.level ) return; - check_and_rollback(); + /* Acquire lock */ + if ( L.lockfn ) + L.lockfn(L.udata, 1); - va_start(argp, fmt); - vfprintf(logger->fp, fmt, argp); - va_end(argp); -} + log_rollback(); -static void cp_printout(char *level, char *fmt, va_list argp) -{ - char buf[MAX_LOG_MESSAGE_LEN]; - struct tm *local; - struct timeval now; - char timestr[256]; + /* check and rollback file */ + time_to_str(time_string); - if(!logger) - return ; - - check_and_rollback(); - - gettimeofday(&now, NULL); - local = localtime(&now.tv_sec); - - strftime(timestr, 256, LOG_TIME_FMT, local); - vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); - -#ifdef DUMPLICATE_OUTPUT - printf("%s.%03ld [%s] : %s", - timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, buf); -#endif - - if (logger->fp) - fprintf(logger->fp, "%s.%03ld [%s] : %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, buf); - - if (logger->fp) - fflush(logger->fp); -} - -static void cp_printout_line(char *level, char *fmt, char *file, int line, va_list argp) -{ - char buf[MAX_LOG_MESSAGE_LEN]; - struct tm *local; - struct timeval now; - char timestr[256]; - - if(!logger) - return ; - - check_and_rollback(); - - gettimeofday(&now, NULL); - local = localtime(&now.tv_sec); - - strftime(timestr, 256, LOG_TIME_FMT, local); - vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); - -#ifdef DUMPLICATE_OUTPUT - printf("[%s.%03ld] <%s> <%s:%04d> : %s", - timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, file, line, buf); -#endif - - if (logger->fp) + /* Log to stderr */ + if ( L.fp == stderr ) { - fprintf(logger->fp, "[%s.%03ld] <%s> <%s:%04d> : %s", - timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, file, line, buf); - - fflush(logger->fp); + fprintf(L.fp, "%s %s %-5s\x1b[0m \x1b[90m%s:%03d:\x1b[0m ", + time_string, level_colors[level], level_names[level], file, line); } -} - -void logger_str(int level, const char *msg) -{ - if (!logger || level>logger->level) - return; - - check_and_rollback(); - - if (logger->fp) - fwrite(msg, 1, strlen(msg), logger->fp); - - if(logger->fp) - fflush(logger->fp); -} - -void logger_min(int level, char *fmt, ...) -{ - va_list argp; - - if (!logger || level>logger->level) - return; - - va_start(argp, fmt); - cp_printout(log_str[level], fmt, argp); - va_end(argp); -} - -void logger_line(int level, char *file, int line, char *fmt, ...) -{ - va_list argp; - - if (!logger || level>logger->level) - return; - - va_start(argp, fmt); - cp_printout_line(log_str[level], fmt, file, line, argp); - - va_end(argp); -} - -#define LINELEN 81 -#define CHARS_PER_LINE 16 -static char *print_char = - " " - " " - " !\"#$%&'()*+,-./" - "0123456789:;<=>?" - "@ABCDEFGHIJKLMNO" - "PQRSTUVWXYZ[\\]^_" - "`abcdefghijklmno" - "pqrstuvwxyz{|}~ " - " " - " " - " ???????????????" - "????????????????" - "????????????????" - "????????????????" - "????????????????" - "????????????????"; - -void logger_dump(int level, char *buf, int len) -{ - int rc; - int idx; - char prn[LINELEN]; - char lit[CHARS_PER_LINE + 2]; - char hc[4]; - short line_done = 1; - - if (!logger || level>logger->level) - return; - - rc = len; - idx = 0; - lit[CHARS_PER_LINE] = '\0'; - - while (rc > 0) + else /* Log to file */ { - if (line_done) - snprintf(prn, LINELEN, "%08X: ", idx); + fprintf(L.fp, "%s %-5s %s:%03d: ", time_string, level_names[level], file, line); + } - do + va_start(args, fmt); + vfprintf(L.fp, fmt, args); + va_end(args); + + fflush(L.fp); + + /* Release lock */ + if ( L.lockfn ) + L.lockfn(L.udata, 0); +} + + +void log_dump(int level, const char *prompt, char *buf, size_t len) +{ + int i, j, ofset; + char line[256]; + unsigned char c; + unsigned char *buffer = (unsigned char *)buf; + + if (!L.fp || level>L.level) + return; + + if( prompt ) + _log_write(level, __FILE__, __LINE__, "%s\r\n", prompt); + + for(i=0; i<len; i+=16) + { + ofset = snprintf(line, sizeof(line), "%04x: ", i); + + /* print hex representation, and print spaces if end of buffer */ + for(j=0; j<16; j++) { - unsigned char c = buf[idx]; - snprintf(hc, 4, "%02X ", c); - strncat(prn, hc, LINELEN); - - lit[idx % CHARS_PER_LINE] = print_char[c]; + if(i+j < len) + ofset += snprintf(line+ofset, sizeof(line)-ofset, "%02x ", buffer[i+j]); + else + ofset += snprintf(line+ofset, sizeof(line)-ofset, " "); } - while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); + ofset += snprintf(line+ofset, sizeof(line)-ofset, " "); - line_done = (idx % CHARS_PER_LINE) == 0; - if (line_done) + /* print ASCII representation */ + for(j=0; j<16; j++) { -#ifdef DUMPLICATE_OUTPUT - printf("%s %s\n", prn, lit); -#endif - if (logger->fp) - fprintf(logger->fp, "%s %s\n", prn, lit); + if (i+j < len) + { + c = buffer[i+j]; + ofset += snprintf(line+ofset, sizeof(line)-ofset, "%c", (c>=32 && c<=126) ? c : '.'); + } + else + { + ofset += snprintf(line+ofset, sizeof(line)-ofset, " "); + } } - } - if (!line_done) - { - int ldx = idx % CHARS_PER_LINE; - lit[ldx++] = print_char[(int)buf[idx]]; - lit[ldx] = '\0'; - - while ((++idx % CHARS_PER_LINE) != 0) - strncat(prn, " ", sizeof(prn)); - -#ifdef DUMPLICATE_OUTPUT - printf("%s %s\n", prn, lit); -#endif - if (logger->fp) - fprintf(logger->fp, "%s %s\n", prn, lit); - + if (L.fp) + fprintf(L.fp, "%s\r\n", line); } } + diff --git a/booster/logger.h b/booster/logger.h index 5505101..ef8569e 100644 --- a/booster/logger.h +++ b/booster/logger.h @@ -1,105 +1,68 @@ -/******************************************************************************** - * Copyright: (C) 2020 LingYun IoT System Studio +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * * Filename: logger.h - * Description: This file is the linux infrastructural logger system library + * Description: This file is common logger API functions * - * Version: 1.0.0(08/08/2020~) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "08/08/2020 05:16:56 PM" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ #ifndef _LOGGER_H_ #define _LOGGER_H_ -#include <stdarg.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> -#include <time.h> -#include <errno.h> +#include <stdarg.h> -#include <sys/types.h> -#include <sys/time.h> +#define LOG_VERSION "v0.1" -#define LOG_VERSION_STR "1.0.0" - -#ifndef FILENAME_LEN -#define FILENAME_LEN 64 -#endif - -#define LOG_STDERR "stderr" /* Debug mode log file is console */ - -#define LOG_ROLLBACK_SIZE 512 /* Default rollback log size */ -#define LOG_ROLLBACK_NONE 0 /* Set rollback size to 0 will not rollback */ - -#define DEFAULT_TIME_FORMAT "%Y-%m-%d %H:%M:%S" -#define MAX_LOG_MESSAGE_LEN 0x1000 - -//#define DUMPLICATE_OUTPUT /* Log to file and printf on console */ - -enum -{ - LOG_LEVEL_DISB = 0, /* Disable "Debug" */ - LOG_LEVEL_ERROR, /* Debug Level "ERROR" */ - LOG_LEVEL_WARN, /* Debug Level "warnning" */ - LOG_LEVEL_NRML, /* Debug Level "Normal" */ - LOG_LEVEL_DEBUG, /* Debug Level "Debug" */ - LOG_LEVEL_INFO, /* Debug Level "Information" */ - LOG_LEVEL_MAX, +/* log level */ +enum { + LOG_LEVEL_ERROR, + LOG_LEVEL_WARN, + LOG_LEVEL_INFO, + LOG_LEVEL_DEBUG, + LOG_LEVEL_TRACE, + LOG_LEVEL_MAX }; +enum { + LOG_LOCK_DISABLE, /* disable lock */ + LOG_LOCK_ENABLE, /* enable lock */ +}; + +#define ROLLBACK_NONE 0 + +/* description: Initial the logger system + * arguments : + * $fname: logger file name, NULL/"console"/"stderr" will log to console + * $level: logger level above; + * $size : logger file max size in KiB + * $lock : thread lock enable or not + * return : <0: Failed ==0: Sucessfully + */ +int log_open(char *fname, int level, int size, int lock); -/* logger->flag definition */ -#define FLAG_LOGGER_LEVEL_OPT 1<<0 /* The log level is sepcified by the command option */ +/* description: Terminate the logger system */ +void log_close(void); -#define FLAG_LOGGER_CONSOLE 1<<1 -#define FLAG_LOGGER_FILE 0<<1 -typedef struct logger_s -{ - unsigned char flag; - char file[FILENAME_LEN]; - int level; - int size; +/* description: log message into log file. Don't call this function directly. */ +void _log_write(int level, const char *file, int line, const char *fmt, ...); - FILE *fp; -} logger_t; -extern char *log_str[]; +/* description: dump a buffer in hex to logger file */ +void log_dump(int level, const char *prompt, char *buf, size_t len); -/* log_size unit is KB */ -extern int log_open(logger_t *logger, char *filename, int level, int log_size); -extern int log_reopen(void); -extern void log_close(void); +/* function: log message into logger file with different log level */ +#define log_trace(...) _log_write(LOG_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) _log_write(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) _log_write(LOG_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) _log_write(LOG_LEVEL_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) _log_write(LOG_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__) -/* lowlvel API */ -extern void logger_raw(const char *fmt, ...); -extern void logger_min(int level, char *fmt, ...); -extern void logger_line(int level, char *file, int line, char *fmt, ...); -extern void logger_str(int level, const char *msg); -extern void logger_dump(int level, char *buf, int len); - -#define LOG_FILE_LINE /* Log the file and line */ - -#ifdef LOG_FILE_LINE -#define log_info(fmt, ...) logger_line(LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define log_dbg(fmt, ...) logger_line(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define log_nrml(fmt, ...) logger_line(LOG_LEVEL_NRML, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define log_warn(fmt, ...) logger_line(LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define log_err(fmt, ...) logger_line(LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#else -#define log_info(fmt, ...) logger_min(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__) -#define log_dbg(fmt, ...) logger_min(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__) -#define log_nrml(fmt, ...) logger_min(LOG_LEVEL_NRML, fmt, ##__VA_ARGS__) -#define log_warn(fmt, ...) logger_min(LOG_LEVEL_WARN, fmt, ##__VA_ARGS__) -#define log_err(fmt, ...) logger_min(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__) #endif - -#endif /* ----- #ifndef _LOGGER_H_ ----- */ - diff --git a/booster/makefile b/booster/makefile index 745ae81..0fd869e 100644 --- a/booster/makefile +++ b/booster/makefile @@ -1,13 +1,33 @@ +#******************************************************************************** +# Copyright: (C) 2023 LingYun IoT System Studio +# All rights reserved. +# +# Filename: Makefile +# Description: This file used compile all the source code to static library +# +# Version: 1.0.0(11/08/23) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "11/08/23 16:18:43" +# +#******************************************************************************* PWD=$(shell pwd ) +BUILD_ARCH=$(shell uname -m) +ifneq ($(findstring $(BUILD_ARCH), "x86_64" "i386"),) + CROSS_COMPILE?=arm-linux-gnueabihf- +endif + +#CROSS_COMPILE= + LIBNAME=$(shell basename ${PWD} ) TOPDIR=$(shell dirname ${PWD} ) +CFLAGS+=-D_GNU_SOURCE all: clean @rm -f *.o - @${CROSSTOOL}gcc ${CFLAGS} -I${TOPDIR} -c *.c - ${CROSSTOOL}ar -rcs lib${LIBNAME}.a *.o + @${CROSS_COMPILE}gcc ${CFLAGS} -I${TOPDIR} -c *.c + ${CROSS_COMPILE}ar -rcs lib${LIBNAME}.a *.o clean: @rm -f *.o @@ -15,4 +35,3 @@ distclean: @make clean - @rm -f cscope.* tags diff --git a/booster/ringbuf.c b/booster/ringbuf.c index f79d496..8902a4d 100644 --- a/booster/ringbuf.c +++ b/booster/ringbuf.c @@ -1,15 +1,16 @@ -/******************************************************************************** - * Copyright: (C) 2021 LingYun IoT System Studio +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * - * Filename: ringbuf.h - * Description: This head file + * Filename: ringbuf.c + * Description: This file is common ring buffer API functions * - * Version: 1.0.0(2021年04月29日) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "2021年04月29日 12时18分32秒" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ + #include <string.h> #include <assert.h> #include "ringbuf.h" @@ -100,7 +101,7 @@ unsigned char rb_peek(struct ring_buffer* rb, int index) { - assert(index < rb_data_size(rb)); + assert(index < rb_data_size(rb)); - return rb->buffer[((rb->rd_pointer + index) % rb->size)]; + return rb->buffer[((rb->rd_pointer + index) % rb->size)]; } diff --git a/booster/ringbuf.h b/booster/ringbuf.h index 23553cc..26153eb 100644 --- a/booster/ringbuf.h +++ b/booster/ringbuf.h @@ -1,13 +1,13 @@ -/******************************************************************************** - * Copyright: (C) 2021 LingYun IoT System Studio +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio. * All rights reserved. * * Filename: ringbuf.h - * Description: This head file + * Description: This file is common ring buffer API functions * - * Version: 1.0.0(2021年04月29日) + * Version: 1.0.0(11/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "2021年04月29日 12时18分32秒" + * ChangeLog: 1, Release initial version on "11/08/23 16:18:43" * ********************************************************************************/ @@ -16,7 +16,7 @@ struct ring_buffer { - unsigned char *buffer; + unsigned char *buffer; int wr_pointer; int rd_pointer; int size; diff --git a/booster/test/gpio-scripts/pinctrl-rzboard b/booster/test/gpio-scripts/pinctrl-rzboard deleted file mode 100755 index facd6cf..0000000 --- a/booster/test/gpio-scripts/pinctrl-rzboard +++ /dev/null @@ -1,144 +0,0 @@ -#!/bin/bash -# This shell script used to control GPIO port on RzBoard - -direction=out -sysdir=/sys/class/gpio/ -pinbase=120 -groupin=8 - -pinnum= -pindir= -action= - -set -u -set -e - -# RedLed: P8_1 GreenLed: P17_2 BlueLed: P19_1 -# UserKey: P39_0 -function usage() -{ - echo "Show pinmap Usage: $0 [-v]" - echo "Output set Usage: $0 P9_1 [1/0]" - echo "Input read Usage: $0 [-i] P9_1" - echo "Unexport Usage: $0 [-u] P9_1" - exit; -} - -function show_pinmap() -{ - echo " - +--------------------+--RzBoard--+--------------------+ - | Name/GPIO | Physical | Name/GPIO | - +--------------------+-----++----+--------------------+ - | 3.3v | 1 || 2 | 5v | - | SDA2(P3_0) | 3 || 4 | 5v | - | SCL2(P3_1) | 5 || 6 | GND | - | GPIO(P12_0) | 7 || 8 | TXD2(P48_0) | - | GND | 9 || 10 | RXD2(P48_1) | - | SCL3(P48_3) | 11 || 12 | GPIO(P17_1) | - | SDA3(P48_2) | 13 || 14 | GND | - | GPIO(P17_0) | 15 || 16 | GPIO(P13_2) | - | 3.3v | 17 || 18 | GPIO(P14_0) | - | SPI1_MOSI(P44_1) | 19 || 20 | GND | - | SPI1_MISO(P44_2) | 21 || 22 | GPIO(P39_1) | - | SPI1_CLK(P44_0) | 23 || 24 | SPI1_SS(P44_3) | - | GND | 25 || 26 | GPIO(P0_1) | - | GPIO(P14_1) | 27 || 28 | GPIO(P46_3) | - | GPIO(P42_3) | 29 || 30 | GND | - | GPIO(P42_4) | 31 || 32 | GPIO(P15_1) | - | GPIO(P10_0) | 33 || 34 | GND | - | GPIO(P9_1) | 35 || 36 | RTS2(P48_4) | - | GPIO(P13_1) | 37 || 38 | CAN0_RX(P11_0) | - | GND | 39 || 40 | CAN0_TX(P10_1) | - +--------------------+-----++----+--------------------+ - | Name/GPIO | Physical | Name/GPIO | - +--------------------+--RzBoard--+--------------------+ - " - exit 0; -} - -function calc_pinum() -{ - pinstr=$1 - - group=`echo $pinstr | cut -d_ -f1 | tr -cd "[0-9]"` - pin=`echo $pinstr | cut -d_ -f2 | tr -cd "[0-9]"` - - pinum=`expr $group \* $groupin + $pin + $pinbase` - pindir=$sysdir/gpio$pinum - - #echo "INFO: GPIO $pinstr map to pinum[$pinum]" -} - -function export_gpio() -{ - if [ -e $pindir ] ; then - return ; - fi - - echo $pinum > $sysdir/export -} - -function unexport_gpio() -{ - if [ ! -e $pindir ] ; then - return ; - fi - - echo $pinum > $sysdir/unexport -} - -function set_gpio() -{ - echo out > $pindir/direction - echo $1 > $pindir/value -} - -function read_gpio() -{ - echo in > $pindir/direction - cat $pindir/value -} - -if [ $# -lt 1 ] ; then - usage; -fi - -while getopts "iuvh" OPTNAME -do - case "${OPTNAME}" in - "i") - direction=in - shift - ;; - - "u") - action=unexport; - shift - ;; - - "v") - show_pinmap; - shift - ;; - - "h") - usage; - ;; - esac -done - -calc_pinum $1 - -if [[ $action == unexport ]] ; then - unexport_gpio - exit; -fi - -export_gpio - -if [ $direction == in ] ; then - read_gpio -else - set_gpio $2 -fi diff --git a/booster/test/logger.c b/booster/test/logger.c deleted file mode 100644 index 851ba9a..0000000 --- a/booster/test/logger.c +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************************************* - * Copyright: (C) 2021 LingYun IoT System Studio - * All rights reserved. - * - * Filename: logger.c - * Description: This file is logger system sample code. - * - * Version: 1.0.0(17/07/21) - * Author: Guo Wenxue <guowenxue@gmail.com> - * ChangeLog: 1, Release initial version on "17/07/21 15:51:04" - * - ********************************************************************************/ -#include "logger.h" - -#define LOG_FILE "test.log" - -int main (int argc, char **argv) -{ - int rv; - logger_t log; - -#ifdef LOG_FILE - if( log_open(&log, "test.log", LOG_LEVEL_NRML, 512) < 0 ) -#else - if( log_open(&log, LOG_STDERR, LOG_LEVEL_DEBUG, LOG_ROLLBACK_NONE) < 0 ) -#endif - { - fprintf(stderr, "initialise logger system failure, rv=%d\n", rv); - return -1; - } - - log_info("logger level [information] message\n"); - log_dbg ("logger level [ debug ] message\n"); - log_nrml("logger level [ normal ] message\n"); - log_warn("logger level [ warnning ] message\n"); - log_err ("logger level [ error ] message\n"); - - log_close(); - - return 0; -} - diff --git a/booster/test/makefile b/booster/test/makefile index 43a40ee..27eda01 100644 --- a/booster/test/makefile +++ b/booster/test/makefile @@ -1,37 +1,64 @@ +#********************************************************************************* +# Copyright: (C) 2022 Guo Wenxue +# All rights reserved. +# +# Filename: Makefile +# Description: This Makefile used to compile all the C source code file in current +# folder to respective excutable binary files. +# +# Version: 1.0.0(03/15/2022~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "03/15/2022 01:29:33 PM" +# +#********************************************************************************/ PWD=$(shell pwd) +LIB_PATH=$(shell dirname ${PWD}) +LIB_NAME=$(shell basename ${LIB_PATH}) +INSTPATH=/tftp -INST_PATH=/tftp +#ARCH ?= i386 +#ARCH?=arm926t +ARCH?=arm920t -LIB_PATH=$(shell dirname ${PWD} ) -LIB_NAME=$(shell basename ${LIB_PATH} ) +#LINK_MODE=STATIC +MODE=PRODUCTION +DEBUG=1 -CFLAGS+=-I${LIB_PATH} -LDFLAGS+=-L${LIB_PATH} -l${LIB_NAME} -lpthread +INSTPATH=/tftp + +CROSS_COMPILE?=arm-linux-gnueabihf- + +export CC=${CROSS_COMPILE}gcc +export CXX=${CROSS_COMPILE}g++ +export AR=${CROSS_COMPILE}ar +export AS=${CROSS_COMPILE}as +export RANLIB=${CROSS_COMPILE}ranlib +export STRIP=${CROSS_COMPILE}strip + +SRCS = $(wildcard ${VPATH}/*.c) +OBJS = $(patsubst %.c,%.o,$(SRCS)) SRCFILES = $(wildcard *.c) BINARIES=$(SRCFILES:%.c=%) -all: libs binaries - @make install +CFLAGS+=-I${LIB_PATH} +LDFLAGS+=-L${LIB_PATH} -l${LIB_NAME} -libs: - make -C ${LIB_PATH} +all: binaries install binaries: ${BINARIES} - @echo " Compile over" %: %.c - ${CROSSTOOL}gcc $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) install: - cp ${BINARIES} ${INST_PATH} + cp $(BINARIES) ${INSTPATH} clean: - @rm -f ${BINARIES} - @rm -f *.log + @rm -f *.o *.log $(BINARIES) -distclean: - @make clean - @make clean -C ${LIB_PATH} - @rm -f cscope.* tags +distclean: clean + @rm -f tags cscope* + +.PHONY: clean entry diff --git a/booster/test/test_logger.c b/booster/test/test_logger.c new file mode 100644 index 0000000..e6ee293 --- /dev/null +++ b/booster/test/test_logger.c @@ -0,0 +1,45 @@ +/********************************************************************************* + * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> + * All rights reserved. + * + * Filename: test_logger.c + * Description: This is the linux logger system test code. + * + * Version: 1.0.0(08/08/2012~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "08/08/2012 06:51:40 PM" + * + ********************************************************************************/ + +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <libgen.h> +#include "logger.h" + +int main (int argc, char **argv) +{ + char buf[256]; + int i; + + for(i=0; i<sizeof(buf); i++) + buf[i] = i; + +#if 1 + log_open("console", LOG_LEVEL_DEBUG, 0, LOG_LOCK_DISABLE); +#else + log_open("test.log", LOG_LEVEL_DEBUG, 10, LOG_LOCK_DISABLE); +#endif + + log_error("This is a errorr message\n"); + log_warn("This is a warnning message\n"); + log_info("This is a informat message\n"); + log_debug("This is a debug message\n"); + log_trace("This is a trace message\n"); + + log_dump(LOG_LEVEL_DEBUG, "Hex dump buffer content:", buf, sizeof(buf)); + + log_close(); + return 0; +} + diff --git a/booster/util_proc.c b/booster/util_proc.c index a17ea29..dfdabae 100644 --- a/booster/util_proc.c +++ b/booster/util_proc.c @@ -13,12 +13,14 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> -#include <libgen.h> +#include <errno.h> #include <fcntl.h> +#include <libgen.h> +#include <pthread.h> #include <sys/types.h> #include <sys/stat.h> -#include <pthread.h> #include "util_proc.h" #include "logger.h" @@ -64,7 +66,7 @@ { struct sigaction sigact, sigign; - log_nrml("Install default signal handler.\n"); + log_info("Install default signal handler.\n"); /* Initialize the catch signal structure. */ sigemptyset(&sigact.sa_mask); @@ -159,7 +161,7 @@ if( check_daemon_running(pidfile) ) { - log_err("Program already running, process exit now"); + log_error("Program already running, process exit now"); return -1; } @@ -167,7 +169,7 @@ { if( set_daemon_running(pidfile) < 0 ) { - log_err("set program running as daemon failure\n"); + log_error("set program running as daemon failure\n"); return -2; } } @@ -175,7 +177,7 @@ { if( record_daemon_pid(pidfile) < 0 ) { - log_err("record program running PID failure\n"); + log_error("record program running PID failure\n"); return -3; } } @@ -209,7 +211,7 @@ { if (mkdir(ipc_dir, mode) < 0) { - log_err("cannot create %s: %s\n", ipc_dir, strerror(errno)); + log_error("cannot create %s: %s\n", ipc_dir, strerror(errno)); return -1; } @@ -225,11 +227,11 @@ write(fd, pid, strlen(pid)); close(fd); - log_dbg("Record PID<%u> to file %s.\n", getpid(), pid_file); + log_debug("Record PID<%u> to file %s.\n", getpid(), pid_file); } else { - log_err("cannot create %s: %s\n", pid_file, strerror(errno)); + log_error("cannot create %s: %s\n", pid_file, strerror(errno)); return -1; } @@ -257,7 +259,7 @@ } else { - log_err("Can't open PID record file %s: %s\n", pid_file, strerror(errno)); + log_error("Can't open PID record file %s: %s\n", pid_file, strerror(errno)); return -1; } return pid; @@ -356,11 +358,11 @@ int set_daemon_running(const char *pid_file) { daemonize(0, 1); - log_nrml("Program running as daemon [PID:%d].\n", getpid()); + log_info("Program running as daemon [PID:%d].\n", getpid()); if (record_daemon_pid(pid_file) < 0) { - log_err("Record PID to file \"%s\" failure.\n", pid_file); + log_error("Record PID to file \"%s\" failure.\n", pid_file); return -2; } diff --git a/booster/util_proc.h b/booster/util_proc.h index 4af3cf2..89856c6 100644 --- a/booster/util_proc.h +++ b/booster/util_proc.h @@ -15,6 +15,7 @@ #define __UTIL_PROC_H_ #include <signal.h> +#include <time.h> #define PID_ASCII_SIZE 11 @@ -59,9 +60,30 @@ * | Low level API | * +---------------------+*/ - - /* get daemon process ID from $pid_file */ extern pid_t get_daemon_pid(const char *pid_file); +/* +------------------------+ + * | inline functions API | + * +------------------------+*/ +static inline void msleep(unsigned long ms) +{ + struct timespec cSleep; + unsigned long ulTmp; + + cSleep.tv_sec = ms / 1000; + if (cSleep.tv_sec == 0) + { + ulTmp = ms * 10000; + cSleep.tv_nsec = ulTmp * 100; + } + else + { + cSleep.tv_nsec = 0; + } + + nanosleep(&cSleep, 0); + return ; +} + #endif -- Gitblit v1.9.1