diff --git a/EC20xlib.cpp b/EC20xlib.cpp new file mode 100644 index 0000000..92ab58a --- /dev/null +++ b/EC20xlib.cpp @@ -0,0 +1,475 @@ +#include +#include "EC20xlib.h" + +#define min _min +#define max _max + + +///////////////////////////////////////////// +// Public methods. +// + +EC20xlib::EC20xlib(Stream &serial) { +#ifndef ESP32 +#ifdef ESP8266 + EC20xconn = new SoftwareSerial(receivePin, transmitPin, false, 1024); +#else + EC20xconn = new SoftwareSerial(receivePin, transmitPin, false); + +#endif + EC20xconn->setTimeout(100); +#else + EC20xconn = &serial; + + EC20xconn->setTimeout(100);//阻塞时间 +#endif +} + + +EC20xlib::~EC20xlib() { + + //delete EC20xconn; +} + + +// Block until the module is ready. +byte EC20xlib::blockUntilReady(long baudRate) { + + byte response = EC20x_NOTOK; + while (EC20x_OK != response) { + response = begin(); + // This means the modem has failed to initialize and we need to reboot + // it. + if (EC20x_FAILURE == response) { + return EC20x_FAILURE; + } + delay(1000); + logln("Waiting for module to be ready..."); + } + return EC20x_OK; +} + + +// Initialize the software serial connection and change the baud rate from the +// default (autodetected) to the desired speed. +byte EC20xlib::begin() { + + EC20xconn->flush(); + + // Factory reset. + if (EC20x_OK != EC20xcommand("AT", "OK", "yy", EC20x_CMD_TIMEOUT, 20, NULL)) return EC20x_FAILURE; + + // Echo off. + if (EC20x_OK != EC20xcommand("ATE0", "OK", "yy", EC20x_CMD_TIMEOUT, 2, NULL)) return EC20x_FAILURE; + + // Echo off. + if (EC20x_OK != EC20xcommand("ATI", "OK", "yy", EC20x_CMD_TIMEOUT, 2, NULL)) return EC20x_FAILURE; + // 检查SIM卡是否在位 + if (EC20x_OK != EC20xcommand("AT+CPIN?", "+CPIN: READY", "yy", EC20x_CMD_TIMEOUT, 2, NULL)) return EC20x_FAILURE; + + // 检查CSQ + if (EC20x_OK != EC20xcommand("AT+CSQ", "OK", "yy", EC20x_CMD_TIMEOUT, 2, NULL)) return EC20x_FAILURE; + + // 查看是否注册GSM网络 + if (EC20x_OK != EC20xcommand("AT+CREG?", "+CREG: 0,1", "+CREG: 0,5", EC20x_CMD_TIMEOUT, 20, NULL)) return EC20x_FAILURE; + + // 查看是否注册GPRS网络 + if (EC20x_OK != EC20xcommand("AT+CGREG?", "+CGREG: 0,1", "+CGREG: 0,5", EC20x_CMD_TIMEOUT, 20, NULL)) return EC20x_FAILURE; + + return EC20x_OK; +} + + +// Reboot the module by setting the specified pin HIGH, then LOW. The pin should +// be connected to a P-MOSFET, not the EC20x's POWER pin. +void EC20xlib::powerCycle(int pin) { + logln("Power-cycling module..."); + + powerOff(pin); + + delay(2000); + + powerOn(pin); + + // Give the module some time to settle. + logln("Done, waiting for the module to initialize..."); + delay(20000); + logln("Done."); + + EC20xconn->flush(); +} + + +// Turn the modem power completely off. +void EC20xlib::powerOff(int pin) { + pinMode(pin, OUTPUT); + digitalWrite(pin, LOW); +} + + +// Turn the modem power on. +void EC20xlib::powerOn(int pin) { + pinMode(pin, OUTPUT); + digitalWrite(pin, HIGH); +} + +// Get the strength of the GSM signal. +int EC20xlib::getSignalStrength() { + String response = ""; + uint32_t respStart = 0; + int strength, error = 0; + + // Issue the command and wait for the response. + EC20xcommand("AT+CSQ", "OK", "+CSQ", EC20x_CMD_TIMEOUT, 2, &response); + + respStart = response.indexOf("+CSQ"); + if (respStart < 0) { + return 0; + } + + sscanf(response.substring(respStart).c_str(), "+CSQ: %d,%d", + &strength, &error); + + // Bring value range 0..31 to 0..100%, don't mind rounding.. + strength = (strength * 100) / 31; + return strength; +} + +/************************************************ +*函数名:ReadCCID +*功能 :读取SIM卡CCID号 +*参数 :DataBuf(输出) CCID号码缓存 应大于20 +*返回 : 0 成功 1 失败 +************************************************/ +byte EC20xlib::Read_CCID(char *DataBuf) +{ + uint8_t re = 0; + uint32_t respStart = 0; + String response = ""; + //发送读取IMSI命令 + re=EC20xcommand("AT+CCID\r\n","+CCID","yy",EC20x_CMD_TIMEOUT, 2, &response); + Serial.println(response); + respStart = response.indexOf("+CCID"); + if (respStart < 0) { + return 0; + } + sscanf(response.substring(respStart).c_str(), "+CCID: %s",DataBuf); + + return re; +} +/************************************************ +*函数名:EC20_Read_IMEI +*功能 :读取模块IMEI号 +*参数 :DataBuf(输出) IMEI号码缓存 应大于20 +*返回 : 0 成功 1 失败 +************************************************/ +byte EC20xlib::Read_IMEI(char *DataBuf) +{ + uint8_t re = 0; + String response = ""; + //发送读取IMSI命令 + re = EC20xcommand("AT+GSN","OK","yy",EC20x_CMD_TIMEOUT, 2, &response); + Serial.println(response); + + response = response.substring(2, 18); + Serial.println(response); + response.toCharArray(DataBuf,16,0); + Serial.println(DataBuf); + return re; +} + +// Get the real time from the modem. Time will be returned as yy/MM/dd,hh:mm:ss+XX +String EC20xlib::getRealTimeClock() { + String response = ""; + + // Issue the command and wait for the response. + EC20xcommand("AT+CCLK?", "OK", "yy", EC20x_CMD_TIMEOUT, 1, &response); + int respStart = response.indexOf("+CCLK: \"") + 8; + response.setCharAt(respStart - 1, '-'); + + return response.substring(respStart, response.indexOf("\"")); +} + +///////////////////////////////////////////// +// Private methods. +// + +// Read some data from the EC20x in a non-blocking manner. +String EC20xlib::read() { + String reply = ""; + if (EC20xconn->available()) { + reply = EC20xconn->readString(); + } + + // XXX: Replace NULs with \xff so we can match on them. + for (int x = 0; x < reply.length(); x++) { + if (reply.charAt(x) == 0) { + reply.setCharAt(x, 255); + } + } + return reply; +} + +// 发送AT命令 +// Issue a command. +byte EC20xlib::EC20xcommand(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) { + byte returnValue = EC20x_NOTOK; + byte count = 0; + + // Get rid of any buffered output. + EC20xconn->flush(); + + while (count < repetitions && returnValue != EC20x_OK) { + log("Issuing command: "); + logln(command); + + EC20xconn->write(command); + EC20xconn->write('\r'); + + if (EC20xwaitFor(resp1, resp2, timeout, response) == EC20x_OK) { + returnValue = EC20x_OK; + } else { + returnValue = EC20x_NOTOK; + } + count++; + } + return returnValue; +} + + +// Wait for responses. +byte EC20xlib::EC20xwaitFor(const char *resp1, const char *resp2, int timeout, String *response) { + unsigned long entry = millis(); + String reply = ""; + byte retVal = 99; + do { + reply += read(); +#ifdef ESP8266 + yield(); +#endif + } while (((reply.indexOf(resp1) + reply.indexOf(resp2)) == -2) && ((millis() - entry) < timeout)); + + if (reply != "") { + log("Reply in "); + log((millis() - entry)); + log(" ms: "); + logln(reply); + } + + if (response != NULL) { + *response = reply; + } + + if ((millis() - entry) >= timeout) { + retVal = EC20x_TIMEOUT; + logln("Timed out."); + } else { + if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) { + logln("Reply OK."); + retVal = EC20x_OK; + } else { + logln("Reply NOT OK."); + retVal = EC20x_NOTOK; + } + } + return retVal; +} + +// Read some data from the EC20x in a non-blocking manner. +byte EC20xlib::connectMqttServer(char *clientID,char *ip,char *port,char *username,char *password) { + char sendbuf[100]; + String response = ""; + + uint32_t respStart = 0; + int client_idx = 0, error = 0,result = 0; + for(int i = 0; i<2;i++) + { + sprintf(sendbuf,"AT+QMTOPEN=0,\"%s\",%s",ip,port); + if (EC20x_OK == EC20xcommand(sendbuf, "+QMTOPEN:", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + { + respStart = response.indexOf("+QMTOPEN:"); + if (respStart < 0) { + return EC20x_FAILURE; + } + sscanf(response.substring(respStart).c_str(), "+QMTOPEN: %d,%d", + &client_idx, &error); + + if(error == EC20x_OK)//连接成功 + { + sprintf(sendbuf,"AT+QMTCONN=0,\"%s\",\"%s\",\"%s\"",clientID,username,password); + if (EC20x_OK == EC20xcommand(sendbuf, "+QMTCONN:", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + { + respStart = response.indexOf("+QMTCONN:"); + if (respStart < 0) { + return EC20x_FAILURE; + } + sscanf(response.substring(respStart).c_str(), "+QMTCONN: %d,%d,%d", + &client_idx,&result, &error); + if(error == EC20x_OK) + { + return EC20x_OK; + logln("connect OK."); + } + else return EC20x_FAILURE; + } + else return EC20x_FAILURE; + } + else if(error == 2)//MQTT 标识符被占用,需要先断开重新连接 + { + if (EC20x_OK != EC20xcommand("AT+QMTCLOSE=0", "+QMTCLOSE: 0,0", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + return EC20x_FAILURE; + } + else return EC20x_FAILURE; + } + else return EC20x_FAILURE; + } + return EC20x_FAILURE; + /* + sprintf(sendbuf,"AT+QMTOPEN=0,\"%s\",%s",ip,port); + if (EC20x_OK != EC20xcommand(sendbuf, "+QMTOPEN: 0,0", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + { + if (EC20x_OK != EC20xcommand("AT+QMTCLOSE=0", "+QMTCLOSE: 0,0", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + return EC20x_FAILURE; + if (EC20x_OK != EC20xcommand(sendbuf, "+QMTOPEN: 0,0", "yy", EC20x_CMD_TIMEOUT+3000, 3, &response)) + return EC20x_FAILURE; + } + + memset(sendbuf,0,sizeof(sendbuf)); + sprintf(sendbuf,"AT+QMTCONN=0,\"%s\",\"%s\",\"%s\"",clientID,username,password); + if (EC20x_OK != EC20xcommand(sendbuf, "+QMTCONN: 0,0,0", "yy", EC20x_CMD_TIMEOUT, 3, &response)) return EC20x_FAILURE; + logln("connect OK."); + + return EC20x_OK; + */ +} + +/* +取消订阅主题 +*/ +byte EC20xlib::UnSubTopic(char *topic,uint8_t qos1) +{ + char data_buff[300];//格式化AT指令时使用 + + logln("UnSubTopic"); + //订阅需要的主题 + sprintf(data_buff,"AT+QMTUNS=0,%d,%s",1,topic); + if (EC20x_OK != EC20xcommand(data_buff,"OK","yy",5000,5,NULL)) return EC20x_FAILURE; + return EC20x_OK; +} +/* +订阅主题 +*/ +byte EC20xlib::SubTopic(char *topic,uint8_t qos1) +{ + char data_buff[300];//格式化AT指令时使用 + + logln("SubTopic"); + //订阅需要的主题 + sprintf(data_buff,"AT+QMTSUB=0,%d,\"%s\",%d",1,topic,qos1); + if (EC20x_OK != EC20xcommand(data_buff,"OK","yy",5000,5,NULL)) return EC20x_FAILURE; + return EC20x_OK; +} +/* +发布主题 +*/ +byte EC20xlib::PubTopic(char *topic,char* msg,uint8_t qos1)//typ_NEC_AQData *AQData_Send, +{ + char data_buff[300];//格式化AT指令时使用 + + logln("PubTopic"); + sprintf(data_buff,"AT+QMTPUBEX=0,0,%d,0,\"%s\",%d",qos1,topic,strlen(msg)); + if (EC20x_OK != EC20xcommand(data_buff,">","yy",5000,5,NULL)) return EC20x_FAILURE; + if (EC20x_OK != EC20xcommand(msg,"OK","yy",5000,5,NULL)) return EC20x_FAILURE; + return EC20x_OK; +} + +/* +发布主题 +*/ +byte EC20xlib::getMessage(char *topic,char* msg,uint8_t qos1)//typ_NEC_AQData *AQData_Send, +{ + unsigned long entry = millis(); + int commaPosition,last_commaPosition;//存储还没有分离出来的字符串 + String reply = ""; + byte retVal = 99; + reply += read(); +#ifdef ESP32 + yield(); +#endif + if (reply != "") { + log("Reply in "); + log((millis() - entry)); + log(" ms: "); + logln(reply); + if(reply.indexOf("+QMTRECV:") != -1) + { + logln("recv data"); + uint8_t i = 0; + for(i = 0;i<3;i++) + { + commaPosition = reply.indexOf(',');//检测字符串中的逗号 + + if(commaPosition != -1)//如果有逗号存在就向下执行 + { + if(i == 2)//获取topic + { + logln( reply.substring(1,commaPosition-1));//打印出第一个逗号位置的字符串 + reply.substring(1,commaPosition-1).toCharArray(topic,reply.substring(1,commaPosition-1).length()+1); + } + + reply = reply.substring(commaPosition+1, reply.length());//打印字符串,从当前位置+1开始 + } + } + if(1)//获取topic的内容 + { + commaPosition = reply.indexOf('"'); + last_commaPosition = reply.lastIndexOf('"'); + logln( reply.substring(commaPosition+1,last_commaPosition));//打印出第一个逗号位置的字符串 + reply.substring(commaPosition+1,last_commaPosition).toCharArray(msg,reply.substring(commaPosition+1,last_commaPosition).length()+1); + } + retVal = EC20x_OK; + } + if(reply.indexOf("+QMTSTAT:") != -1) + { + logln("mqtt disconnect"); + /* + 整型。MQTT 客户端标识符。 + 整型。错误代码。详细信息请参考下表。 + + 1 连接被服务器断开或者重置 执行 AT+QMTOPEN 重建 MQTT 连接 + 2 发送 PINGREQ 包超时或者失败 首先反激活 PDP,然后再激活 PDP 并重建MQTT 连接。 + 3 发送 CONNECT 包超时或者失败 1. 查看输入的用户名和密码是否正确。 + 2. 确保客户端 ID 未被占用。 + 3. 重建 MQTT 连接,并尝试再次发送CONNECT 包到服务器。 + 4 接收 CONNACK 包超时或者失败 1. 查看输入的用户名和密码是否正确。 + 2. 确保客户端 ID 未被占用。 + 3. 重建 MQTT 连接,并尝试再次发送CONNECT 包到服务器。 + 5 客户端向服务器发送 DISCONNECT 包,但 + 是服务器主动断开 MQTT 连接 正常流程。 + 6 因为发送数据包总是失败,客户端主动断开MQTT 连接 1. 确保数据正确。 + 2. 可能因为网络拥堵或者其他错误,尝试重建 MQTT 连接。 + 7 链路不工作或者服务器不可用 确保当前链路或者服务器可用。 + 8 客户端主动断开 MQTT 连接 尝试重建连接。 + 9~255 留作将来使用 + */ + //重新连接 + retVal = EC20x_DISCONNECT; + } + if(reply.indexOf("+QMTPUBEX:") != -1) + { + logln("rev the result of public message"); + /* + 整型。MQTT 客户端标识符。范围:0~5。 + 整型。数据包消息标识符。范围:0~65535。只有当=0 时,该参数值为 0。 + 整型。命令执行结果。 + 0 数据包发送成功且接收到服务器的 ACK(当=0 时发布了数据,则无需 ACK) + 1 数据包重传 + 2 数据包发送失败 + */ + //接收到发送返回 + retVal = EC20x_DISCONNECT; + } + + } + return retVal; +} diff --git a/EC20xlib.h b/EC20xlib.h new file mode 100644 index 0000000..c7b85a5 --- /dev/null +++ b/EC20xlib.h @@ -0,0 +1,57 @@ +#ifndef EC20xlib_h +#define EC20xlib_h + +#include + +#define DEBUG +#ifdef DEBUG +#define log(msg) Serial.print(msg) +#define logln(msg) Serial.println(msg) +#else +#define log(msg) +#define logln(msg) +#endif + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +#define EC20x_OK 0 +#define EC20x_NOTOK 1 +#define EC20x_TIMEOUT 2 +#define EC20x_FAILURE 3 +#define EC20x_DISCONNECT 4 + +#define EC20x_CMD_TIMEOUT 2000 + +//#define EC20xconn Serial2 + +class EC20xlib { +public: + EC20xlib(Stream &serial); + ~EC20xlib(); + + byte begin(); + byte blockUntilReady(long baudRate); + + void powerCycle(int pin); + void powerOn(int pin); + void powerOff(int pin); + + int getSignalStrength(); + String getRealTimeClock(); + + byte connectMqttServer(char *clientID,char *ip,char *port,char *username,char *password); + byte SubTopic(char *topic,uint8_t qos1); + byte PubTopic(char *topic,char* msg,uint8_t qos1); + byte UnSubTopic(char *topic,uint8_t qos1); + byte getMessage(char *topic,char* msg,uint8_t qos1); + byte Read_CCID(char *DataBuf); + byte Read_IMEI(char *DataBuf); +private: + Stream* EC20xconn; + String read(); + byte EC20xcommand(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response); + byte EC20xwaitFor(const char *resp1, const char *resp2, int timeout, String *response); + long detectRate(); + char setRate(long baudRate); +}; +#endif diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..87c0133 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Stavros Korokithakis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index b52ede1..f6b4de6 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# EC20x_lib \ No newline at end of file +# EC20x_lib + diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..7edf2ff --- /dev/null +++ b/keywords.txt @@ -0,0 +1,35 @@ +####################################### +# A6 GSM communication module +# (esp8266) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EC20xlib KEYWORD1 +callInfo KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +powerCycle KEYWORD2 + +dial KEYWORD2 +redial KEYWORD2 +hangUp KEYWORD2 +checkCallStatus KEYWORD2 +getSignalStrength KEYWORD2 + +sendSMS KEYWORD2 + +setVol KEYWORD2 +enableSpeaker KEYWORD2 + +EC20xconn KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/library.json b/library.json new file mode 100644 index 0000000..e203fca --- /dev/null +++ b/library.json @@ -0,0 +1,14 @@ +{ + "name": "EC20xlib", + "keywords": [ + "EC20", "GSM", "CAT1", "mobile" + ], + "description": "An ESP8266/Arduino library for communicating with the EC20 cat1 module.", + "repository": + { + "type": "git", + "url": "https://github.com/luyang14/EC20x_lib.git" + }, + "frameworks": "arduino", + "platforms": "*" +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..c3e3ef0 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=EC20xlib +version=0.1.0 +author=Stavros Korokithakis +maintainer=iotts +sentence=An ESP8266/ESP32/Arduino library for communicating with the EC20 CAT1 module. +paragraph= +category=Communication +url=https://github.com/luyang14/EC20x_lib.git +architectures=* diff --git a/sscanf.cpp b/sscanf.cpp new file mode 100644 index 0000000..bafaeea --- /dev/null +++ b/sscanf.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Opsycon AB. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include + +#define MAXLN 200 +#define ISSPACE " \t\n\r\f\v\"" + +size_t strcspn(const char *p, const char *s) { + int i, j; + + for (i = 0; p[i]; i++) { + for (j = 0; s[j]; j++) { + if (s[j] == p[i]) { + break; + } + } + if (s[j]) { + break; + } + } + return (i); +} + +char * _getbase(char *p, int *basep) { + if (p[0] == '0') { + switch (p[1]) { + case 'x': + *basep = 16; + break; + case 't': + case 'n': + *basep = 10; + break; + case 'o': + *basep = 8; + break; + default: + *basep = 10; + return (p); + } + return (p + 2); + } + *basep = 10; + return (p); +} + +/* + * _atob(vp,p,base) + */ +int _atob(uint32_t *vp, char *p, int base) { + uint32_t value, v1, v2; + char *q, tmp[20]; + int digit; + + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + base = 16; + p += 2; + } + + if (base == 16 && (q = strchr(p, '.')) != 0) { + if (q - p > sizeof(tmp) - 1) { + return (0); + } + + strncpy(tmp, p, q - p); + tmp[q - p] = '\0'; + if (!_atob(&v1, tmp, 16)) { + return (0); + } + + q++; + if (strchr(q, '.')) { + return (0); + } + + if (!_atob(&v2, q, 16)) { + return (0); + } + *vp = (v1 << 16) + v2; + return (1); + } + + value = *vp = 0; + for (; *p; p++) { + if (*p >= '0' && *p <= '9') { + digit = *p - '0'; + } else if (*p >= 'a' && *p <= 'f') { + digit = *p - 'a' + 10; + } else if (*p >= 'A' && *p <= 'F') { + digit = *p - 'A' + 10; + } else { + return (0); + } + + if (digit >= base) { + return (0); + } + value *= base; + value += digit; + } + *vp = value; + return (1); +} + +/* + * atob(vp,p,base) + * converts p to binary result in vp, rtn 1 on success + */ +int atob(uint32_t *vp, char *p, int base) { + uint32_t v; + if (base == 0) { + p = _getbase(p, &base); + } + if (_atob(&v, p, base)) { + *vp = v; + return (1); + } + return (0); +} + +/* + * vsscanf(buf,fmt,ap) + */ + +int vsscanf(const char *buf, const char *s, va_list ap) { + uint32_t count, noassign, width, base, lflag; + const char *tc; + char *t, tmp[MAXLN]; + + count = noassign = width = lflag = 0; + while (*s && *buf) { + while (isspace(*s)) { + s++; + } + if (*s == '%') { + s++; + for (; *s; s++) { + if (strchr("dibouxcsefg%", *s)) { + break; + } + if (*s == '*') { + noassign = 1; + } else if (*s == 'l' || *s == 'L') { + lflag = 1; + } else if (*s >= '1' && *s <= '9') { + for (tc = s; isdigit(*s); s++); + strncpy(tmp, tc, s - tc); + tmp[s - tc] = '\0'; + atob(&width, tmp, 10); + s--; + } + } + if (*s == 's') { + while (isspace(*buf)) { + buf++; + } + if (!width) { + width = strcspn(buf, ISSPACE); + } + if (!noassign) { + strncpy(t = va_arg(ap, char *), buf, width); + t[width] = '\0'; + } + buf += width; + } else if (*s == 'c') { + if (!width) { + width = 1; + } + if (!noassign) { + strncpy(t = va_arg(ap, char *), buf, width); + t[width] = '\0'; + } + buf += width; + } else if (strchr("dobxu", *s)) { + while (isspace(*buf)) { + buf++; + } + if (*s == 'd' || *s == 'u') { + base = 10; + } else if (*s == 'x') { + base = 16; + } else if (*s == 'o') { + base = 8; + } else if (*s == 'b') { + base = 2; + } + if (!width) { + if (isspace(*(s + 1)) || *(s + 1) == 0) { + width = strcspn(buf, ISSPACE); + } else { + width = strchr(buf, *(s + 1)) - buf; + } + } + strncpy(tmp, buf, width); + tmp[width] = '\0'; + buf += width; + if (!noassign) { + atob(va_arg(ap, uint32_t *), tmp, base); + } + } + if (!noassign) { + count++; + } + width = noassign = lflag = 0; + s++; + } else { + while (isspace(*buf)) { + buf++; + } + if (*s != *buf) { + break; + } else { + s++, buf++; + } + } + } + return (count); +} + + +int __attribute__((used)) sscanf(const char *buf, const char *fmt, ...) { + int count; + va_list ap; + + va_start(ap, fmt); + count = vsscanf(buf, fmt, ap); + va_end(ap); + return (count); +}