diff --git a/MyConfig.h b/MyConfig.h index 84a5b1c..b8e0517 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -410,7 +410,7 @@ #define MY_RF24_CE_PIN 4 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CE_PIN 27 - #elif defined(LINUX) + #elif defined(__linux__) #define MY_RF24_CE_PIN 22 #else #define MY_RF24_CE_PIN 9 @@ -426,7 +426,7 @@ #define MY_RF24_CS_PIN 15 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CS_PIN 3 - #elif defined(LINUX) + #elif defined(__linux__) #define MY_RF24_CS_PIN 24 #else #define MY_RF24_CS_PIN 10 @@ -718,11 +718,11 @@ ***************************************/ /** - * @def MY_LINUX_TTY_NAME + * @def MY_LINUX_SERIAL_PORT * @brief Set the name of predictable tty */ -#ifndef MY_LINUX_TTY_NAME -#define MY_LINUX_TTY_NAME "/dev/ttyAMA0" +#ifndef MY_LINUX_SERIAL_PORT +#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0" #endif /** diff --git a/MySensors.h b/MySensors.h index d4c7a5a..77e36ac 100644 --- a/MySensors.h +++ b/MySensors.h @@ -69,7 +69,7 @@ #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" -#elif defined(LINUX) +#elif defined(__linux__) // Remove PSTR macros from debug prints #undef PSTR #define PSTR(x) (x) @@ -284,7 +284,9 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif - #if !defined(LINUX) + #if defined(__linux__) + #include "drivers/RF24/RF24_Linux.cpp" + #else #include "drivers/RF24/RF24.cpp" #endif #include "core/MyTransportNRF24.cpp" @@ -329,7 +331,7 @@ #if !defined(MY_CORE_ONLY) #if defined(ARDUINO_ARCH_ESP8266) #include "core/MyMainESP8266.cpp" - #elif defined(LINUX) + #elif defined(__linux__) #include "core/MyMainLinux.cpp" #else #include "core/MyMainDefault.cpp" diff --git a/configure b/configure index dc3012c..8df6e97 100755 --- a/configure +++ b/configure @@ -35,15 +35,10 @@ MySensors options: --my-debug=[enable|disable] Enables or disables debugging. Default to enable. - --my-gateway=[none|ethernet|mqtt] + --my-config-file= Config file path. [/etc/MySensorGateway.cfg] + --my-gateway=[none|ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. Default to ethernet. - --my-config-file= Config file path. [/etc/MySensorGateway.cfg] - --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. - Default to rf24. - --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. - --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] - RF24 PA level. --my-controller-url-address= Controller or MQTT broker url. --my-controller-ip-address= @@ -51,11 +46,18 @@ MySensors options: Use commas instead of points. Example: 127,0,0,1 --my-port= The port to keep open on gateway mode. If gateway is set to mqtt, it sets the broker port. + --my-serial-port= Serial port. [/dev/ttyUSB0] + --my-serial-baudrate= Serial baud rate. [115200] --my-mqtt-client-id= MQTT client id. --my-mqtt-publish-topic-prefix= MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. + --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. + Default to rf24. + --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. + --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] + RF24 PA level. --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. For RaspberryPi use BCM numbering. --my-rx-message-buffer-size= @@ -251,6 +253,12 @@ for opt do --my-radio=*) radio_type=${optarg} ;; + --my-serial-port=*) + CXXFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CXXFLAGS" + ;; + --my-serial-baudrate=*) + CXXFLAGS="-DMY_BAUD_RATE=${optarg} $CXXFLAGS" + ;; --my-rf24-channel=*) CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" ;; @@ -305,7 +313,7 @@ if [ -z "${CPUFLAGS}" ]; then CPUFLAGS=$(gcc_cpu_flags $SOC) fi -CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX $CXXFLAGS" +CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS" if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then CXXFLAGS+="-D__RPI_BPLUS" @@ -317,6 +325,8 @@ fi if [[ ${gateway_type} == "ethernet" ]]; then CXXFLAGS="-DMY_GATEWAY_LINUX $CXXFLAGS" +elif [[ ${gateway_type} == "serial" ]]; then + CXXFLAGS="-DMY_GATEWAY_SERIAL $CXXFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then LDFLAGS="-lmosquitto $LDFLAGS" CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index ee74731..bf48457 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -30,12 +30,12 @@ static const size_t _length = 1024; // ATMega328 has 1024 bytes static uint8_t _config[_length]; bool CheckConfigFile() { - struct stat fileInfo; + struct stat fileInfo; if (stat(CONFIG_FILE, &fileInfo) != 0) { //File does not exist. Create it. debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); if (!myFile) { debug("Unable to create config file %s.\n", CONFIG_FILE); return false; @@ -47,7 +47,7 @@ bool CheckConfigFile() { return false; } else { //Read config into local memory. - ifstream myFile(CONFIG_FILE, ios::in | ios::binary); + std::ifstream myFile(CONFIG_FILE, std::ios::in | std::ios::binary); if (!myFile) { debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); return false; @@ -68,6 +68,10 @@ void hwInit() if (!CheckConfigFile()) { exit(1); } + + #ifdef MY_GATEWAY_SERIAL + MY_SERIALDEVICE.begin(MY_BAUD_RATE); + #endif } void hwReadConfigBlock(void* buf, void* addr, size_t length) @@ -86,7 +90,7 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) if (length && offs + length <= _length) { memcpy(_config+offs, buf, length); - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); if (!myFile) { debug("Unable to write config to file %s.\n", CONFIG_FILE); return; diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 1d763ce..0d3e49b 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -20,10 +20,12 @@ #ifndef MyHwLinuxGeneric_h #define MyHwLinuxGeneric_h -#include "MyHw.h" #include #include +#include "MyHw.h" +#include "SerialPort.h" +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); #define MY_SERIALDEVICE Serial // Define these as macros (do nothing) @@ -35,8 +37,8 @@ void hwInit(); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); +void hwWriteConfig(int adr, uint8_t value); #ifdef MY_RF24_IRQ_PIN static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 2d0a9db..836f817 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -51,7 +51,7 @@ void _process() { transportProcess(); #endif - #if defined(LINUX) + #if defined(__linux__) // To avoid high cpu usage usleep(10000); // 10ms #endif @@ -65,7 +65,7 @@ void _infiniteLoop() { #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif - #if defined(LINUX) + #if defined(__linux__) exit(1); #endif } diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index ce39008..cdd3f2b 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -20,8 +20,8 @@ #include "MyConfig.h" #include "MyTransport.h" -#ifdef LINUX_ARCH_RASPBERRYPI - #include "drivers/RF24/RF24_Linux.cpp" +#ifdef __linux__ + #include "drivers/RF24/RF24_Linux.h" #else #include "drivers/RF24/RF24.h" #endif diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 08e9701..e1dc088 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -1,18 +1,17 @@ #ifndef Arduino_h #define Arduino_h -#include +#include #include - -#ifdef __cplusplus - #include - - using namespace std; - - extern "C" { -#endif - -void yield(void); +#include +#include +#include +#include +#include +#include +#include +#include +#include "stdlib_noniso.h" #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 @@ -21,17 +20,11 @@ void yield(void); #define RAD_TO_DEG 57.295779513082320876798154814105 #define EULER 2.718281828459045235360287471352 -#ifndef __cplusplus - #define min(a,b) ((a)<(b)?(a):(b)) - #define max(a,b) ((a)>(b)?(a):(b)) - #define abs(x) ((x)>0?(x):-(x)) - #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) -#endif - #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) #define radians(deg) ((deg)*DEG_TO_RAD) #define degrees(rad) ((rad)*RAD_TO_DEG) #define sq(x) ((x)*(x)) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) #define lowByte(w) ((uint8_t) ((w) & 0xff)) #define highByte(w) ((uint8_t) ((w) >> 8)) @@ -43,19 +36,23 @@ void yield(void); #define bit(b) (1UL << (b)) +#define GET_MACRO(_0, _1, _2, NAME, ...) NAME +#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__) + +using std::string; +using std::min; +using std::max; +using std::abs; + typedef bool boolean; typedef uint8_t byte; +typedef string String; -char *itoa(int value, char* result, int base); -char *ltoa(long value, char* result, int base); -char *ultoa(long num, char *str, int radix); -char *utoa(int num, char *str, int radix); -char *dtostrf(float f, int width, int decimals, char *result); +void yield(void); unsigned long millis(void); void delay(unsigned int millis); - -#ifdef __cplusplus - } -#endif +void randomSeed(unsigned long seed); +long randMax(long howbig); +long randMinMax(long howsmall, long howbig); #endif diff --git a/drivers/Linux/Client.h b/drivers/Linux/Client.h index 067b57d..4f38ac2 100644 --- a/drivers/Linux/Client.h +++ b/drivers/Linux/Client.h @@ -21,6 +21,7 @@ #ifndef client_h #define client_h + #include "Stream.h" #include "IPAddress.h" diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index f21f5d3..78dc143 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -50,7 +50,7 @@ class EthernetClient : public Client { private: - int _sock; + int _sock; //!< @brief Network socket. public: /** diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp new file mode 100644 index 0000000..306b82c --- /dev/null +++ b/drivers/Linux/Print.cpp @@ -0,0 +1,238 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified December 2014 by Ivan Grokhotkov + Modified May 2015 by Michael C. Miller - esp8266 progmem support + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#include +#include +#include +#include +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +size_t Print::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while(size--) { + n += write(*buffer++); + } + return n; +} + +size_t Print::printf(const char *format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = write((const uint8_t*) buffer, len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} + +size_t Print::print(const std::string &s) { + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) { + return write(str); +} + +size_t Print::print(char c) { + return write(c); +} + +size_t Print::print(unsigned char b, int base) { + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) { + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) { + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) { + if(base == 0) { + return write(n); + } else if(base == 10) { + if(n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) { + if(base == 0) + return write(n); + else + return printNumber(n, base); +} + +size_t Print::print(double n, int digits) { + return printFloat(n, digits); +} + +size_t Print::println(void) { + return print("\r\n"); +} + +size_t Print::println(const std::string &s) { + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) { + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) { + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) { + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) { + size_t n = print(num, digits); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if(base < 2) + base = 10; + + do { + unsigned long m = n; + n /= base; + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) { + size_t n = 0; + + if(std::isnan(number)) + return print("nan"); + if(std::isinf(number)) + return print("inf"); + if(number > 4294967040.0) + return print("ovf"); // constant determined empirically + if(number < -4294967040.0) + return print("ovf"); // constant determined empirically + + // Handle negative numbers + if(number < 0.0) { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long) number; + double remainder = number - (double) int_part; + n += print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + n += print("."); + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + int toPrint = int(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/drivers/Linux/Print.h b/drivers/Linux/Print.h new file mode 100644 index 0000000..b63e7a1 --- /dev/null +++ b/drivers/Linux/Print.h @@ -0,0 +1,76 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#ifndef Print_h +#define Print_h + +#include +#include +#include + +#if !DOXYGEN +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print { + private: + size_t printNumber(unsigned long n, uint8_t base); + size_t printFloat(double number, uint8_t digits); + + public: + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) + return 0; + return write((const uint8_t *) str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *) buffer, size); + } + + size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); + size_t print(const std::string &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const std::string &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + }; + +#endif +#endif diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp new file mode 100644 index 0000000..732d102 --- /dev/null +++ b/drivers/Linux/SerialPort.cpp @@ -0,0 +1,159 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Marcelo Aquino + * Copyright (C) 2016 Marcelo Aquino + * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "SerialPort.h" + +#define SERIAL_PORT "/dev/ttyAMA0" + +SerialPort::SerialPort() +{ + SerialPort(SERIAL_PORT); +} + +SerialPort::SerialPort(const char *port) : serialPort(std::string(port)) +{} + +void SerialPort::begin(int bauds) +{ + speed_t speed; + struct termios options; + + if ((sd = open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { + fprintf(stderr, "Unable to open the serial port %s - \n", serialPort.c_str()); + exit(-1); + } + + // nonblocking mode + fcntl(sd, F_SETFL, FNDELAY); + + switch (bauds) { + case 50: speed = B50 ; break ; + case 75: speed = B75 ; break ; + case 110: speed = B110 ; break ; + case 134: speed = B134 ; break ; + case 150: speed = B150 ; break ; + case 200: speed = B200 ; break ; + case 300: speed = B300 ; break ; + case 600: speed = B600 ; break ; + case 1200: speed = B1200 ; break ; + case 1800: speed = B1800 ; break ; + case 2400: speed = B2400 ; break ; + case 9600: speed = B9600 ; break ; + case 19200: speed = B19200 ; break ; + case 38400: speed = B38400 ; break ; + case 57600: speed = B57600 ; break ; + case 115200: speed = B115200 ; break ; + default: speed = B115200 ; break ; + } + + // Get the current options of the port + if (tcgetattr(sd, &options) < 0) { + perror("Couldn't get term attributes"); + exit(1); + } + + // make raw + cfmakeraw(&options); + + // Set the baud rate + cfsetispeed(&options, speed); + cfsetospeed(&options, speed); + + // turn on READ & ignore ctrl lines + options.c_cflag |= (CLOCAL | CREAD); + // 8N1 + options.c_cflag &= ~CSTOPB; + + options.c_lflag &= ~ECHOE; + + // Timer unused + options.c_cc[VTIME]=0; + // At least on character before satisfy reading + options.c_cc[VMIN]=0; + + // Set parameters + if (tcsetattr(sd, TCSANOW, &options) < 0) { + perror("Couldn't set term attributes"); + exit(1); + } + + // flush + if (tcflush(sd, TCIOFLUSH) < 0) { + perror("Couldn't flush serial"); + exit(1); + } + + usleep(10000); +} + +int SerialPort::available() +{ + int nbytes = 0; + + if (ioctl(sd, FIONREAD, &nbytes) < 0) { + fprintf(stderr, "Failed to get byte count on serial.\n"); + exit(-1); + } + return nbytes; +} + +int SerialPort::read() +{ + unsigned char c; + + ::read(sd, &c, 1); + return c; +} + +size_t SerialPort::write(uint8_t b) +{ + return ::write(sd, &b, 1); +} + +size_t SerialPort::write(const uint8_t *buffer, size_t size) +{ + return ::write(sd, buffer, size); +} + +int SerialPort::peek() +{ + FILE * f = fdopen(sd, "r+"); + int c = getc(f); + if (c == EOF) return -1; + ungetc(c, f); + return c; +} + +void SerialPort::flush() +{ + tcflush(sd, TCIFLUSH); +} + +void SerialPort::end() +{ + close(sd); +} diff --git a/drivers/Linux/SerialPort.h b/drivers/Linux/SerialPort.h new file mode 100644 index 0000000..e344c6d --- /dev/null +++ b/drivers/Linux/SerialPort.h @@ -0,0 +1,100 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Marcelo Aquino + * Copyright (C) 2016 Marcelo Aquino + * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef SerialPort_h +#define SerialPort_h + +#include +#include "Stream.h" + +/** + * SerialPort Class + * Class that provides the functionality of arduino Serial library + */ +class SerialPort : public Stream { + +private: + int sd; //!< @brief file descriptor number. + std::string serialPort; //!< @brief tty name. + +public: + /** + * @brief SerialPort constructor. + */ + SerialPort(); + /** + * @brief SerialPort constructor. + */ + SerialPort(const char *port); + /** + * @brief Sets the data rate in bits per second (baud) for serial data transmission. + * + * @param serialSpeed serial port speed. + */ + void begin(int serialSpeed); + /** + * @brief Get the number of bytes available. + * + * Get the numberof bytes (characters) available for reading from + * the serial port. + * + * @return number of bytes avalable to read. + */ + int available(); + /** + * @brief Reads 1 byte of incoming serial data. + * + * @return first byte of incoming serial data available. + */ + int read(); + /** + * @brief Writes a single byte to the serial port. + * + * @param b byte to write. + * @return number of bytes written. + */ + size_t write(uint8_t b); + /** + * @brief Writes binary data to the serial port. + * + * @param buffer to write. + * @param size of the buffer. + * @return number of bytes written. + */ + size_t write(const uint8_t *buffer, size_t size); + /** + * @brief + * + * Returns the next byte (character) of incoming serial data without removing it from + * the internal serial buffer. + * + * @return -1 if no data else character in the buffer. + */ + int peek(); + /** + * @brief Remove any data remaining on the serial buffer. + */ + void flush(); + /** + * @brief Disables serial communication. + */ + void end(); +}; + +#endif diff --git a/drivers/Linux/Server.h b/drivers/Linux/Server.h index 7910e83..c637f7a 100644 --- a/drivers/Linux/Server.h +++ b/drivers/Linux/Server.h @@ -20,8 +20,10 @@ #ifndef server_h #define server_h +#include "Print.h" + #if !DOXYGEN -class Server { +class Server : public Print { public: virtual void begin() =0; }; diff --git a/drivers/Linux/Stream.cpp b/drivers/Linux/Stream.cpp new file mode 100644 index 0000000..1817083 --- /dev/null +++ b/drivers/Linux/Stream.cpp @@ -0,0 +1,258 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#include +#include + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() { + int c; + _startMillis = millis(); + do { + c = read(); + if(c >= 0) + return c; + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() { + int c; + _startMillis = millis(); + do { + c = peek(); + if(c >= 0) + return c; + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit() { + int c; + while(1) { + c = timedPeek(); + if(c < 0) + return c; // timeout + if(c == '-') + return c; + if(c >= '0' && c <= '9') + return c; + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + +// find returns true if the target string is found +bool Stream::find(const char *target) { + return findUntil(target, (char*) ""); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(const char *target, size_t length) { + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(const char *target, const char *terminator) { + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) { + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if(*target == 0) + return true; // return true if target is a null string + while((c = timedRead()) > 0) { + + if(c != target[index]) + index = 0; // reset index if any char does not match + + if(c == target[index]) { + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen) { // return true if all chars in the target match + return true; + } + } + + if(termLen > 0 && c == terminator[termIndex]) { + if(++termIndex >= termLen) + return false; // return false if terminate string found before target string + } else + termIndex = 0; + } + return false; +} + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() { + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) { + boolean isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do { + if(c == skipChar) + ; // ignore this charactor + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == skipChar); + + if(isNegative) + value = -value; + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat() { + return parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar) { + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do { + if(c == skipChar) + ; // ignore + else if(c == '-') + isNegative = true; + else if(c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) { + size_t count = 0; + while(count < length) { + int c = timedRead(); + if(c < 0) + break; + *buffer++ = (char) c; + count++; + } + return count; +} + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { + if(length < 1) + return 0; + size_t index = 0; + while(index < length) { + int c = timedRead(); + if(c < 0 || c == terminator) + break; + *buffer++ = (char) c; + index++; + } + return index; // return number of characters, not including null terminator +} + +std::string Stream::readString() { + std::string ret; + int c = timedRead(); + while(c >= 0) { + ret += (char) c; + c = timedRead(); + } + return ret; +} + +std::string Stream::readStringUntil(char terminator) { + std::string ret; + int c = timedRead(); + while(c >= 0 && c != terminator) { + ret += (char) c; + c = timedRead(); + } + return ret; +} diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h index 226543b..dff2074 100644 --- a/drivers/Linux/Stream.h +++ b/drivers/Linux/Stream.h @@ -1,16 +1,119 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis + Modified August 2016 by Marcelo Aquino for MySensors use + */ + #ifndef Stream_h #define Stream_h -#if !DOXYGEN -class Stream { - public: - virtual size_t write(uint8_t) = 0; - virtual size_t write(const uint8_t *buffer, size_t size) = 0; +#include +#include +#include "Print.h" - virtual int available() = 0; - virtual int read() = 0; - virtual int peek() = 0; - virtual void flush() = 0; +// compatability macros for testing +/* + #define getInt() parseInt() + #define getInt(skipChar) parseInt(skipchar) + #define getFloat() parseFloat() + #define getFloat(skipChar) parseFloat(skipChar) + #define getString( pre_string, post_string, buffer, length) + readBytesBetween( pre_string, terminator, buffer, length) + */ + +#if !DOXYGEN +class Stream: public Print { + protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() { + _timeout = 1000; + } + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + + bool find(const char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) { + return find((char *) target); + } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(const uint8_t *target, size_t length) { + return find((char *) target, length); + } + // returns true if target string is found, false if timed out + + bool find(char target) { return find (&target, 1); } + + bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found + bool findUntil(const uint8_t *target, const char *terminator) { + return findUntil((char *) target, terminator); + } + + bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) { + return findUntil((char *) target, targetLen, terminate, termLen); + } + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + float parseFloat(); // float version of parseInt + + virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytes(uint8_t *buffer, size_t length) { + return readBytes((char *) buffer, length); + } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) { + return readBytesUntil(terminator, (char *) buffer, length); + } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + std::string readString(); + std::string readStringUntil(char terminator); + + protected: + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(char skipChar); // as above but the given skipChar is ignored }; #endif diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index ff76cc5..a0a0eb3 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -1,185 +1,12 @@ -#include #include #include +#include #include "Arduino.h" // For millis() static unsigned long millis_at_start = 0; -/** -* C++ version 0.4 char* style "itoa": -* Written by Lukás Chmela -* Released under GPLv3. -*/ -char *itoa(int value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - int tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -/** - * C++ version 0.4 char* style "itoa": - * Written by Lukás Chmela - * Released under GPLv3. - */ -char *ltoa(long value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - long tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -char *ultoa(long num, char *str, int radix) -{ - unsigned long value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -/** - * Copyright (c) 2012, Peter A. Bigot - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the software nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. - */ - -char *utoa(int num, char *str, int radix) -{ - unsigned int value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -char *dtostrf(float f, int width, int decimals, char *result) -{ - sprintf(result,"%*.*f", width, decimals, f); - return result; -} +void yield(void) {} unsigned long millis(void) { @@ -202,3 +29,27 @@ void delay(unsigned int millis) sleeper.tv_nsec = (long)(millis % 1000) * 1000000; nanosleep(&sleeper, NULL); } + +void randomSeed(unsigned long seed) +{ + if (seed != 0) { + srand(seed); + } +} + +long randMax(long howbig) +{ + if (howbig == 0) { + return 0; + } + return rand() % howbig; +} + +long randMinMax(long howsmall, long howbig) +{ + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return randMax(diff) + howsmall; +} diff --git a/drivers/Linux/noniso.cpp b/drivers/Linux/noniso.cpp new file mode 100644 index 0000000..f628aa7 --- /dev/null +++ b/drivers/Linux/noniso.cpp @@ -0,0 +1,147 @@ +/* + noniso.cpp - replacements for non-ISO functions used by Arduino core + Copyright © 2016 Ivan Grokhotkov + + 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. + + Modified August 2016 by Marcelo Aquino for MySensors use +*/ + +#include +#include +#include +#include +#include +#include +#include "stdlib_noniso.h" + +char* utoa(unsigned value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned quotient = value; + + do { + const unsigned tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char* itoa(int value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + int quotient = abs(value); + + do { + const int tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +int atoi(const char* s) { + return (int) atol(s); +} + +long atol(const char* s) { + char * tmp; + return strtol(s, &tmp, 10); +} + +double atof(const char* s) { + char * tmp; + return strtod(s, &tmp); +} + +void reverse(char* begin, char* end) { + char *is = begin; + char *ie = end - 1; + while(is < ie) { + char tmp = *ie; + *ie = *is; + *is = tmp; + ++is; + --ie; + } +} + +char* ltoa(long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + long quotient = abs(value); + + do { + const long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +char* ultoa(unsigned long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned long quotient = value; + + do { + const unsigned long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char* dtostrf (double val, signed char width, unsigned char prec, char *s) { + sprintf(s,"%*.*f", width, prec, val); + return s; +} diff --git a/drivers/Linux/stdlib_noniso.h b/drivers/Linux/stdlib_noniso.h new file mode 100644 index 0000000..636cbf4 --- /dev/null +++ b/drivers/Linux/stdlib_noniso.h @@ -0,0 +1,52 @@ +/* + stdlib_noniso.h - nonstandard (but usefull) conversion functions + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef STDLIB_NONISO_H +#define STDLIB_NONISO_H + +#ifdef __cplusplus +extern "C"{ +#endif + +int atoi(const char *s); + +long atol(const char* s); + +double atof(const char* s); + +char* itoa (int val, char *s, int radix); + +char* ltoa (long val, char *s, int radix); + +char* utoa (unsigned int val, char *s, int radix); + +char* ultoa (unsigned long val, char *s, int radix); + +char* dtostrf (double val, signed char width, unsigned char prec, char *s); + +void reverse(char* begin, char* end); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif