From 091377369a011f0f68d222964bf5ec81814865fc Mon Sep 17 00:00:00 2001 From: Libelium Date: Mon, 19 Dec 2016 13:16:06 +0100 Subject: [PATCH] API v026 --- libraries/BLE/WaspBLE.cpp | 61 +- libraries/BLE/WaspBLE.h | 10 +- libraries/BLE/keywords.txt | 49 +- .../{SensorGas_PRO => BME280}/BME280.cpp | 4 +- libraries/{SensorGas_PRO => BME280}/BME280.h | 4 +- libraries/BME280/keywords.txt | 121 + libraries/BT_Pro/WaspBT_Pro.cpp | 56 +- libraries/BT_Pro/WaspBT_Pro.h | 6 +- libraries/BT_Pro/keywords.txt | 22 +- libraries/CAN/WaspCAN.cpp | 23 +- libraries/CAN/WaspCAN.h | 12 +- libraries/CAN/keywords.txt | 103 +- libraries/Frame/WaspFrame.cpp | 849 +- libraries/Frame/WaspFrame.h | 808 +- ...ameConstants.h => WaspFrameConstantsv12.h} | 774 +- libraries/Frame/WaspFrameConstantsv15.h | 1300 +++ libraries/Frame/keywords.txt | 214 +- libraries/GPRS_Pro/WaspGPRS_Pro.cpp | 4 +- libraries/GPRS_Pro/WaspGPRS_Pro.h | 4 +- libraries/GPRS_Pro/keywords.txt | 2 +- libraries/GPRS_SIM908/WaspGPRS_SIM908.cpp | 4 +- libraries/GPRS_SIM908/WaspGPRS_SIM908.h | 4 +- libraries/GPRS_SIM908/keywords.txt | 3 +- libraries/GPRS_SIM928A/WaspGPRS_SIM928A.cpp | 4 +- libraries/GPRS_SIM928A/WaspGPRS_SIM928A.h | 6 +- libraries/GPRS_SIM928A/keywords.txt | 3 +- libraries/GPS/WaspGPS.cpp | 6 +- libraries/GPS/WaspGPS.h | 4 +- libraries/GPS/keywords.txt | 3 +- libraries/LoRaWAN/WaspLoRaWAN.cpp | 3591 ++++++--- libraries/LoRaWAN/WaspLoRaWAN.h | 26 +- libraries/LoRaWAN/keywords.txt | 25 +- libraries/ModbusMaster/ModbusMaster.cpp | 943 +++ libraries/ModbusMaster/ModbusMaster.h | 307 + libraries/ModbusMaster/keywords.txt | 26 + libraries/ModbusSlave/ModbusSlave.cpp | 686 ++ libraries/ModbusSlave/ModbusSlave.h | 99 + libraries/ModbusSlave/keywords.txt | 8 + libraries/OPC_N2/WaspOPC_N2.cpp | 712 +- libraries/OPC_N2/WaspOPC_N2.h | 37 +- libraries/OPC_N2/keywords.txt | 1 + libraries/RFID1356/WaspRFID13.cpp | 76 +- libraries/RFID1356/WaspRFID13.h | 8 +- libraries/RFID1356/keywords.txt | 65 +- libraries/RS232/Wasp232.cpp | 64 +- libraries/RS232/Wasp232.h | 4 +- libraries/RS232/keywords.txt | 2 +- libraries/RS485/Wasp485.cpp | 39 +- libraries/RS485/Wasp485.h | 4 +- libraries/SX1272/WaspSX1272.cpp | 39 +- libraries/SX1272/WaspSX1272.h | 4 +- libraries/SX1272/keywords.txt | 16 +- libraries/SensorAgr_v20/WaspSensorAgr_v20.cpp | 36 +- libraries/SensorAgr_v20/WaspSensorAgr_v20.h | 4 +- libraries/SensorAgr_v20/keywords.txt | 3 +- libraries/SensorAgr_v30/WaspSensorAgr_v30.cpp | 1282 +++ libraries/SensorAgr_v30/WaspSensorAgr_v30.h | 325 + libraries/SensorAgr_v30/keywords.txt | 59 + libraries/SensorAmbient/WaspSensorAmbient.cpp | 621 +- libraries/SensorAmbient/WaspSensorAmbient.h | 260 +- libraries/SensorAmbient/keywords.txt | 6 +- libraries/SensorCities/WaspSensorCities.cpp | 41 +- libraries/SensorCities/WaspSensorCities.h | 6 +- libraries/SensorCities/keywords.txt | 2 +- .../SensorCities_PRO/WaspSensorCities_PRO.cpp | 338 + .../SensorCities_PRO/WaspSensorCities_PRO.h | 151 + libraries/SensorCities_PRO/keywords.txt | 48 + .../SensorEvent_v20/WaspSensorEvent_v20.cpp | 28 +- .../SensorEvent_v20/WaspSensorEvent_v20.h | 6 +- libraries/SensorEvent_v20/keywords.txt | 2 +- .../SensorEvent_v30/WaspSensorEvent_v30.cpp | 1034 +++ .../SensorEvent_v30/WaspSensorEvent_v30.h | 228 + libraries/SensorEvent_v30/keywords.txt | 42 + libraries/SensorGas_PRO/LMP91000.cpp | 29 +- libraries/SensorGas_PRO/LMP91000.h | 4 +- libraries/SensorGas_PRO/MCP3421.cpp | 47 +- libraries/SensorGas_PRO/MCP3421.h | 35 +- libraries/SensorGas_PRO/WaspSensorGas_Pro.cpp | 2207 ++++-- libraries/SensorGas_PRO/WaspSensorGas_Pro.h | 233 +- libraries/SensorGas_PRO/keywords.txt | 151 +- libraries/SensorGas_v20/WaspSensorGas_v20.cpp | 26 +- libraries/SensorGas_v20/WaspSensorGas_v20.h | 8 +- libraries/SensorGas_v20/keywords.txt | 2 +- libraries/SensorGas_v30/WaspSensorGas_v30.cpp | 1994 +++++ libraries/SensorGas_v30/WaspSensorGas_v30.h | 461 ++ libraries/SensorGas_v30/keywords.txt | 79 + libraries/SensorParking/WaspSensorParking.cpp | 6 +- libraries/SensorParking/WaspSensorParking.h | 4 +- libraries/SensorParking/keywords.txt | 2 +- .../WaspSensorPrototyping_v20.cpp | 21 +- .../WaspSensorPrototyping_v20.h | 8 +- libraries/SensorPrototyping_v20/keywords.txt | 2 +- .../SensorRadiation/WaspSensorRadiation.cpp | 11 +- .../SensorRadiation/WaspSensorRadiation.h | 4 +- libraries/SensorRadiation/keywords.txt | 2 +- libraries/SensorSW/TurbiditySensor.cpp | 644 +- libraries/SensorSW/TurbiditySensor.h | 69 +- libraries/SensorSW/WaspSensorSW.cpp | 117 +- libraries/SensorSW/WaspSensorSW.h | 79 +- libraries/SensorSW/keywords.txt | 7 +- libraries/SensorSW/utility/ADC.cpp | 4 +- libraries/SensorSW/utility/ADC.h | 4 +- libraries/SensorSW/utility/filter.cpp | 4 +- libraries/SensorSW/utility/filter.h | 4 +- .../SensorSmart_v20/WaspSensorSmart_v20.cpp | 6 +- .../SensorSmart_v20/WaspSensorSmart_v20.h | 8 +- libraries/SensorSmart_v20/keywords.txt | 2 +- libraries/Sigfox/WaspSigfox.cpp | 432 +- libraries/Sigfox/WaspSigfox.h | 60 +- libraries/Sigfox/keywords.txt | 40 +- libraries/SmartWaterIons/keywords.txt | 5 +- libraries/SmartWaterIons/smartWaterIons.cpp | 119 +- libraries/SmartWaterIons/smartWaterIons.h | 93 +- libraries/SmartWaterIons/utility/ADC7705.cpp | 4 +- libraries/SmartWaterIons/utility/ADC7705.h | 4 +- libraries/TSL2561/TSL2561.cpp | 380 + libraries/TSL2561/TSL2561.h | 255 + libraries/TSL2561/keywords.txt | 79 + .../UltrasoundSensor/UltrasoundSensor.cpp | 88 + libraries/UltrasoundSensor/UltrasoundSensor.h | 75 + libraries/UltrasoundSensor/keywords.txt | 9 + libraries/WIFI/WaspWIFI.cpp | 136 +- libraries/WIFI/WaspWIFI.h | 4 +- libraries/WIFI/keywords.txt | 5 +- libraries/WIFI_PRO/WaspWIFI_PRO.cpp | 6530 ++++++++++++++++ libraries/WIFI_PRO/WaspWIFI_PRO.h | 314 + libraries/WIFI_PRO/keywords.txt | 125 + libraries/WIFI_PRO/utility/ati_error_codes.h | 221 + libraries/WIFI_PRO/utility/ati_generator.h | 283 + libraries/Wasp4G/Wasp4G.cpp | 6947 +++++++++++++++++ libraries/Wasp4G/Wasp4G.h | 1433 ++++ libraries/Wasp4G/keywords.txt | 176 + libraries/Wasp4G/utility/Wasp4G_constants.h | 482 ++ libraries/Wasp4G/utility/Wasp4G_error_codes.h | 177 + libraries/WaspAES/WaspAES.cpp | 4 +- libraries/WaspAES/WaspAES.h | 4 +- libraries/WaspAES/keywords.txt | 2 +- libraries/WaspHash/WaspHash.cpp | 4 +- libraries/WaspHash/WaspHash.h | 4 +- libraries/WaspHash/keywords.txt | 2 +- libraries/WaspRSA/WaspRSA.cpp | 4 +- libraries/WaspRSA/WaspRSA.h | 4 +- libraries/WaspRSA/keywords.txt | 2 +- libraries/WaspStackEEPROM/WaspStackEEPROM.cpp | 4 +- libraries/WaspStackEEPROM/WaspStackEEPROM.h | 4 +- libraries/WaspStackEEPROM/keywords.txt | 2 +- libraries/XBee802/WaspXBee802.cpp | 11 +- libraries/XBee802/WaspXBee802.h | 4 +- libraries/XBee802/keywords.txt | 2 +- libraries/XBee868/WaspXBee868.cpp | 16 +- libraries/XBee868/WaspXBee868.h | 2 +- libraries/XBee868/keywords.txt | 2 +- libraries/XBee868LP/WaspXBee868LP.cpp | 979 +++ libraries/XBee868LP/WaspXBee868LP.h | 385 + libraries/XBee868LP/keywords.txt | 46 + libraries/XBee900/WaspXBee900.cpp | 17 +- libraries/XBee900/WaspXBee900.h | 4 +- libraries/XBee900/keywords.txt | 2 +- libraries/XBee900HP/WaspXBee900HP.cpp | 900 +++ libraries/XBee900HP/WaspXBee900HP.h | 337 + libraries/XBee900HP/keywords.txt | 23 + libraries/XBeeDM/WaspXBeeDM.cpp | 11 +- libraries/XBeeDM/WaspXBeeDM.h | 4 +- libraries/XBeeDM/keywords.txt | 5 +- libraries/XBeeZB/WaspXBeeZB.cpp | 81 +- libraries/XBeeZB/WaspXBeeZB.h | 52 +- libraries/XBeeZB/keywords.txt | 8 +- libraries/_3G/Wasp3G.cpp | 364 +- libraries/_3G/Wasp3G.h | 40 +- libraries/_3G/keywords.txt | 87 +- libraries/_4_20mA/currentLoop.cpp | 4 +- libraries/_4_20mA/currentLoop.h | 4 +- libraries/_4_20mA/keywords.txt | 2 +- waspmote-api/Printable.h | 4 + waspmote-api/WConstants.h | 2 +- waspmote-api/WInterrupts.c | 31 +- waspmote-api/WaspACC.cpp | 47 +- waspmote-api/WaspACC.h | 4 +- waspmote-api/WaspClasses.h | 5 +- waspmote-api/WaspConstants.h | 114 +- waspmote-api/WaspEEPROM.cpp | 521 ++ waspmote-api/WaspEEPROM.h | 96 + waspmote-api/WaspGPRS_Pro_core.cpp | 24 +- waspmote-api/WaspGPRS_Pro_core.h | 4 +- waspmote-api/WaspOneWire.cpp | 4 +- waspmote-api/WaspOneWire.h | 8 +- waspmote-api/WaspPWR.cpp | 744 +- waspmote-api/WaspPWR.h | 214 +- waspmote-api/WaspRTC.cpp | 218 +- waspmote-api/WaspRTC.h | 58 +- waspmote-api/WaspSD.cpp | 179 +- waspmote-api/WaspSD.h | 6 +- waspmote-api/WaspSPI.cpp | 194 +- waspmote-api/WaspSPI.h | 25 +- waspmote-api/WaspUART.cpp | 360 +- waspmote-api/WaspUART.h | 39 +- waspmote-api/WaspUSB.cpp | 55 +- waspmote-api/WaspUSB.h | 5 +- waspmote-api/WaspUtils.cpp | 609 +- waspmote-api/WaspUtils.h | 75 +- waspmote-api/WaspVariables.h | 9 +- waspmote-api/WaspXBeeCore.cpp | 275 +- waspmote-api/WaspXBeeCore.h | 55 +- waspmote-api/Waspmote.h | 6 +- waspmote-api/Wire.cpp | 434 +- waspmote-api/Wire.h | 132 +- waspmote-api/binary.h | 2 + waspmote-api/eeprom_utilities/aes132_comm.c | 465 ++ waspmote-api/eeprom_utilities/aes132_comm.h | 270 + waspmote-api/eeprom_utilities/aes132_i2c.h | 142 + waspmote-api/main.cpp | 78 +- waspmote-api/pins_waspmote.c | 82 +- waspmote-api/pins_waspmote.h | 110 +- waspmote-api/sd_utilities/Sd2Card.cpp | 35 +- waspmote-api/sd_utilities/Sd2Card.h | 15 +- waspmote-api/sd_utilities/SdBaseFile.cpp | 236 +- waspmote-api/sd_utilities/SdBaseFile.h | 4 + waspmote-api/sd_utilities/SdFat.cpp | 4 + waspmote-api/sd_utilities/SdFat.h | 5 +- waspmote-api/sd_utilities/SdFatConfig.h | 4 + waspmote-api/sd_utilities/SdFatStructs.h | 4 + waspmote-api/sd_utilities/SdFile.cpp | 4 + waspmote-api/sd_utilities/SdFile.h | 4 + waspmote-api/sd_utilities/SdInfo.h | 4 + waspmote-api/sd_utilities/SdStream.cpp | 6 +- waspmote-api/sd_utilities/SdStream.h | 4 + waspmote-api/sd_utilities/SdVolume.cpp | 328 +- waspmote-api/sd_utilities/SdVolume.h | 3 + waspmote-api/sd_utilities/bufstream.h | 4 + waspmote-api/sd_utilities/ios.h | 4 + waspmote-api/sd_utilities/iostream.h | 4 + waspmote-api/sd_utilities/istream.cpp | 263 +- waspmote-api/sd_utilities/istream.h | 4 + waspmote-api/sd_utilities/ostream.cpp | 211 +- waspmote-api/sd_utilities/ostream.h | 4 + waspmote-api/twi.c | 10 +- waspmote-api/twi.h | 4 +- waspmote-api/wiring.c | 40 +- waspmote-api/wiring.h | 5 +- waspmote-api/wiring_analog.c | 67 +- waspmote-api/wiring_digital.c | 3 + waspmote-api/wiring_private.h | 8 +- waspmote-api/wiring_pulse.c | 4 +- waspmote-api/wiring_serial.c | 4 +- waspmote-api/wiring_shift.c | 5 +- 245 files changed, 43682 insertions(+), 7286 deletions(-) rename libraries/{SensorGas_PRO => BME280}/BME280.cpp (99%) rename libraries/{SensorGas_PRO => BME280}/BME280.h (99%) create mode 100644 libraries/BME280/keywords.txt rename libraries/Frame/{WaspFrameConstants.h => WaspFrameConstantsv12.h} (64%) create mode 100644 libraries/Frame/WaspFrameConstantsv15.h create mode 100755 libraries/ModbusMaster/ModbusMaster.cpp create mode 100755 libraries/ModbusMaster/ModbusMaster.h create mode 100644 libraries/ModbusMaster/keywords.txt create mode 100755 libraries/ModbusSlave/ModbusSlave.cpp create mode 100755 libraries/ModbusSlave/ModbusSlave.h create mode 100644 libraries/ModbusSlave/keywords.txt create mode 100755 libraries/SensorAgr_v30/WaspSensorAgr_v30.cpp create mode 100755 libraries/SensorAgr_v30/WaspSensorAgr_v30.h create mode 100644 libraries/SensorAgr_v30/keywords.txt create mode 100755 libraries/SensorCities_PRO/WaspSensorCities_PRO.cpp create mode 100755 libraries/SensorCities_PRO/WaspSensorCities_PRO.h create mode 100644 libraries/SensorCities_PRO/keywords.txt create mode 100755 libraries/SensorEvent_v30/WaspSensorEvent_v30.cpp create mode 100755 libraries/SensorEvent_v30/WaspSensorEvent_v30.h create mode 100644 libraries/SensorEvent_v30/keywords.txt create mode 100644 libraries/SensorGas_v30/WaspSensorGas_v30.cpp create mode 100755 libraries/SensorGas_v30/WaspSensorGas_v30.h create mode 100644 libraries/SensorGas_v30/keywords.txt create mode 100755 libraries/TSL2561/TSL2561.cpp create mode 100755 libraries/TSL2561/TSL2561.h create mode 100644 libraries/TSL2561/keywords.txt create mode 100755 libraries/UltrasoundSensor/UltrasoundSensor.cpp create mode 100755 libraries/UltrasoundSensor/UltrasoundSensor.h create mode 100644 libraries/UltrasoundSensor/keywords.txt create mode 100755 libraries/WIFI_PRO/WaspWIFI_PRO.cpp create mode 100755 libraries/WIFI_PRO/WaspWIFI_PRO.h create mode 100644 libraries/WIFI_PRO/keywords.txt create mode 100644 libraries/WIFI_PRO/utility/ati_error_codes.h create mode 100755 libraries/WIFI_PRO/utility/ati_generator.h create mode 100755 libraries/Wasp4G/Wasp4G.cpp create mode 100755 libraries/Wasp4G/Wasp4G.h create mode 100644 libraries/Wasp4G/keywords.txt create mode 100755 libraries/Wasp4G/utility/Wasp4G_constants.h create mode 100644 libraries/Wasp4G/utility/Wasp4G_error_codes.h create mode 100644 libraries/XBee868LP/WaspXBee868LP.cpp create mode 100644 libraries/XBee868LP/WaspXBee868LP.h create mode 100644 libraries/XBee868LP/keywords.txt create mode 100755 libraries/XBee900HP/WaspXBee900HP.cpp create mode 100755 libraries/XBee900HP/WaspXBee900HP.h create mode 100755 libraries/XBee900HP/keywords.txt create mode 100644 waspmote-api/WaspEEPROM.cpp create mode 100644 waspmote-api/WaspEEPROM.h create mode 100644 waspmote-api/eeprom_utilities/aes132_comm.c create mode 100644 waspmote-api/eeprom_utilities/aes132_comm.h create mode 100644 waspmote-api/eeprom_utilities/aes132_i2c.h diff --git a/libraries/BLE/WaspBLE.cpp b/libraries/BLE/WaspBLE.cpp index 037f82f..01e8802 100644 --- a/libraries/BLE/WaspBLE.cpp +++ b/libraries/BLE/WaspBLE.cpp @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.5 + * Version: 3.0 * Design: David Gascón * Implementation: Javier Siscart */ @@ -682,17 +682,8 @@ int8_t WaspBLE::ON(uint8_t UartMode) if (UartMode >= 2) _uartBT = 1; else _uartBT = UartMode; - // Power On the module with the corresponding pin - if(_uartBT == SOCKET0) - { - pinMode(BLE_PW_0,OUTPUT); - digitalWrite(BLE_PW_0,HIGH); - } - else if (_uartBT == SOCKET1) - { - pinMode(BLE_PW_1,OUTPUT); - digitalWrite(BLE_PW_1,HIGH); - } + // power on the socket + PWR.powerSocket(_uartBT, HIGH); // delay to power up. delay(100); @@ -759,24 +750,18 @@ void WaspBLE::OFF() closeSerial(_uartBT); // update Waspmote Register - if(_uartBT == SOCKET0) WaspRegister &= ~(REG_SOCKET0); - if(_uartBT == SOCKET1) WaspRegister &= ~(REG_SOCKET1); + if (_uartBT == SOCKET0) WaspRegister &= ~(REG_SOCKET0); + if (_uartBT == SOCKET1) WaspRegister &= ~(REG_SOCKET1); // to disable wake up pin. sleep(); - // Disable power pin. - if(!_uartBT) - { - pinMode(BLE_PW_0,OUTPUT); - digitalWrite(BLE_PW_0,LOW); - } - else - { - Utils.setMux(MUX_TO_LOW,MUX_TO_LOW); - pinMode(BLE_PW_1,OUTPUT); - digitalWrite(BLE_PW_1,LOW); - } + // unselect multiplexer + if (_uartBT == SOCKET0) Utils.setMuxUSB(); + if (_uartBT == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uartBT, LOW); } @@ -945,6 +930,19 @@ uint16_t WaspBLE::scanDevice(uint8_t* Mac, uint8_t maxTime, uint8_t TXPower) strcpy_P(message, (char*)pgm_read_word(&(table_BLE[6]))); USB.printf(message, errorCode); #endif + + // Now it is necessary to stop scan. + if(endProcedure() != 0) + { + #if BLE_DEBUG > 0 + // copy "Stop fail. err: %x\n" form flash + char message[25] =""; + strcpy_P(message, (char*)pgm_read_word(&(table_BLE[5]))); + USB.printf(message, errorCode); + #endif + return errorCode; + } + return errorCode; } @@ -2641,17 +2639,14 @@ uint16_t WaspBLE::writeLocalAttribute(uint16_t handle, uint8_t * data, uint8_t l uint16_t WaspBLE::writeLocalAttribute(uint16_t handle, uint8_t indicate, uint8_t * data, uint8_t length) { // maximum writtable data is 54 bytes length + uint8_t payload[54]; + uint8_t flag = 0; + if (length > 54) { length = 54; } - - uint8_t payload[length+4]; - - uint8_t flag = 0; - - payload[0] = (uint8_t)(handle & 0x00FF); payload[1] = (uint8_t)((handle & 0xFF00) >> 8); @@ -2811,7 +2806,7 @@ uint16_t WaspBLE::attributeWrite(uint8_t connection, uint16_t atthandle, char * uint16_t WaspBLE::attributeWrite(uint8_t connection, uint16_t atthandle, uint8_t * data, uint8_t length) { - uint8_t payload[length+4]; + uint8_t payload[length]; payload[0] = connection; payload[1] = (uint8_t)(atthandle & 0x00FF); diff --git a/libraries/BLE/WaspBLE.h b/libraries/BLE/WaspBLE.h index a74ccbb..cf521db 100644 --- a/libraries/BLE/WaspBLE.h +++ b/libraries/BLE/WaspBLE.h @@ -1,7 +1,7 @@ /*! \file WaspBLE.h \briefLibrary for managing the Bluetooth low energy BLE112 - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Javier Siscart @@ -50,11 +50,7 @@ // General constants // Default baudrate -#define BT_BLUEGIGA_RATE 115200 -// Bluetooth power pin when SOCKET1 is used. Same as DIGITAL 6 -#define BLE_PW_1 6 -// Bluetooth power pin when SOCKET0 is used. Same as Xbee_pw -#define BLE_PW_0 22 +#define BT_BLUEGIGA_RATE 115200 // BLuetooth Sleep pin for SOCKET0. Same as XBEE_SLEEP #define BLE_SLEEP 47 //max packet size allowed by the protocol diff --git a/libraries/BLE/keywords.txt b/libraries/BLE/keywords.txt index abb9102..3a5dc58 100644 --- a/libraries/BLE/keywords.txt +++ b/libraries/BLE/keywords.txt @@ -43,15 +43,15 @@ BLE_GAP_ADVERTISEMENT LITERAL1 BLE_GAP_SCAN_RESPONSE LITERAL1 BLE_DISABLE_BONDING LITERAL1 BLE_ENABLE_BONDING LITERAL1 -BLE_DISABLE_MITM LITERAL1 +BLE_DISABLE_MITM LITERAL1 BLE_ENABLE_MITM LITERAL1 BLE_INDICATE_ENABLED LITERAL1 BLE_INDICATE_DISABLED LITERAL1 BLE_EVENT_SYSTEM_BOOT LITERAL1 -BLE_EVENT_SYSTEM_DEBUG LITERAL1 +BLE_EVENT_SYSTEM_DEBUG LITERAL1 BLE_EVENT_SYSTEM_ENDPOINT_WATERMARK_RX LITERAL1 BLE_EVENT_SYSTEM_ENDPOINT_WATERMARK_TX LITERAL1 -BLE_EVENT_SYSTEM_SCRIPT_FAILURE LITERAL1 +BLE_EVENT_SYSTEM_SCRIPT_FAILURE LITERAL1 BLE_EVENT_SYSTEM_NO_LICENSE_KEY LITERAL1 BLE_EVENT_FLASH_PS_KEY LITERAL1 BLE_EVENT_ATTRIBUTES_VALUE LITERAL1 @@ -60,7 +60,7 @@ BLE_EVENT_ATTRIBUTES_STATUS LITERAL1 BLE_EVENT_CONNECTION_STATUS LITERAL1 BLE_EVENT_CONNECTION_VERSION_IND LITERAL1 BLE_EVENT_CONNECTION_FEATURE_IND LITERAL1 -BLE_EVENT_CONNECTION_RAW_RX LITERAL1 +BLE_EVENT_CONNECTION_RAW_RX LITERAL1 BLE_EVENT_CONNECTION_DISCONNECTED LITERAL1 BLE_EVENT_ATTCLIENT_INDICATED LITERAL1 BLE_EVENT_ATTCLIENT_PROCEDURE_COMPLETED LITERAL1 @@ -115,5 +115,44 @@ getOwnMac KEYWORD2 sendCommand KEYWORD2 readCommandAnswer KEYWORD2 WaspBLE KEYWORD2 +mac KEYWORD2 +rssi KEYWORD2 +advData KEYWORD2 +_baudrateBT KEYWORD2 +_uartBT KEYWORD2 +previousMAC KEYWORD2 +GAP_discover_mode KEYWORD2 +GAP_discoverable_mode KEYWORD2 +GAP_connectable_mode KEYWORD2 +scan_interval KEYWORD2 +scan_window KEYWORD2 +scan_policy KEYWORD2 +adv_policy KEYWORD2 +active KEYWORD2 +scan_duplicate_filtering KEYWORD2 +TXPower KEYWORD2 +adv_interval_max KEYWORD2 +adv_interval_min KEYWORD2 +adv_channels KEYWORD2 +set_scanrsp KEYWORD2 +scanIndex KEYWORD2 +parseScanEvent KEYWORD2 +saveDevice KEYWORD2 +parseName KEYWORD2 +discoveredDevice KEYWORD2 +my_bd_addr KEYWORD2 +deviceRole KEYWORD2 +scanNetworkCancel KEYWORD2 +endProcedure KEYWORD2 +getScanningParameters KEYWORD2 +ADCRead KEYWORD2 +sayHello KEYWORD2 +ADCValue KEYWORD2 +setBondableMode KEYWORD2 +setKey KEYWORD2 +deleteBonding KEYWORD2 +getBonding KEYWORD2 +setSecurityParameters KEYWORD2 +parseEvent KEYWORD2 -BLE KEYWORD3 +BLE KEYWORD1 diff --git a/libraries/SensorGas_PRO/BME280.cpp b/libraries/BME280/BME280.cpp similarity index 99% rename from libraries/SensorGas_PRO/BME280.cpp rename to libraries/BME280/BME280.cpp index 7383305..065401b 100755 --- a/libraries/SensorGas_PRO/BME280.cpp +++ b/libraries/BME280/BME280.cpp @@ -1,7 +1,7 @@ /* * Library for managing the BME280 sensor * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ diff --git a/libraries/SensorGas_PRO/BME280.h b/libraries/BME280/BME280.h similarity index 99% rename from libraries/SensorGas_PRO/BME280.h rename to libraries/BME280/BME280.h index 1362443..a230e9f 100755 --- a/libraries/SensorGas_PRO/BME280.h +++ b/libraries/BME280/BME280.h @@ -1,7 +1,7 @@ /*! \file BME280.h \brief Library for managing the BME280 sensor - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego diff --git a/libraries/BME280/keywords.txt b/libraries/BME280/keywords.txt new file mode 100644 index 0000000..e10f2a4 --- /dev/null +++ b/libraries/BME280/keywords.txt @@ -0,0 +1,121 @@ +# BME280 # + +BME280_I2C_ADDRESS1 LITERAL1 +BME280_I2C_ADDRESS2 LITERAL1 +BME280_I2C_ADDRESS LITERAL1 +BME280_SLEEP_MODE LITERAL1 +BME280_FORCED_MODE LITERAL1 +BME280_NORMAL_MODE LITERAL1 +BME280_SOFT_RESET_CODE LITERAL1 +BME280_STANDBY_TIME_1_MS LITERAL1 +BME280_STANDBY_TIME_63_MS LITERAL1 +BME280_STANDBY_TIME_125_MS LITERAL1 +BME280_STANDBY_TIME_250_MS LITERAL1 +BME280_STANDBY_TIME_500_MS LITERAL1 +BME280_STANDBY_TIME_1000_MS LITERAL1 +BME280_STANDBY_TIME_10_MS LITERAL1 +BME280_STANDBY_TIME_20_MS LITERAL1 +BME280_OVERSAMP_SKIPPED LITERAL1 +BME280_OVERSAMP_1X LITERAL1 +BME280_OVERSAMP_2X LITERAL1 +BME280_OVERSAMP_4X LITERAL1 +BME280_OVERSAMP_8X LITERAL1 +BME280_OVERSAMP_16X LITERAL1 +BME280_FILTER_COEFF_OFF LITERAL1 +BME280_FILTER_COEFF_2 LITERAL1 +BME280_FILTER_COEFF_4 LITERAL1 +BME280_FILTER_COEFF_8 LITERAL1 +BME280_FILTER_COEFF_16 LITERAL1 +BME280_DIG_T1_LSB_REG LITERAL1 +BME280_DIG_T1_MSB_REG LITERAL1 +BME280_DIG_T2_LSB_REG LITERAL1 +BME280_DIG_T2_MSB_REG LITERAL1 +BME280_DIG_T3_LSB_REG LITERAL1 +BME280_DIG_T3_MSB_REG LITERAL1 +BME280_DIG_P1_LSB_REG LITERAL1 +BME280_DIG_P1_MSB_REG LITERAL1 +BME280_DIG_P2_LSB_REG LITERAL1 +BME280_DIG_P2_MSB_REG LITERAL1 +BME280_DIG_P3_LSB_REG LITERAL1 +BME280_DIG_P3_MSB_REG LITERAL1 +BME280_DIG_P4_LSB_REG LITERAL1 +BME280_DIG_P4_MSB_REG LITERAL1 +BME280_DIG_P5_LSB_REG LITERAL1 +BME280_DIG_P5_MSB_REG LITERAL1 +BME280_DIG_P6_LSB_REG LITERAL1 +BME280_DIG_P6_MSB_REG LITERAL1 +BME280_DIG_P7_LSB_REG LITERAL1 +BME280_DIG_P7_MSB_REG LITERAL1 +BME280_DIG_P8_LSB_REG LITERAL1 +BME280_DIG_P8_MSB_REG LITERAL1 +BME280_DIG_P9_LSB_REG LITERAL1 +BME280_DIG_P9_MSB_REG LITERAL1 +BME280_DIG_H1_REG LITERAL1 +BME280_DIG_H2_LSB_REG LITERAL1 +BME280_DIG_H2_MSB_REG LITERAL1 +BME280_DIG_H3_REG LITERAL1 +BME280_DIG_H4_MSB_REG LITERAL1 +BME280_DIG_H5_LSB_H4_LSB_REG LITERAL1 +BME280_DIG_H5_MSB_REG LITERAL1 +BME280_DIG_H6_REG LITERAL1 +BME280_CHIP_ID_REG LITERAL1 +BME280_RST_REG LITERAL1 +BME280_STAT_REG LITERAL1 +BME280_CTRL_MEAS_REG LITERAL1 +BME280_CTRL_HUMIDITY_REG LITERAL1 +BME280_CONFIG_REG LITERAL1 +BME280_PRESSURE_MSB_REG LITERAL1 +BME280_PRESSURE_LSB_REG LITERAL1 +BME280_PRESSURE_XLSB_REG LITERAL1 +BME280_TEMPERATURE_MSB_REG LITERAL1 +BME280_TEMPERATURE_LSB_REG LITERAL1 +BME280_TEMPERATURE_XLSB_REG LITERAL1 +BME280_HUMIDITY_MSB_REG LITERAL1 +BME280_HUMIDITY_LSB_REG LITERAL1 +BME280_CHIP_ID_REG_CHIP_ID LITERAL1 +BME280_STAT_REG_MEASURING__POS LITERAL1 +BME280_STAT_REG_MEASURING__MSK LITERAL1 +BME280_STAT_REG_MEASURING__LEN LITERAL1 +BME280_STAT_REG_IM_UPDATE__POS LITERAL1 +BME280_STAT_REG_IM_UPDATE__MSK LITERAL1 +BME280_STAT_REG_IM_UPDATE__LEN LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__POS LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__MSK LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__LEN LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__POS LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__MSK LITERAL1 +BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__LEN LITERAL1 +BME280_CTRL_MEAS_REG_POWER_MODE__POS LITERAL1 +BME280_CTRL_MEAS_REG_POWER_MODE__MSK LITERAL1 +BME280_CTRL_MEAS_REG_POWER_MODE__LEN LITERAL1 +BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__POS LITERAL1 +BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__MSK LITERAL1 +BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__LEN LITERAL1 +BME280_CONFIG_REG_TSB__POS LITERAL1 +BME280_CONFIG_REG_TSB__MSK LITERAL1 +BME280_CONFIG_REG_TSB__LEN LITERAL1 +BME280_CONFIG_REG_FILTER__POS LITERAL1 +BME280_CONFIG_REG_FILTER__MSK LITERAL1 +BME280_CONFIG_REG_FILTER__LEN LITERAL1 +BME280_CONFIG_REG_SPI3_ENABLE__POS LITERAL1 +BME280_CONFIG_REG_SPI3_ENABLE__MSK LITERAL1 +BME280_CONFIG_REG_SPI3_ENABLE__LEN LITERAL1 +BME280_PRESSURE_XLSB_REG_DATA__POS LITERAL1 +BME280_PRESSURE_XLSB_REG_DATA__MSK LITERAL1 +BME280_PRESSURE_XLSB_REG_DATA__LEN LITERAL1 +BME280_TEMPERATURE_XLSB_REG_DATA__POS LITERAL1 +BME280_TEMPERATURE_XLSB_REG_DATA__MSK LITERAL1 +BME280_TEMPERATURE_XLSB_REG_DATA__LEN LITERAL1 + +BME280 KEYWORD2 +ON KEYWORD2 +checkID KEYWORD2 +readCalibration KEYWORD2 +showCalibration KEYWORD2 +getTemperature KEYWORD2 +getPressure KEYWORD2 +getHumidity KEYWORD2 + +BME KEYWORD1 + + diff --git a/libraries/BT_Pro/WaspBT_Pro.cpp b/libraries/BT_Pro/WaspBT_Pro.cpp index 878241f..b3211bc 100755 --- a/libraries/BT_Pro/WaspBT_Pro.cpp +++ b/libraries/BT_Pro/WaspBT_Pro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.4 + * Version: 3.0 * Design: David Gascón * Implementation: Javier Siscart */ @@ -1033,25 +1033,20 @@ int8_t WaspBT_Pro::ON(uint8_t UartMode) // prevent bad uart number. By default UART1 if (UartMode>=2) _uartBT = 1; else _uartBT=UartMode; - - if(!_uartBT) - { - Utils.setMuxSocket0(); - beginSerial(_baudrateBT,_uartBT); - pinMode(BT_PRO_PW_0,OUTPUT); - digitalWrite(BT_PRO_PW_0,HIGH); - } - else - { - Utils.setMuxSocket1(); - beginSerial(_baudrateBT,_uartBT); - pinMode(BT_PRO_PW_1,OUTPUT); - digitalWrite(BT_PRO_PW_1,HIGH); - } + // select multiplexer + if (_uartBT == SOCKET0) Utils.setMuxSocket0(); + if (_uartBT == SOCKET1) Utils.setMuxSocket1(); + + // open uart + beginSerial(_baudrateBT,_uartBT); + + // power on the socket + PWR.powerSocket(_uartBT, HIGH); + // update Waspmote Register - if(_uartBT == SOCKET0) WaspRegister |= REG_SOCKET0; - if(_uartBT == SOCKET1) WaspRegister |= REG_SOCKET1; + if (_uartBT == SOCKET0) WaspRegister |= REG_SOCKET0; + if (_uartBT == SOCKET1) WaspRegister |= REG_SOCKET1; //~ beginSerial(_baudrateBT,_uartBT); serialFlush(_uartBT); @@ -1087,24 +1082,19 @@ int8_t WaspBT_Pro::ON() */ void WaspBT_Pro::OFF() { - + // close uart closeSerial(_uartBT); // update Waspmote Register - if(_uartBT == SOCKET0) WaspRegister &= ~(REG_SOCKET0); - if(_uartBT == SOCKET1) WaspRegister &= ~(REG_SOCKET1); + if (_uartBT == SOCKET0) WaspRegister &= ~(REG_SOCKET0); + if (_uartBT == SOCKET1) WaspRegister &= ~(REG_SOCKET1); - if(!_uartBT) - { - pinMode(BT_PRO_PW_0,OUTPUT); - digitalWrite(BT_PRO_PW_0,LOW); - } - else - { - Utils.setMux(MUX_TO_LOW,MUX_TO_LOW); - pinMode(BT_PRO_PW_1,OUTPUT); - digitalWrite(BT_PRO_PW_1,LOW); - } + // unselect multiplexer + if (_uartBT == SOCKET0) Utils.setMuxUSB(); + if (_uartBT == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uartBT, LOW); SD.OFF(); diff --git a/libraries/BT_Pro/WaspBT_Pro.h b/libraries/BT_Pro/WaspBT_Pro.h index 566491d..ac628c1 100755 --- a/libraries/BT_Pro/WaspBT_Pro.h +++ b/libraries/BT_Pro/WaspBT_Pro.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Javier Siscart */ @@ -51,8 +51,6 @@ #define BLOCK_SIZE 32 // Bytes per block used reading UART #define BLOCK_MAC_SIZE 17 // Bytes per block used to parse Macs #define COMMAND_SIZE 40 -#define BT_PRO_PW_1 6 // Bluetooth power pin when UART1 is used. Same as DIGITAL 6 -#define BT_PRO_PW_0 22 // Bluetooth power pin when UART0 is used. Same as Xbee_pw #define BT_NODE_ID_ADDR 1024 // EEPROM address where node ID is stored. #define ERRORSD1 "err1" // Error writting. #define ERRORSD2 "err2" // Error creating. diff --git a/libraries/BT_Pro/keywords.txt b/libraries/BT_Pro/keywords.txt index 6d38694..f14b1c5 100644 --- a/libraries/BT_Pro/keywords.txt +++ b/libraries/BT_Pro/keywords.txt @@ -59,5 +59,25 @@ getRSSI KEYWORD2 pair KEYWORD2 removePairedDevices KEYWORD2 isPaired KEYWORD2 +txPower KEYWORD2 +mac_address KEYWORD2 +CoD KEYWORD2 +devClass KEYWORD2 +commandAnswer KEYWORD2 +theCommand KEYWORD2 +mem_addr KEYWORD2 +identifier KEYWORD2 +lookForAnswer KEYWORD2 +changeInquiryPower KEYWORD2 +parseNames KEYWORD2 +parseBlock KEYWORD2 +waitInquiryAnswer KEYWORD2 +getSetDateID KEYWORD2 +waitScanDeviceAnswer KEYWORD2 +setInquiryTime KEYWORD2 +eraseSDFiles KEYWORD2 +createSDFiles KEYWORD2 +printBuffer KEYWORD2 +printBuffer2 KEYWORD2 -BT_Pro KEYWORD3 +BT_Pro KEYWORD1 diff --git a/libraries/CAN/WaspCAN.cpp b/libraries/CAN/WaspCAN.cpp index 1374cb9..30cc1a2 100755 --- a/libraries/CAN/WaspCAN.cpp +++ b/libraries/CAN/WaspCAN.cpp @@ -1,7 +1,7 @@ -/*! \file WaspCAN.h +/*! \file WaspCAN.cpp \brief Library for managing CAN Bus modules * - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: David Gascon * Implementation: Luis Antonio Martin Nuez & Ahmad Saad */ @@ -56,8 +56,8 @@ bool WaspCAN::ON(uint16_t speed) #endif //Active power Xbee - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); + PWR.powerSocket(SOCKET0, HIGH); + SPI.isSocket0 = true; //SD CS configure pinMode(SD_SS,OUTPUT); @@ -167,7 +167,7 @@ bool WaspCAN::ON(uint16_t speed) writeRegister( BFPCTRL, 0 ); //Set normal mode - setMode(NORMAL_MODE); + setMode(CAN_NORMAL_MODE); //Test its correct mode /* @@ -193,7 +193,8 @@ bool WaspCAN::ON(uint16_t speed) //!************************************************************* void WaspCAN::OFF(void ) { - digitalWrite(XBEE_PW, LOW); + PWR.powerSocket(SOCKET0, LOW); + SPI.isSocket0 = false; delay(100); } @@ -399,16 +400,16 @@ void WaspCAN::setMode(uint8_t mode) { uint8_t mode_register = 0; - if (mode == LISTEN_ONLY_MODE) { + if (mode == CAN_LISTEN_ONLY_MODE) { mode_register = (0<. - Version: 1.0 + Version: 3.0 Design: David Gascón Implementation: Luis Antonio Martín Nuez & Ahmad Saad */ @@ -52,10 +52,10 @@ #define SPI_RX_STATUS 0xB0 #define SPI_BIT_MODIFY 0x05 -#define LISTEN_ONLY_MODE 0x01 -#define LOOPBACK_MODE 0x02 -#define SLEEP_MODE 0x03 -#define NORMAL_MODE 0x04 +#define CAN_LISTEN_ONLY_MODE 0x01 +#define CAN_LOOPBACK_MODE 0x02 +#define CAN_SLEEP_MODE 0x03 +#define CAN_NORMAL_MODE 0x04 /*********************************************************************** MCP2515 REGISTERS diff --git a/libraries/CAN/keywords.txt b/libraries/CAN/keywords.txt index b8d7dfa..c2ed0eb 100644 --- a/libraries/CAN/keywords.txt +++ b/libraries/CAN/keywords.txt @@ -54,10 +54,10 @@ SPI_RTS LITERAL1 SPI_READ_STATUS LITERAL1 SPI_RX_STATUS LITERAL1 SPI_BIT_MODIFY LITERAL1 -LISTEN_ONLY_MODE LITERAL1 -LOOPBACK_MODE LITERAL1 -SLEEP_MODE LITERAL1 -NORMAL_MODE LITERAL1 +CAN_LISTEN_ONLY_MODE LITERAL1 +CAN_LOOPBACK_MODE LITERAL1 +CAN_SLEEP_MODE LITERAL1 +CAN_NORMAL_MODE LITERAL1 RXF0SIDH LITERAL1 RXF0SIDL LITERAL1 RXF0EID8 LITERAL1 @@ -172,6 +172,99 @@ RXB1D4 LITERAL1 RXB1D5 LITERAL1 RXB1D6 LITERAL1 RXB1D7 LITERAL1 +B1BFS LITERAL1 +B0BFS LITERAL1 +B1BFE LITERAL1 +B0BFE LITERAL1 +B1BFM LITERAL1 +B0BFM LITERAL1 +B2RTS LITERAL1 +B1RTS LITERAL1 +B0RTS LITERAL1 +B2RTSM LITERAL1 +B1RTSM LITERAL1 +B0RTSM LITERAL1 +OPMOD2 LITERAL1 +OPMOD1 LITERAL1 +OPMOD0 LITERAL1 +ICOD2 LITERAL1 +ICOD1 LITERAL1 +ICOD0 LITERAL1 +REQOP2 LITERAL1 +REQOP1 LITERAL1 +REQOP0 LITERAL1 +ABAT LITERAL1 +CLKEN LITERAL1 +CLKPRE1 LITERAL1 +CLKPRE0 LITERAL1 +SOF LITERAL1 +WAKFIL LITERAL1 +PHSEG22 LITERAL1 +PHSEG21 LITERAL1 +PHSEG20 LITERAL1 +BTLMODE LITERAL1 +SAM LITERAL1 +PHSEG12 LITERAL1 +PHSEG11 LITERAL1 +PHSEG10 LITERAL1 +PHSEG2 LITERAL1 +PHSEG1 LITERAL1 +PHSEG0 LITERAL1 +SJW1 LITERAL1 +SJW0 LITERAL1 +BRP5 LITERAL1 +BRP4 LITERAL1 +BRP3 LITERAL1 +BRP2 LITERAL1 +BRP1 LITERAL1 +BRP0 LITERAL1 +MERRE LITERAL1 +WAKIE LITERAL1 +ERRIE LITERAL1 +TX2IE LITERAL1 +TX1IE LITERAL1 +TX0IE LITERAL1 +RX1IE LITERAL1 +RX0IE LITERAL1 +MERRF LITERAL1 +WAKIF LITERAL1 +ERRIF LITERAL1 +TX2IF LITERAL1 +TX1IF LITERAL1 +TX0IF LITERAL1 +RX1IF LITERAL1 +RX0IF LITERAL1 +RX1OVR LITERAL1 +RX0OVR LITERAL1 +TXB0 LITERAL1 +TXEP LITERAL1 +RXEP LITERAL1 +TXWAR LITERAL1 +RXWAR LITERAL1 +EWARN LITERAL1 +ABTF LITERAL1 +MLOA LITERAL1 +TXERR LITERAL1 +TXREQ LITERAL1 +TXP1 LITERAL1 +TXP0 LITERAL1 +RXM1 LITERAL1 +RXM0 LITERAL1 +RXRTR LITERAL1 +BUKT LITERAL1 +BUKT1 LITERAL1 +FILHIT0 LITERAL1 +RSM1 LITERAL1 +FILHIT2 LITERAL1 +FILHIT1 LITERAL1 +EXIDE LITERAL1 +SRR LITERAL1 +IDE LITERAL1 +RTR LITERAL1 +DLC3 LITERAL1 +DLC2 LITERAL1 +DLC1 LITERAL1 +DLC0 LITERAL1 messageRx KEYWORD2 messageTx KEYWORD2 @@ -199,4 +292,4 @@ getEngineFuelRate KEYWORD2 CiARequest KEYWORD2 sendMessage KEYWORD2 -CAN KEYWORD3 +CAN KEYWORD1 diff --git a/libraries/Frame/WaspFrame.cpp b/libraries/Frame/WaspFrame.cpp index b887b8f..0ad686d 100755 --- a/libraries/Frame/WaspFrame.cpp +++ b/libraries/Frame/WaspFrame.cpp @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.9 + * Version: 3.0 * Design: David Gascón * Implementation: Yuri Carmona, Javier Siscart, Joaquín Ruiz */ @@ -26,7 +26,6 @@ #endif #include "WaspFrame.h" -#include "WaspFrameConstants.h" @@ -69,7 +68,7 @@ WaspFrame::WaspFrame() */ void WaspFrame::setFrameSize( uint8_t size ) { - if( size < MAX_FRAME) + if (size < MAX_FRAME) { // set new maximum size _maxSize = size; @@ -79,10 +78,6 @@ void WaspFrame::setFrameSize( uint8_t size ) // input parameter exceeds the predefined constant _maxSize = MAX_FRAME; } - - - - } @@ -150,205 +145,119 @@ void WaspFrame::setFrameSize( uint8_t protocol, uint8_t addressing, uint8_t linkEncryption, uint8_t AESEncryption) -{ - - /// AES disabled - if( AESEncryption == DISABLED ) - { - switch (protocol) - { - /// XBEE_802_15_4 //////////////// - case XBEE_802_15_4: - - if( linkEncryption == DISABLED) - { - // XBEE_802 & Link Disabled & AES Disabled - _maxSize = 100; - } - else if( linkEncryption == ENABLED) - { - if( addressing == UNICAST_16B ) - { - // XBEE_802 & Unicast 16B & Link Enabled & AES Disabled - _maxSize = 98; - } - else if( addressing == UNICAST_64B ) - { - // XBEE_802 & Unicast 64B & Link Enabled & AES Disabled - _maxSize = 94; - } - else if( addressing == BROADCAST_MODE ) - { - // XBEE_802 & Broadcast & Link Enabled & AES Disabled - _maxSize = 95; - } - } - break; - - /// ZIGBEE ///////////////////// - case ZIGBEE: - - if( linkEncryption == DISABLED) +{ + // no limit + _maxSize = MAX_FRAME; + + switch (protocol) + { + /// XBEE_802_15_4 //////////////// + case XBEE_802_15_4: + + if( linkEncryption == DISABLED) + { + // XBEE_802 & Link Disabled + _maxSize = 100; + } + else if( linkEncryption == ENABLED) + { + if( addressing == UNICAST_16B ) { - if( addressing == UNICAST_64B ) - { - // ZIGBEE & Unicast & Link Disabled & AES Disabled - _maxSize = 74; - } - else if( addressing == BROADCAST_MODE ) - { - // ZIGBEE & Broadcast & Link Disabled & AES Disabled - _maxSize = 92; - } + // XBEE_802 & Unicast 16B & Link Enabled + _maxSize = 98; } - else if( linkEncryption == ENABLED) + else if( addressing == UNICAST_64B ) { - if( addressing == UNICAST_64B ) - { - // ZIGBEE & Unicast 64B & Link Enabled & AES Disabled - _maxSize = 66; - } - else if( addressing == BROADCAST_MODE ) - { - // ZIGBEE & Broadcast & Link Enabled & AES Disabled - _maxSize = 84; - } - } - break; - - /// DIGIMESH ///////////////////// - case DIGIMESH: - - _maxSize = 73; - break; - - /// XBEE_900 ///////////////////// - case XBEE_900: - - if( linkEncryption == DISABLED) - { - _maxSize = 100; + // XBEE_802 & Unicast 64B & Link Enabled + _maxSize = 94; } - else if( linkEncryption == ENABLED) + else if( addressing == BROADCAST_MODE ) + { + // XBEE_802 & Broadcast & Link Enabled + _maxSize = 95; + } + } + break; + + /// ZIGBEE ///////////////////// + case ZIGBEE: + + if( linkEncryption == DISABLED) + { + if( addressing == UNICAST_64B ) { - _maxSize = 80; - } - - break; - - /// XBEE_868 ///////////////////// - case XBEE_868: - - _maxSize = 100; - break; - - default : - // No limit - _maxSize = MAX_FRAME; - break; - } - } - /// AES enabled - else if( AESEncryption == ENABLED ) - { - switch (protocol) - { - /// XBEE_802_15_4 //////////////// - case XBEE_802_15_4: - - if( linkEncryption == DISABLED) - { - // XBEE_802 & Link Disabled & AES Enabled - _maxSize = ((100-10-strlen(_waspmoteID))/16)*16; + // ZIGBEE & Unicast & Link Disabled & AES Disabled + _maxSize = 74; } - else if( linkEncryption == ENABLED) - { - if( addressing == UNICAST_16B ) - { - // XBEE_802 & Unicast 16B & Link Enabled & AES Enabled - _maxSize = ((98-10-strlen(_waspmoteID))/16)*16; - } - else if( addressing == UNICAST_64B ) - { - // XBEE_802 & Unicast 64B & Link Enabled & AES Enabled - _maxSize = ((94-10-strlen(_waspmoteID))/16)*16; - } - else if( addressing == BROADCAST_MODE ) - { - // XBEE_802 & Broadcast & Link Enabled & AES Enabled - _maxSize = ((95-10-strlen(_waspmoteID))/16)*16; - } - } - break; - - /// ZIGBEE ///////////////////// - case ZIGBEE: - - if( linkEncryption == DISABLED) + else if( addressing == BROADCAST_MODE ) + { + // ZIGBEE & Broadcast & Link Disabled & AES Disabled + _maxSize = 92; + } + } + else if( linkEncryption == ENABLED) + { + if( addressing == UNICAST_64B ) { - if( addressing == UNICAST_64B ) - { - // ZIGBEE & Unicast & Link Disabled & AES Enabled - _maxSize = ((74-10-strlen(_waspmoteID))/16)*16; - } - else if( addressing == BROADCAST_MODE ) - { - // ZIGBEE & Broadcast & Link Disabled & AES Enabled - _maxSize = ((92-10-strlen(_waspmoteID))/16)*16; - } + // ZIGBEE & Unicast 64B & Link Enabled & AES Disabled + _maxSize = 66; } - else if( linkEncryption == ENABLED) - { - if( addressing == UNICAST_64B ) - { - // ZIGBEE & Unicast 64B & Link Enabled & AES Enabled - _maxSize = ((66-10-strlen(_waspmoteID))/16)*16; - } - else if( addressing == BROADCAST_MODE ) - { - // ZIGBEE & Broadcast & Link Enabled & AES Enabled - _maxSize = ((84-10-strlen(_waspmoteID))/16)*16; - } - } - break; + else if( addressing == BROADCAST_MODE ) + { + // ZIGBEE & Broadcast & Link Enabled & AES Disabled + _maxSize = 84; + } + } + break; + + /// DIGIMESH ///////////////////// + case DIGIMESH: - /// DIGIMESH ///////////////////// - case DIGIMESH: + _maxSize = 73; + break; + + /// XBEE_900 ///////////////////// + case XBEE_900: + + if( linkEncryption == DISABLED) + { + _maxSize = 100; + } + else if( linkEncryption == ENABLED) + { + _maxSize = 80; + } - _maxSize = ((73-10-strlen(_waspmoteID))/16)*16; - break; - - /// XBEE_900 ///////////////////// - case XBEE_900: + break; + + /// XBEE_868 ///////////////////// + case XBEE_868: - if( linkEncryption == DISABLED) - { - _maxSize = ((100-10-strlen(_waspmoteID))/16)*16; - } - else if( linkEncryption == ENABLED) - { - _maxSize = ((80-10-strlen(_waspmoteID))/16)*16; - } - - break; + _maxSize = 100; + break; - /// XBEE_868 ///////////////////// - case XBEE_868: - - _maxSize = ((100-10-strlen(_waspmoteID))/16)*16; - break; - - default : - // No limit - _maxSize = MAX_FRAME; - break; - } + default : + // No limit + _maxSize = MAX_FRAME; + break; + } + + /// AES enabled + if (AESEncryption == ENABLED) + { + uint8_t fixed_header_length; + + if (_boot_version >= 'G') + { + fixed_header_length = 14; + } + else + { + fixed_header_length = 10; + } + + _maxSize = ((_maxSize - fixed_header_length - strlen(_waspmoteID))/16)*16; - } - /// No limit - else - { - _maxSize = MAX_FRAME; } } @@ -361,7 +270,7 @@ void WaspFrame::setFrameSize( uint8_t protocol, * * */ -uint8_t WaspFrame::getFrameSize( void ) +uint16_t WaspFrame::getFrameSize( void ) { return _maxSize; } @@ -395,7 +304,7 @@ void WaspFrame::createFrame(uint8_t mode) { // local variables uint8_t sequence; - char str[16]; + char str[17]; // store mode: ASCII or BINARY _mode = mode; @@ -417,7 +326,14 @@ void WaspFrame::createFrame(uint8_t mode) if( _mode == ASCII ) { /** ASCII FRAME **/ - type=B10000000; + if (_boot_version >= 'G') + { + type = INFORMATION_FRAME_V15+128; + } + else + { + type = INFORMATION_FRAME_V12+128; + } buffer[3]= type; // initialize 'number of fields' byte @@ -429,8 +345,33 @@ void WaspFrame::createFrame(uint8_t mode) // set serial ID length = 6; - // _serial_id is read in main.cpp - snprintf(str, sizeof(str), "%lu", _serial_id); + // add _serial_id depending on the hw version + if (_boot_version >= 'G') + { + snprintf(str, + sizeof(str), + "%02X%02X%02X%02X%02X%02X%02X%02X", + _serial_id[0], + _serial_id[1], + _serial_id[2], + _serial_id[3], + _serial_id[4], + _serial_id[5], + _serial_id[6], + _serial_id[7]); + } + else + { + union { + uint32_t lu; + char array[4]; + } aux; + aux.array[3] = _serial_id[4]; + aux.array[2] = _serial_id[5]; + aux.array[1] = _serial_id[6]; + aux.array[0] = _serial_id[7]; + snprintf(str, sizeof(str),"%lu", aux.lu); + } for( uint16_t i=0 ; i= 'G') { - /** BINARY FRAME **/ - type=B00000000; - buffer[3] = type; + type = INFORMATION_FRAME_V15; } - + else + { + type = INFORMATION_FRAME_V12; + } + buffer[3] = type; + // set serial ID // _serial_id is read in main.cpp char val[4]; - memcpy(val, (const void*)&_serial_id, 4); + memcpy(val, (const void*)&_serial_id[4], 4); /*union { unsigned long f; @@ -522,13 +467,30 @@ void WaspFrame::createFrame(uint8_t mode) u.b[0] = val[0]; USB.println(u.f); */ - + + // concatenate sensor name to frame string - buffer[5] = val[0]; - buffer[6] = val[1]; - buffer[7] = val[2]; - buffer[8] = val[3]; - length = 9; + // add _serial_id depending on the hw version + if (_boot_version >= 'G') + { + buffer[5] = _serial_id[0]; + buffer[6] = _serial_id[1]; + buffer[7] = _serial_id[2]; + buffer[8] = _serial_id[3]; + buffer[9] = _serial_id[4]; + buffer[10] = _serial_id[5]; + buffer[11] = _serial_id[6]; + buffer[12] = _serial_id[7]; + length = 13; + } + else + { + buffer[5] = val[0]; + buffer[6] = val[1]; + buffer[7] = val[2]; + buffer[8] = val[3]; + length = 9; + } // set identifier for( int i=0 ; i<16 ; i++ ) @@ -592,6 +554,9 @@ void WaspFrame::createFrame(uint8_t mode) */ uint8_t WaspFrame::encryptFrame( uint16_t keySize, char* password ) { + // define var + uint16_t temp_length; + // Variable for encrypted message's length uint16_t encrypted_length; @@ -627,40 +592,73 @@ uint8_t WaspFrame::encryptFrame( uint16_t keySize, char* password ) // key size. ECB mode is always used for Meshlium. uint8_t frame_type; - if( keySize == AES_128 ) - { - frame_type = AES128_ECB_FRAME; - } - else if( keySize == AES_192 ) - { - frame_type = AES192_ECB_FRAME; - } - else if( keySize == AES_256 ) + // insert serial ID + if (_boot_version >= 'G') { - frame_type = AES256_ECB_FRAME; + switch (keySize) + { + case AES_128: frame_type = AES128_ECB_FRAME_V15; + break; + case AES_192: frame_type = AES192_ECB_FRAME_V15; + break; + case AES_256: frame_type = AES256_ECB_FRAME_V15; + break; + default: return 0; + + } } else { - return 0; + switch (keySize) + { + case AES_128: frame_type = AES128_ECB_FRAME_V12; + break; + case AES_192: frame_type = AES192_ECB_FRAME_V12; + break; + case AES_256: frame_type = AES256_ECB_FRAME_V12; + break; + default: return 0; + + } } - - // set serial ID - char val[4]; - memcpy(val, (const void*)&_serial_id, 4); - + // set frame delimiter frame.buffer[0] = '<'; frame.buffer[1] = '='; frame.buffer[2] = '>'; frame.buffer[3] = frame_type; frame.buffer[4] = encrypted_length + 5 + strlen(frame._waspmoteID); // length - frame.buffer[5] = val[0]; // serial ID - frame.buffer[6] = val[1]; // serial ID - frame.buffer[7] = val[2]; // serial ID - frame.buffer[8] = val[3]; // serial ID - // temporal length of frame - uint16_t temp_length = 9; + + // insert serial ID + if (_boot_version >= 'G') + { + frame.buffer[5] = _serial_id[0]; // serial ID + frame.buffer[6] = _serial_id[1]; // serial ID + frame.buffer[7] = _serial_id[2]; // serial ID + frame.buffer[8] = _serial_id[3]; // serial ID + frame.buffer[9] = _serial_id[4]; // serial ID + frame.buffer[10] = _serial_id[5]; // serial ID + frame.buffer[11] = _serial_id[6]; // serial ID + frame.buffer[12] = _serial_id[7]; // serial ID + + // temporal length of frame + temp_length = 13; + } + else + { + // set serial ID + char val[4]; + memcpy(val, (const void*)&_serial_id[4], 4); + + frame.buffer[5] = val[0]; + frame.buffer[6] = val[1]; + frame.buffer[7] = val[2]; + frame.buffer[8] = val[3]; + + // temporal length of frame + temp_length = 9; + } // waspmote ID for(uint16_t i = 0; i < strlen(frame._waspmoteID) ; i++) @@ -801,13 +799,21 @@ void WaspFrame::showFrame(void) */ int8_t WaspFrame::addSensor(uint8_t type, int value) { - char str[10]; + char str[20]; if(_mode == ASCII) { // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string itoa( value, str, 10); @@ -872,7 +878,16 @@ int8_t WaspFrame::addSensor(uint8_t type, int value) //Check again (1 byte or 2 bytes) uint8_t config; - config =(uint8_t)pgm_read_word(&(SENSOR_TYPE_TABLE[type])); + + if (_boot_version >= 'G') + { + config = (uint8_t)pgm_read_word(&(FRAME_SENSOR_TYPE_TABLE[type])); + } + else + { + config = (uint8_t)pgm_read_word(&(SENSOR_TYPE_TABLE[type])); + } + if (config == TYPE_INT) { @@ -914,6 +929,151 @@ int8_t WaspFrame::addSensor(uint8_t type, int value) +/* + * addSensor (type, value) - add sensor value to frame + * + * Parameters: + * type : Refers to the type of sensor data + * value : indicates the sensor value as a float + * + * Returns: + * 'length' of the composed frame when ok + * -1 when the maximum length of the frame is reached + * + */ +int8_t WaspFrame::addSensor(uint8_t type, uint16_t value) +{ + char str[20]; + + if(_mode == ASCII) + { + // get name of sensor from table + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } + + // convert from integer to string + ultoa( (uint32_t)value, str, 10); + + // check if new sensor value fits in the frame or not + // in the case the maximum length is reached, exit with error + // if not, then add the new sensor length to the total length + if(!checkLength( strlen(name) + + strlen(str) + + strlen(":") + + strlen("#") )) + { + return -1; + } + + // create index for each element to be inserted in the sensor field + // 'index_1' is needed for adding the sensor tag + // 'index_2' is needed for adding ':' + // 'index_3' is needed for adding sensor value + // 'index_4' is needed for adding the separator '#' + int index_1 = length-strlen(name)-strlen(str)-strlen(":")-strlen("#"); + int index_2 = length-strlen(str)-strlen(":")-strlen("#"); + int index_3 = length-strlen(str)-strlen("#"); + int index_4 = length-strlen("#"); + + // add sensor tag + memcpy ( &buffer[index_1], name, strlen(name) ); + + // add ':' + memcpy ( &buffer[index_2], ":", strlen(":") ); + + // add input string defined in 'str' + memcpy ( &buffer[index_3], str, strlen(str) ); + + // add separator '#' + memcpy ( &buffer[index_4], "#", strlen("#") ); + + // increment sensor fields counter + numFields++; + + // set sensor fields counter + buffer[4] = numFields; + } + else + { + // check if the data input type corresponds to the sensor + if (value<=255) + { + if( checkFields(type, TYPE_UINT8, 1) == -1 ) return -1; + } + else + { + if( checkFields(type, TYPE_INT, 1) == -1 ) return -1; + } + + // set data bytes (in this case, int is two bytes) + char val[2]; + memcpy(val,&value,2); + + /*char val1 = value &0xFF; + char val2 = (value >> 8) &0xFF; */ + + //Check again (1 byte or 2 bytes) + uint8_t config; + + if (_boot_version >= 'G') + { + config = (uint8_t)pgm_read_word(&(FRAME_SENSOR_TYPE_TABLE[type])); + } + else + { + config = (uint8_t)pgm_read_word(&(SENSOR_TYPE_TABLE[type])); + } + + + if (config == TYPE_INT) + { + // check if new sensor value fits + if(!checkLength(3)) + { + return -1; + } + + // concatenate sensor name to frame string + buffer[length-3] = (char)type; + buffer[length-2] = val[0]; + buffer[length-1] = val[1]; + buffer[length] = '\0'; + } + else + { + // check if new sensor value fits + if(!checkLength(2)) + { + return -1; + } + + // concatenate sensor name to frame string + buffer[length-2] = (char)type; + buffer[length-1] = val[0]; + buffer[length] = '\0'; + } + + // increment sensor fields counter + numFields++; + // update number of bytes field + buffer[4] = frame.length-5; + + } + + return length; +} + + + + /* * addSensor (type, value) - add sensor value to frame * @@ -933,8 +1093,16 @@ int8_t WaspFrame::addSensor(uint8_t type, unsigned long value) if(_mode == ASCII) { // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string ultoa( value, str, 10); @@ -1044,7 +1212,15 @@ int8_t WaspFrame::addSensor(uint8_t type, double value) { // get name of sensor from table char numDecimals; - numDecimals =(uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + + if (_boot_version >= 'G') + { + numDecimals = (uint8_t)pgm_read_word(&(FRAME_DECIMAL_TABLE[type])); + } + else + { + numDecimals = (uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + } return addSensor(type, value, numDecimals); } @@ -1074,8 +1250,16 @@ int8_t WaspFrame::addSensor(uint8_t type, double value, int N) dtostrf( value, N, N, str ); // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // check if new sensor value fits in the frame or not // in the case the maximum length is reached, exit with error @@ -1185,7 +1369,7 @@ int8_t WaspFrame::addSensor(uint8_t type, char* str) // limit the max string length to MAX_SIZE Bytes // to avoid running out of memory - if ( string_length >= MAX_SIZE) + if (string_length >= MAX_SIZE) { string_length = MAX_SIZE; } @@ -1211,8 +1395,16 @@ int8_t WaspFrame::addSensor(uint8_t type, char* str) if(_mode == ASCII) { // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // check if new sensor value fits in the frame or not // in the case the maximum length is reached, exit with error @@ -1315,7 +1507,15 @@ int8_t WaspFrame::addSensor(uint8_t type, double val1, double val2) { // get name of sensor from table char numDecimals; - numDecimals =(uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + + if (_boot_version >= 'G') + { + numDecimals = (uint8_t)pgm_read_word(&(FRAME_DECIMAL_TABLE[type])); + } + else + { + numDecimals = (uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + } // convert from float to string @@ -1323,8 +1523,16 @@ int8_t WaspFrame::addSensor(uint8_t type, double val1, double val2) dtostrf( val2, numDecimals, numDecimals, str2 ); // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // check if new sensor value fits in the frame or not // in the case the maximum length is reached, exit with error @@ -1452,8 +1660,16 @@ int8_t WaspFrame::addSensor(uint8_t type, unsigned long val1, unsigned long val2 if(_mode == ASCII) { // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string ultoa( val1, str1, 10); @@ -1571,17 +1787,25 @@ int8_t WaspFrame::addSensor(uint8_t type, unsigned long val1, unsigned long val2 */ int8_t WaspFrame::addSensor(uint8_t type, uint8_t val1, uint8_t val2, uint8_t val3) { - char str1[10]; - char str2[10]; - char str3[10]; + char str1[20]; + char str2[20]; + char str3[20]; if(_mode == ASCII) { /// ASCII // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string itoa( val1, str1, 10); @@ -1706,18 +1930,26 @@ int8_t WaspFrame::addSensor(uint8_t type, uint8_t val1, uint8_t val2, uint8_t va */ int8_t WaspFrame::addSensor(uint8_t type, uint8_t val1, uint8_t val2, uint8_t val3, int val4) { - char str1[10]; - char str2[10]; - char str3[10]; - char str4[10]; + char str1[20]; + char str2[20]; + char str3[20]; + char str4[20]; if(_mode == ASCII) { /// ASCII // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string itoa( val1, str1, 10); @@ -1864,15 +2096,23 @@ int8_t WaspFrame::addSensor(uint8_t type, uint8_t val1, uint8_t val2, uint8_t va */ int8_t WaspFrame::addSensor(uint8_t type, int val1,int val2,int val3) { - char str1[10]; - char str2[10]; - char str3[10]; + char str1[20]; + char str2[20]; + char str3[20]; if(_mode == ASCII) { // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // convert from integer to string itoa( val1, str1, 10); @@ -2001,7 +2241,15 @@ int8_t WaspFrame::addSensor(uint8_t type, double val1,double val2,double val3) { // get name of sensor from table char numDecimals; - numDecimals =(uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + + if (_boot_version >= 'G') + { + numDecimals = (uint8_t)pgm_read_word(&(FRAME_DECIMAL_TABLE[type])); + } + else + { + numDecimals = (uint8_t)pgm_read_word(&(DECIMAL_TABLE[type])); + } // convert from float to string dtostrf( val1, numDecimals, numDecimals, str1 ); @@ -2009,8 +2257,16 @@ int8_t WaspFrame::addSensor(uint8_t type, double val1,double val2,double val3) dtostrf( val3, numDecimals, numDecimals, str3 ); // get name of sensor from table - char name[10]; - strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + char name[20]; + + if (_boot_version >= 'G') + { + strcpy_P(name, (char*)pgm_read_word(&(FRAME_SENSOR_TABLE[type]))); + } + else + { + strcpy_P(name, (char*)pgm_read_word(&(SENSOR_TABLE[type]))); + } // check if new sensor value fits in the frame or not // in the case the maximum length is reached, exit with error @@ -2144,9 +2400,16 @@ int8_t WaspFrame::checkFields(uint8_t type, uint8_t typeVal, uint8_t fields) uint8_t config; uint8_t nfields; - // *1* check sensor typeVal + // *1* check sensor typeVal + if (_boot_version >= 'G') + { + config = (uint8_t)pgm_read_word(&(FRAME_SENSOR_TYPE_TABLE[type])); + } + else + { + config = (uint8_t)pgm_read_word(&(SENSOR_TYPE_TABLE[type])); + } - config =(uint8_t)pgm_read_word(&(SENSOR_TYPE_TABLE[type])); // special case (0 might be 1) if (config ==1) @@ -2157,10 +2420,12 @@ int8_t WaspFrame::checkFields(uint8_t type, uint8_t typeVal, uint8_t fields) } else { - USB.print(F("ERR sensor type & value mismatch, ")); - USB.print( config, DEC); + PRINT_FRAME(F("Error sensor type mismatch for index ")); + USB.print(type, DEC); + USB.print(F(": ")); + USB.print(config, DEC); USB.print(F(" vs ")); - USB.println( typeVal, DEC); + USB.println(typeVal, DEC); return -1; } } @@ -2172,7 +2437,9 @@ int8_t WaspFrame::checkFields(uint8_t type, uint8_t typeVal, uint8_t fields) } else { - USB.print(F("ERR sensor type & value mismatch, ")); + PRINT_FRAME(F("Error sensor type mismatch for index ")); + USB.print(type, DEC); + USB.print(F(": ")); USB.print( config, DEC); USB.print(F(" vs ")); USB.println( typeVal, DEC); @@ -2180,16 +2447,24 @@ int8_t WaspFrame::checkFields(uint8_t type, uint8_t typeVal, uint8_t fields) } } - // *2* check sensor number of fields - - nfields =(uint8_t)pgm_read_word(&(SENSOR_FIELD_TABLE[type])); + // *2* check sensor number of fields + if (_boot_version >= 'G') + { + nfields =(uint8_t)pgm_read_word(&(FRAME_SENSOR_FIELD_TABLE[type])); + } + else + { + nfields =(uint8_t)pgm_read_word(&(SENSOR_FIELD_TABLE[type])); + } + + if (nfields == fields) { //OK } else { - USB.println(F("ERR sensor type & number of fields mismatch")); + PRINT_FRAME(F("Error sensor type & number of fields mismatch\r\n")); return -1; } @@ -2239,7 +2514,7 @@ void WaspFrame::setID(char* moteID) // set zeros in EEPROM addresses for( int i=0 ; i<16 ; i++ ) { - eeprom_write_byte((unsigned char *) i+MOTEID_ADDR, 0x00); + eeprom_write_byte((unsigned char *) i+EEPROM_FRAME_MOTEID, 0x00); } // clear the waspmote ID attribute @@ -2248,14 +2523,14 @@ void WaspFrame::setID(char* moteID) // set the mote ID from EEPROM memory for( int i=0 ; i<16 ; i++ ) { - if( moteID[i] != '#' ) + if ((moteID[i] != '#') && (moteID[i] != ' ')) { - eeprom_write_byte((unsigned char *) i+MOTEID_ADDR, moteID[i]); + eeprom_write_byte((unsigned char *) i+EEPROM_FRAME_MOTEID, moteID[i]); _waspmoteID[i] = moteID[i]; } else { - eeprom_write_byte((unsigned char *) i+MOTEID_ADDR, '_'); + eeprom_write_byte((unsigned char *) i+EEPROM_FRAME_MOTEID, '_'); _waspmoteID[i] = '_'; } @@ -2282,7 +2557,7 @@ void WaspFrame::getID(char* moteID) // read mote ID from EEPROM memory for(int i=0 ; i<16 ; i++ ) { - _waspmoteID[i] = Utils.readEEPROM(i+MOTEID_ADDR); + _waspmoteID[i] = Utils.readEEPROM(i+EEPROM_FRAME_MOTEID); moteID[i] = _waspmoteID[i]; } moteID[16]='\0'; @@ -2297,7 +2572,7 @@ void WaspFrame::getID(char* moteID) void WaspFrame::storeSequence(uint8_t seqNumber) { // store frame sequence number to EEPROM[163] - eeprom_write_byte((unsigned char *) SEQUENCE_ADDR, seqNumber); + eeprom_write_byte((unsigned char *) EEPROM_FRAME_SEQUENCE, seqNumber); } @@ -2311,7 +2586,7 @@ void WaspFrame::storeSequence(uint8_t seqNumber) uint8_t WaspFrame::readSequence(void) { // read frame sequence number from EEPROM[163] - return Utils.readEEPROM(SEQUENCE_ADDR); + return Utils.readEEPROM(EEPROM_FRAME_SEQUENCE); } diff --git a/libraries/Frame/WaspFrame.h b/libraries/Frame/WaspFrame.h index 01d67f1..6cf83c5 100755 --- a/libraries/Frame/WaspFrame.h +++ b/libraries/Frame/WaspFrame.h @@ -1,7 +1,7 @@ /*! \file WaspFrame.h \brief Library for creating formated frames - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.9 + Version: 3.1 Design: David Gascón Implementation: Yuri Carmona, Javier Siscart, Joaquín Ruiz @@ -41,761 +41,18 @@ #include #include #include "../WaspAES/WaspAES.h" +#include "WaspFrameConstantsv12.h" +#include "WaspFrameConstantsv15.h" /****************************************************************************** * Definitions & Declarations ******************************************************************************/ +// define print message +#define PRINT_FRAME(str) USB.print(F("[FRAME] ")); USB.print(str); -/// Gases Board sensor measurements - -/*! \def SENSOR_CO - \brief Carbon Monoxide measurement type - */ -/*! \def SENSOR_CO2 - \brief Carbon Dioxide measurement type - */ -/*! \def SENSOR_O2 - \brief Oxygen measurement type - */ -/*! \def SENSOR_CH4 - \brief Methane measurement type - */ -/*! \def SENSOR_LPG - \brief Liquefied Pretoleum Gases measurement type - */ -/*! \def SENSOR_NH3 - \brief Ammonia measurement type - */ -/*! \def SENSOR_AP1 - \brief Air Pollutans 1 measurement type - */ -/*! \def SENSOR_AP2 - \brief Air Pollutans 2 measurement type - */ -/*! \def SENSOR_SV - \brief Solvent Vapors measurement type - */ -/*! \def SENSOR_NO2 - \brief Nitrogen Dioxide measurement type - */ -/*! \def SENSOR_O3 - \brief Ozone measurement type - */ -/*! \def SENSOR_VOC - \brief Hydrocarbons measurement type - */ -/*! \def SENSOR_TC - \brief Temperature Celsius measurement type - */ -/*! \def SENSOR_TF - \brief Temperature Fahrenheit measurement type - */ -/*! \def SENSOR_HUM - \brief Humidity measurement type - */ -/*! \def SENSOR_PA - \brief Pressure atmospheric measurement type - */ - - -/// Events Board Sensor measurements - -/*! \def SENSOR_PW - \brief Pressure/Weight measurement type - */ -/*! \def SENSOR_BEND - \brief Bend measurement type - */ -/*! \def SENSOR_VBR - \brief Vibration measurement type - */ -/*! \def SENSOR_HALL - \brief Hall Effect measurement type - */ -/*! \def SENSOR_LP - \brief Liquid Presence measurement type - */ -/*! \def SENSOR_LL - \brief Liquid Level measurement type - */ -/*! \def SENSOR_LUM - \brief Luminosity measurement type - */ -/*! \def SENSOR_PIR - \brief Presence measurement type - */ -/*! \def SENSOR_ST - \brief Stretch measurement type - */ - - -/// Smart cities sensor measurements - -/*! \def SENSOR_MCP - \brief Microphone measurement type - */ -/*! \def SENSOR_CDG - \brief Crack detection gauge measurement type - */ -/*! \def SENSOR_CPG - \brief Crack propagation gauge measurement type - */ -/*! \def SENSOR_LD - \brief Linear Displacement measurement type - */ -/*! \def SENSOR_DUST - \brief Dust measurement type - */ -/*! \def SENSOR_US - \brief Ultrasound measurement type - */ - - -/// Smart parking sensor measurements - -/*! \def SENSOR_MF - \brief Magnetic Field measurement type - */ -/*! \def SENSOR_PS - \brief Parking Spot Status measurement type - */ - -/// Agriculture sensor measurements - -/*! \def SENSOR_AIR - \brief Air Temperature / Humidity measurement type - */ -/*! \def SENSOR_SOIL - \brief Soil Temperature / Moisture measurement type - */ -/*! \def SENSOR_LW - \brief Leaf Wetness measurement type - */ -/*! \def SENSOR_PAR - \brief Solar Radiation measurement type - */ -/*! \def SENSOR_UV - \brief Ultraviolet Radiation measurement type - */ -/*! \def SENSOR_TD - \brief Trunk Diameter measurement type - */ -/*! \def SENSOR_SD - \brief Stem Diameter measurement type - */ -/*! \def SENSOR_FD - \brief Fruit Diameter measurement type - */ -/*! \def SENSOR_ANE - \brief Anemometer measurement type - */ -/*! \def SENSOR_WV - \brief Wind Vane measurement type - */ -/*! \def SENSOR_PLV - \brief Pluviometer measurement type - */ - - -/// Radiation sensor measurements - -/*! \def SENSOR_RAD - \brief Geiger tube measurement type - */ - - -/// Smart Metering sensor measurements - -/*! \def SENSOR_CU - \brief Current measurement type - */ -/*! \def SENSOR_WF - \brief Water flow measurement type - */ -/*! \def SENSOR_LC - \brief Load cell measurement type - */ -/*! \def SENSOR_DF - \brief Distance foil measurement type - */ - - -/// Additional sensor measurements - -/*! \def SENSOR_BAT - \brief Battery measurement type - */ -/*! \def SENSOR_GPS - \brief Global Positioning System measurement type - */ -/*! \def SENSOR_RSSI - \brief RSSI measurement type - */ -/*! \def SENSOR_MAC - \brief MAC Address measurement type - */ -/*! \def SENSOR_NA - \brief Network Address measurement type - */ -/*! \def SENSOR_NID - \brief Network Identifier origin measurement type - */ -/*! \def SENSOR_DATE - \brief Date measurement type - */ -/*! \def SENSOR_TIME - \brief Time measurement type - */ -/*! \def SENSOR_GMT - \brief GMT measurement type - */ -/*! \def SENSOR_RAM - \brief RAM measurement type - */ -/*! \def SENSOR_IN_TEMP - \brief Internal temperature measurement type - */ -/*! \def SENSOR_MILLIS - \brief Millis measurement type - */ - -/// Special sensor measurements - -/*! \def SENSOR_STR - \brief String type - */ - -/// Smart Water - -/*! \def SENSOR_PH - \brief pH measurement type - */ -/*! \def SENSOR_ORP - \brief Oxidation Reduction Potential measurement type - */ -/*! \def SENSOR_DI - \brief Disolved Ion measurement type - */ -/*! \def SENSOR_DO - \brief Disolved Oxygen measurement type - */ -/*! \def SENSOR_COND - \brief Conductivity measurement type - */ -/*! \def SENSOR_WT - \brief Water Temperature measurement type - */ - - -/// Smart Libelium -/*! \def SENSOR_DM_ST - \brief XBee Digimesh awake time for cyclic sleep mode - */ -/*! \def SENSOR_DM_SP - \brief XBee Digimesh asleep time for cyclic sleep mode - */ -/*! \def SENSOR_TX_PWR - \brief XBee transmision power - */ -/*! \def SENSOR_LUX - \brief Luxes measurement type - */ - - -/// GPS -/*! \def SENSOR_SPEED - \brief GPS speed over the ground measurement type - */ -/*! \def SENSOR_COURSE - \brief GPS course over the ground measurement type - */ -/*! \def SENSOR_ALTITUDE - \brief GPS altitude over the ground measurement type - */ -/*! \def SENSOR_HDOP - \brief GPS HDOP over the ground measurement type - */ -/*! \def SENSOR_VDOP - \brief GPS VDOP over the ground measurement type - */ -/*! \def SENSOR_PDOP - \brief GPS PDOP over the ground measurement type - */ - - -/// State Machine -/*! \def SENSOR_FSM - \brief Finite State Machine (FSM) value - */ - - -/// New pluviometer values -/*! \def SENSOR_PLV1 - \brief pluviomter value for current hour - */ - /*! \def SENSOR_PLV2 - \brief pluviomter value for previous hour - */ - /*! \def SENSOR_PLV3 - \brief pluviomter value for last 24h - */ - -/// P&S watermarks -/*! \def SENSOR_SOIL_C - \brief watermark value for P&S connector C - */ - /*! \def SENSOR_SOIL_D - \brief watermark value for P&S connector D - */ - /*! \def SENSOR_SOIL_E - \brief watermark value for P&S connector E - */ - /*! \def SENSOR_SOIL_F - \brief watermark value for P&S connector F - */ - -/// Waspmote OEM watermarks -/*! \def SENSOR_SOIL1 - \brief Agriculture Board watermark1 - */ - /*! \def SENSOR_SOIL2 - \brief Agriculture Board watermark2 - */ - /*! \def SENSOR_SOIL3 - \brief Agriculture Board watermark3 - */ - - /// DS18B20 - /*! \def SENSOR_TCC - \brief DS18B20 temperature sensor - */ - - /// P&S Ultrasound depending on socket voltage ref - /*! \def SENSOR_US_3V3 - \brief WRA1 Ultrasound sensor powered at 3V3 - */ -/*! \def SENSOR_US_5V - \brief WRA1 Ultrasound sensor powered at 5V - */ - - -/// P&S Security sensors depending on socket (Security - Events board) - /*! \def SENSOR_LUM_D - \brief LDR sensor in socket D - */ -/*! \def SENSOR_LUM_E - \brief LDR sensor in socket E - */ - /*! \def SENSOR_LUM_F - \brief LDR sensor in socket F - */ - /*! \def SENSOR_LP_D - \brief Liquid Presence sensor in socket D - */ - /*! \def SENSOR_LP_E - \brief Liquid Presence sensor in socket E - */ - /*! \def SENSOR_LP_F - \brief Liquid Presence sensor in socket F - */ - /*! \def SENSOR_LL_D - \brief Liquid Level sensor in socketD - */ - /*! \def SENSOR_LL_E - \brief Liquid Level sensor in socketE - */ - /*! \def SENSOR_LL_F - \brief Liquid Level sensor in socketF - */ - /*! \def SENSOR_HALL_D - \brief Hall Effect sensor in socket D - */ - /*! \def SENSOR_HALL_E - \brief Hall Effect sensor in socket E - */ - /*! \def SENSOR_HALL_F - \brief Hall Effect sensor in socket F - */ - -/// P&S liquid flow sensor depending on socket (Smart Metering) -/*! \def SENSOR_WF_C - \brief Liquid Flow sensor in socket C - */ -/*! \def SENSOR_WF_E - \brief Liquid Flow sensor in socket E - */ - -/// Unix/Epoch timestamp -/*! \def SENSOR_TST - \brief Unix (aka Epoch) timestamp value - */ - -/// Turbidity sensor -/*! \def SENSOR_TURB - \brief Turbidity sensor - */ - - -/// Version parameters -/*! \def SENSOR_VAPI - \brief API version - */ -/*! \def SENSOR_VPROG - \brief Program version - */ -/*! \def SENSOR_VBOOT - \brief Bootloader version - */ - - -/// Gases PRO -/*! \def SENSOR_GP_CL2 - \brief Chlorine measurement type - */ -/*! \def SENSOR_GP_CO - \brief Carbon Monoxide measurement type - */ -/*! \def SENSOR_GP_ETO - \brief Ethylene Oxide measurement type - */ -/*! \def SENSOR_GP_H2 - \brief Hydrogen measurement type - */ -/*! \def SENSOR_GP_H2S - \brief Hydrogen Sulphide measurement type - */ -/*! \def SENSOR_GP_HCL - \brief Hydrogen Chloride measurement type - */ -/*! \def SENSOR_GP_HCN - \brief Hydrogen Cyanide measurement type - */ -/*! \def SENSOR_GP_NH3 - \brief Ammonia measurement type - */ -/*! \def SENSOR_GP_NO - \brief Nitrogen Monoxide measurement type - */ -/*! \def SENSOR_GP_NO2 - \brief Nitrogen Dioxide measurement type - */ -/*! \def SENSOR_GP_O2 - \brief Oxygen measurement type - */ -/*! \def SENSOR_GP_PH3 - \brief Phospine measurement type - */ -/*! \def SENSOR_GP_SO2 - \brief Sulfur Dioxide measurement type - */ -/*! \def SENSOR_GP_CH4 - \brief Methane and other combustible gases measurement type - */ -/*! \def SENSOR_GP_O3 - \brief Ozone measurement type - */ -/*! \def SENSOR_GP_CO2 - \brief Carbon Dioxide measurement type - */ -/*! \def SENSOR_GP_TC - \brief Temperature Celsius measurement type - */ -/*! \def SENSOR_GP_TF - \brief Temperature Fahrenheit measurement type - */ -/*! \def SENSOR_GP_HUM - \brief Humidity measurement type - */ -/*! \def SENSOR_GP_PRES - \brief Pressure measurement type - */ -/*! \def SENSOR_OPC_TC - \brief Temperature Celsius measurement type - */ -/*! \def SENSOR_OPC_TF - \brief Temperature Fahrenheit measurement type - */ -/*! \def SENSOR_OPC_PM1 - \brief PM1 measurement type - */ -/*! \def SENSOR_OPC_PM2_5 - \brief PM2.5 measurement type - */ -/*! \def SENSOR_OPC_PM10 - \brief PM10 measurement type - */ -/*! \def SENSOR_OPC_PART - \brief Particle bin counter measurement type - */ -/*! \def SENSOR_SWI_CA - \brief Calcium ion measurement type - */ -/*! \def SENSOR_SWI_FL - \brief Fluoride ion measurement type - */ -/*! \def SENSOR_SWI_BF - \brief Tetrafluoroborate ion measurement type - */ -/*! \def SENSOR_SWI_NO - \brief Nitrates ion measurement type - */ -/*! \def SENSOR_SWI_BR - \brief Bromide ion measurement type - */ -/*! \def SENSOR_SWI_CL - \brief Chlorideion measurement type - */ -/*! \def SENSOR_SWI_CU - \brief Cupric ion measurement type - */ -/*! \def SENSOR_SWI_IO - \brief Iodide ion measurement type - */ -/*! \def SENSOR_SWI_PB - \brief Lead ion measurement type - */ -/*! \def SENSOR_SWI_AG - \brief Silver ion measurement type - */ -/*! \def SENSOR_SWI_PH - \brief pH (for Smart Water Ions) measurement type - */ - - -// Gases -#define SENSOR_CO 0 -#define SENSOR_CO2 1 -#define SENSOR_O2 2 -#define SENSOR_CH4 3 -#define SENSOR_LPG 4 -#define SENSOR_NH3 5 -#define SENSOR_AP1 6 -#define SENSOR_AP2 7 -#define SENSOR_SV 8 -#define SENSOR_NO2 9 -#define SENSOR_O3 10 -#define SENSOR_VOC 11 -#define SENSOR_TCA 12 -#define SENSOR_TFA 13 -#define SENSOR_HUMA 14 -#define SENSOR_PA 15 - -// Events -#define SENSOR_PW 16 -#define SENSOR_BEND 17 -#define SENSOR_VBR 18 -#define SENSOR_HALL 19 -#define SENSOR_LP 20 -#define SENSOR_LL 21 -#define SENSOR_LUM 22 -#define SENSOR_PIR 23 -#define SENSOR_ST 24 - -// Smart Cities -#define SENSOR_MCP 25 -#define SENSOR_CDG 26 -#define SENSOR_CPG 27 -#define SENSOR_LD 28 -#define SENSOR_DUST 29 -#define SENSOR_US 30 - -// Smart parking -#define SENSOR_MF 31 -#define SENSOR_PS 32 - -// Agriculture -#define SENSOR_TCB 33 -#define SENSOR_TFB 34 -#define SENSOR_HUMB 35 -#define SENSOR_SOILT 36 -#define SENSOR_SOIL 37 -#define SENSOR_LW 38 -#define SENSOR_PAR 39 -#define SENSOR_UV 40 -#define SENSOR_TD 41 -#define SENSOR_SD 42 -#define SENSOR_FD 43 -#define SENSOR_ANE 44 -#define SENSOR_WV 45 -#define SENSOR_PLV 46 - -// Radiation -#define SENSOR_RAD 47 - -// Smart meetering -#define SENSOR_CU 48 -#define SENSOR_WF 49 -#define SENSOR_LC 50 -#define SENSOR_DF 51 - -// Additional -#define SENSOR_BAT 52 -#define SENSOR_GPS 53 -#define SENSOR_RSSI 54 -#define SENSOR_MAC 55 -#define SENSOR_NA 56 -#define SENSOR_NID 57 -#define SENSOR_DATE 58 -#define SENSOR_TIME 59 -#define SENSOR_GMT 60 -#define SENSOR_RAM 61 -#define SENSOR_IN_TEMP 62 -#define SENSOR_ACC 63 -#define SENSOR_MILLIS 64 - -// Special -#define SENSOR_STR 65 - -// Meshlium -#define SENSOR_MBT 66 -#define SENSOR_MWIFI 67 - -// RFID -#define SENSOR_UID 68 -#define SENSOR_RB 69 - -// Smart Water -#define SENSOR_PH 70 -#define SENSOR_ORP 71 -#define SENSOR_DO 72 -#define SENSOR_COND 73 -#define SENSOR_WT 74 -#define SENSOR_DINA 75 -#define SENSOR_DICA 76 -#define SENSOR_DIF 77 -#define SENSOR_DICL 78 -#define SENSOR_DIBR 79 -#define SENSOR_DII 80 -#define SENSOR_DICU2 81 -#define SENSOR_DIK 82 -#define SENSOR_DIMG2 83 -#define SENSOR_DINO3 84 - -// Smart Libelium -#define SENSOR_TX_PWR 85 -#define SENSOR_DM_ST 86 -#define SENSOR_DM_SP 87 -#define SENSOR_LUX 88 - -// GPS -#define SENSOR_SPEED 89 -#define SENSOR_COURSE 90 -#define SENSOR_ALTITUDE 91 -#define SENSOR_HDOP 92 -#define SENSOR_VDOP 93 -#define SENSOR_PDOP 94 - -// Finite State Machine status -#define SENSOR_FSM 95 - -// New pluviometer values -#define SENSOR_PLV1 96 -#define SENSOR_PLV2 97 -#define SENSOR_PLV3 98 - -// P&S watermark sensors (Smart Agriculture) -#define SENSOR_SOIL_C 99 -#define SENSOR_SOIL_D 100 -#define SENSOR_SOIL_E 101 -#define SENSOR_SOIL_F 102 - -// Waspmote OEM watermark sensors -#define SENSOR_SOIL1 103 -#define SENSOR_SOIL2 104 -#define SENSOR_SOIL3 105 - -// DS18B20 -#define SENSOR_TCC 106 - -// P&S Ultrasound depending on socket voltage ref (Smart Cities & Smart Metering) -#define SENSOR_US_3V3 107 -#define SENSOR_US_5V 108 - -// P&S Security sensors depending on socket (Smart Security) -#define SENSOR_LUM_D 109 -#define SENSOR_LUM_E 110 -#define SENSOR_LUM_F 111 -#define SENSOR_LP_D 112 -#define SENSOR_LP_E 113 -#define SENSOR_LP_F 114 -#define SENSOR_LL_D 115 -#define SENSOR_LL_E 116 -#define SENSOR_LL_F 117 -#define SENSOR_HALL_D 118 -#define SENSOR_HALL_E 119 -#define SENSOR_HALL_F 120 - -// P&S liquid flow sensor depending on socket (Smart Metering) -#define SENSOR_WF_C 121 -#define SENSOR_WF_E 122 - -// Unix/Epoch timestamp -#define SENSOR_TST 123 - -// Turbidity sensor -#define SENSOR_TURB 124 - -// Version parameters -#define SENSOR_VAPI 125 -#define SENSOR_VPROG 126 -#define SENSOR_VBOOT 127 - - -// Gases PRO -#define SENSOR_GP_CL2 128 -#define SENSOR_GP_CO 129 -#define SENSOR_GP_ETO 130 -#define SENSOR_GP_H2 131 -#define SENSOR_GP_H2S 132 -#define SENSOR_GP_HCL 133 -#define SENSOR_GP_HCN 134 -#define SENSOR_GP_NH3 135 -#define SENSOR_GP_NO 136 -#define SENSOR_GP_NO2 137 -#define SENSOR_GP_O2 138 -#define SENSOR_GP_PH3 139 -#define SENSOR_GP_SO2 140 -#define SENSOR_GP_CH4 141 -#define SENSOR_GP_O3 142 -#define SENSOR_GP_CO2 143 -#define SENSOR_GP_TC 144 -#define SENSOR_GP_TF 145 -#define SENSOR_GP_HUM 146 -#define SENSOR_GP_PRES 147 - -// OPCN2 Dust Sensor -#define SENSOR_OPC_TC 148 -#define SENSOR_OPC_TF 149 -#define SENSOR_OPC_P 150 -#define SENSOR_OPC_PM1 151 -#define SENSOR_OPC_PM2_5 152 -#define SENSOR_OPC_PM10 153 -#define SENSOR_OPC_PART 154 - -// Smart Water Ions -#define SENSOR_SWI_CA 155 -#define SENSOR_SWI_FL 156 -#define SENSOR_SWI_FB 157 -#define SENSOR_SWI_NO 158 -#define SENSOR_SWI_BR 159 -#define SENSOR_SWI_CL 160 -#define SENSOR_SWI_CU 161 -#define SENSOR_SWI_IO 162 -#define SENSOR_SWI_PB 163 -#define SENSOR_SWI_AG 164 -#define SENSOR_SWI_PH 165 - -// P&S Smart Water sensors depending on socket (Smart Water) -#define SENSOR_PH_A 166 -#define SENSOR_PH_B 167 -#define SENSOR_PH_C 168 -#define SENSOR_ORP_A 169 -#define SENSOR_ORP_B 170 -#define SENSOR_ORP_C 171 - // define MACROS in order to manage bits inside Bytes #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) @@ -806,7 +63,7 @@ /*! \def MAX_FRAME \brief maximum size in bytes of the frame */ -#define MAX_FRAME 150 +#define MAX_FRAME 255 @@ -843,26 +100,38 @@ /*! \def SERVICE2_FRAME \brief */ -#define EXAMPLE_FRAME 0 -#define TIMEOUT_FRAME 1 -#define EVENT_FRAME 2 -#define ALARM_FRAME 3 -#define SERVICE1_FRAME 4 -#define SERVICE2_FRAME 5 -#define SET_TIME_FRAME 6 +#define INFORMATION_FRAME_V12 0 +#define TIMEOUT_FRAME 1 +#define EVENT_FRAME 2 +#define ALARM_FRAME 3 +#define SERVICE1_FRAME 4 +#define SERVICE2_FRAME 5 +#define INFORMATION_FRAME_V15 6 -/*! \def AES128_ECB_FRAME - \brief Encrypted frame using AES-128 key size and ECB mode +/*! \def AES128_ECB_FRAME_V12 + \brief Encrypted frame using AES-128 key size and ECB mode (Waspmote v12) + */ +/*! \def AES192_ECB_FRAME_V12 + \brief Encrypted frame using AES-192 key size and ECB mode (Waspmote v12) */ -/*! \def AES192_ECB_FRAME - \brief Encrypted frame using AES-192 key size and ECB mode +/*! \def AES256_ECB_FRAME_V12 + \brief Encrypted frame using AES-256 key size and ECB mode (Waspmote v12) */ -/*! \def AES256_ECB_FRAME - \brief Encrypted frame using AES-256 key size and ECB mode +/*! \def AES128_ECB_FRAME_V15 + \brief Encrypted frame using AES-128 key size and ECB mode (Waspmote v15) */ -#define AES128_ECB_FRAME 97 -#define AES192_ECB_FRAME 98 -#define AES256_ECB_FRAME 99 +/*! \def AES192_ECB_FRAME_V15 + \brief Encrypted frame using AES-192 key size and ECB mode (Waspmote v15) + */ +/*! \def AES256_ECB_FRAME_V15 + \brief Encrypted frame using AES-256 key size and ECB mode (Waspmote v15) + */ +#define AES128_ECB_FRAME_V15 94 +#define AES192_ECB_FRAME_V15 95 +#define AES256_ECB_FRAME_V15 96 +#define AES128_ECB_FRAME_V12 97 +#define AES192_ECB_FRAME_V12 98 +#define AES256_ECB_FRAME_V12 99 @@ -901,9 +170,7 @@ //! Variable : Waspmote serial id -/*! -*/ -extern volatile unsigned long _serial_id; +extern volatile uint8_t _serial_id[8]; /****************************************************************************** @@ -1011,7 +278,7 @@ class WaspFrame /*! This function gets the frame maximum size \return uint8_t indicating the value of _maxSize */ - uint8_t getFrameSize( void ); + uint16_t getFrameSize( void ); //! Function : creates a new frame /*! This function creates a new ASCII frame getting the mote ID from the @@ -1056,6 +323,7 @@ class WaspFrame void showFrame(void); int8_t addSensor(uint8_t type, int value); + int8_t addSensor(uint8_t type, uint16_t value); int8_t addSensor(uint8_t type, unsigned long value); int8_t addSensor(uint8_t type, double value); int8_t addSensor(uint8_t type, double value, int N); diff --git a/libraries/Frame/WaspFrameConstants.h b/libraries/Frame/WaspFrameConstantsv12.h similarity index 64% rename from libraries/Frame/WaspFrameConstants.h rename to libraries/Frame/WaspFrameConstantsv12.h index 54a6c7c..b194858 100644 --- a/libraries/Frame/WaspFrameConstants.h +++ b/libraries/Frame/WaspFrameConstantsv12.h @@ -1,7 +1,7 @@ /*! \file WaspFrameConstants.h - \brief Header file for Waspmote Frame Constants + \brief Header file for Waspmote v12 Frame Constants - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.5 + Version: 3.0 Design: David Gascón Implementation: Yuri Carmona, Javier Siscart, Joaquín Ruiz, Alejandro Gallego @@ -31,6 +31,760 @@ #include +//////////////////////////////////////////////////////////////////////////////// +// Waspmote v12 FRAME definitions +//////////////////////////////////////////////////////////////////////////////// + + +/// Gases Board sensor measurements + +/*! \def SENSOR_CO + \brief Carbon Monoxide measurement type + */ +/*! \def SENSOR_CO2 + \brief Carbon Dioxide measurement type + */ +/*! \def SENSOR_O2 + \brief Oxygen measurement type + */ +/*! \def SENSOR_CH4 + \brief Methane measurement type + */ +/*! \def SENSOR_LPG + \brief Liquefied Pretoleum Gases measurement type + */ +/*! \def SENSOR_NH3 + \brief Ammonia measurement type + */ +/*! \def SENSOR_AP1 + \brief Air Pollutans 1 measurement type + */ +/*! \def SENSOR_AP2 + \brief Air Pollutans 2 measurement type + */ +/*! \def SENSOR_SV + \brief Solvent Vapors measurement type + */ +/*! \def SENSOR_NO2 + \brief Nitrogen Dioxide measurement type + */ +/*! \def SENSOR_O3 + \brief Ozone measurement type + */ +/*! \def SENSOR_VOC + \brief Hydrocarbons measurement type + */ +/*! \def SENSOR_TC + \brief Temperature Celsius measurement type + */ +/*! \def SENSOR_TF + \brief Temperature Fahrenheit measurement type + */ +/*! \def SENSOR_HUM + \brief Humidity measurement type + */ +/*! \def SENSOR_PA + \brief Pressure atmospheric measurement type + */ + + +/// Events Board Sensor measurements + +/*! \def SENSOR_PW + \brief Pressure/Weight measurement type + */ +/*! \def SENSOR_BEND + \brief Bend measurement type + */ +/*! \def SENSOR_VBR + \brief Vibration measurement type + */ +/*! \def SENSOR_HALL + \brief Hall Effect measurement type + */ +/*! \def SENSOR_LP + \brief Liquid Presence measurement type + */ +/*! \def SENSOR_LL + \brief Liquid Level measurement type + */ +/*! \def SENSOR_LUM + \brief Luminosity measurement type + */ +/*! \def SENSOR_PIR + \brief Presence measurement type + */ +/*! \def SENSOR_ST + \brief Stretch measurement type + */ + + +/// Smart cities sensor measurements + +/*! \def SENSOR_MCP + \brief Microphone measurement type + */ +/*! \def SENSOR_CDG + \brief Crack detection gauge measurement type + */ +/*! \def SENSOR_CPG + \brief Crack propagation gauge measurement type + */ +/*! \def SENSOR_LD + \brief Linear Displacement measurement type + */ +/*! \def SENSOR_DUST + \brief Dust measurement type + */ +/*! \def SENSOR_US + \brief Ultrasound measurement type + */ + + +/// Smart parking sensor measurements + +/*! \def SENSOR_MF + \brief Magnetic Field measurement type + */ +/*! \def SENSOR_PS + \brief Parking Spot Status measurement type + */ + +/// Agriculture sensor measurements + +/*! \def SENSOR_AIR + \brief Air Temperature / Humidity measurement type + */ +/*! \def SENSOR_SOIL + \brief Soil Temperature / Moisture measurement type + */ +/*! \def SENSOR_LW + \brief Leaf Wetness measurement type + */ +/*! \def SENSOR_PAR + \brief Solar Radiation measurement type + */ +/*! \def SENSOR_UV + \brief Ultraviolet Radiation measurement type + */ +/*! \def SENSOR_TD + \brief Trunk Diameter measurement type + */ +/*! \def SENSOR_SD + \brief Stem Diameter measurement type + */ +/*! \def SENSOR_FD + \brief Fruit Diameter measurement type + */ +/*! \def SENSOR_ANE + \brief Anemometer measurement type + */ +/*! \def SENSOR_WV + \brief Wind Vane measurement type + */ +/*! \def SENSOR_PLV + \brief Pluviometer measurement type + */ + + +/// Radiation sensor measurements + +/*! \def SENSOR_RAD + \brief Geiger tube measurement type + */ + + +/// Smart Metering sensor measurements + +/*! \def SENSOR_CU + \brief Current measurement type + */ +/*! \def SENSOR_WF + \brief Water flow measurement type + */ +/*! \def SENSOR_LC + \brief Load cell measurement type + */ +/*! \def SENSOR_DF + \brief Distance foil measurement type + */ + + +/// Additional sensor measurements + +/*! \def SENSOR_BAT + \brief Battery measurement type + */ +/*! \def SENSOR_GPS + \brief Global Positioning System measurement type + */ +/*! \def SENSOR_RSSI + \brief RSSI measurement type + */ +/*! \def SENSOR_MAC + \brief MAC Address measurement type + */ +/*! \def SENSOR_NA + \brief Network Address measurement type + */ +/*! \def SENSOR_NID + \brief Network Identifier origin measurement type + */ +/*! \def SENSOR_DATE + \brief Date measurement type + */ +/*! \def SENSOR_TIME + \brief Time measurement type + */ +/*! \def SENSOR_GMT + \brief GMT measurement type + */ +/*! \def SENSOR_RAM + \brief RAM measurement type + */ +/*! \def SENSOR_IN_TEMP + \brief Internal temperature measurement type + */ +/*! \def SENSOR_MILLIS + \brief Millis measurement type + */ + +/// Special sensor measurements + +/*! \def SENSOR_STR + \brief String type + */ + +/// Smart Water + +/*! \def SENSOR_PH + \brief pH measurement type + */ +/*! \def SENSOR_ORP + \brief Oxidation Reduction Potential measurement type + */ +/*! \def SENSOR_DI + \brief Disolved Ion measurement type + */ +/*! \def SENSOR_DO + \brief Disolved Oxygen measurement type + */ +/*! \def SENSOR_COND + \brief Conductivity measurement type + */ +/*! \def SENSOR_WT + \brief Water Temperature measurement type + */ + + +/// Smart Libelium +/*! \def SENSOR_DM_ST + \brief XBee Digimesh awake time for cyclic sleep mode + */ +/*! \def SENSOR_DM_SP + \brief XBee Digimesh asleep time for cyclic sleep mode + */ +/*! \def SENSOR_TX_PWR + \brief XBee transmision power + */ +/*! \def SENSOR_LUX + \brief Luxes measurement type + */ + + +/// GPS +/*! \def SENSOR_SPEED + \brief GPS speed over the ground measurement type + */ +/*! \def SENSOR_COURSE + \brief GPS course over the ground measurement type + */ +/*! \def SENSOR_ALTITUDE + \brief GPS altitude over the ground measurement type + */ +/*! \def SENSOR_HDOP + \brief GPS HDOP over the ground measurement type + */ +/*! \def SENSOR_VDOP + \brief GPS VDOP over the ground measurement type + */ +/*! \def SENSOR_PDOP + \brief GPS PDOP over the ground measurement type + */ + + +/// State Machine +/*! \def SENSOR_FSM + \brief Finite State Machine (FSM) value + */ + + +/// New pluviometer values +/*! \def SENSOR_PLV1 + \brief pluviomter value for current hour + */ + /*! \def SENSOR_PLV2 + \brief pluviomter value for previous hour + */ + /*! \def SENSOR_PLV3 + \brief pluviomter value for last 24h + */ + +/// P&S watermarks +/*! \def SENSOR_SOIL_C + \brief watermark value for P&S connector C + */ + /*! \def SENSOR_SOIL_D + \brief watermark value for P&S connector D + */ + /*! \def SENSOR_SOIL_E + \brief watermark value for P&S connector E + */ + /*! \def SENSOR_SOIL_F + \brief watermark value for P&S connector F + */ + +/// Waspmote OEM watermarks +/*! \def SENSOR_SOIL1 + \brief Agriculture Board watermark1 + */ + /*! \def SENSOR_SOIL2 + \brief Agriculture Board watermark2 + */ + /*! \def SENSOR_SOIL3 + \brief Agriculture Board watermark3 + */ + + /// DS18B20 + /*! \def SENSOR_TCC + \brief DS18B20 temperature sensor + */ + + /// P&S Ultrasound depending on socket voltage ref + /*! \def SENSOR_US_3V3 + \brief WRA1 Ultrasound sensor powered at 3V3 + */ +/*! \def SENSOR_US_5V + \brief WRA1 Ultrasound sensor powered at 5V + */ + + +/// P&S Security sensors depending on socket (Security - Events board) + /*! \def SENSOR_LUM_D + \brief LDR sensor in socket D + */ +/*! \def SENSOR_LUM_E + \brief LDR sensor in socket E + */ + /*! \def SENSOR_LUM_F + \brief LDR sensor in socket F + */ + /*! \def SENSOR_LP_D + \brief Liquid Presence sensor in socket D + */ + /*! \def SENSOR_LP_E + \brief Liquid Presence sensor in socket E + */ + /*! \def SENSOR_LP_F + \brief Liquid Presence sensor in socket F + */ + /*! \def SENSOR_LL_D + \brief Liquid Level sensor in socketD + */ + /*! \def SENSOR_LL_E + \brief Liquid Level sensor in socketE + */ + /*! \def SENSOR_LL_F + \brief Liquid Level sensor in socketF + */ + /*! \def SENSOR_HALL_D + \brief Hall Effect sensor in socket D + */ + /*! \def SENSOR_HALL_E + \brief Hall Effect sensor in socket E + */ + /*! \def SENSOR_HALL_F + \brief Hall Effect sensor in socket F + */ + +/// P&S liquid flow sensor depending on socket (Smart Metering) +/*! \def SENSOR_WF_C + \brief Liquid Flow sensor in socket C + */ +/*! \def SENSOR_WF_E + \brief Liquid Flow sensor in socket E + */ + +/// Unix/Epoch timestamp +/*! \def SENSOR_TST + \brief Unix (aka Epoch) timestamp value + */ + +/// Turbidity sensor +/*! \def SENSOR_TURB + \brief Turbidity sensor + */ + + +/// Version parameters +/*! \def SENSOR_VAPI + \brief API version + */ +/*! \def SENSOR_VPROG + \brief Program version + */ +/*! \def SENSOR_VBOOT + \brief Bootloader version + */ + + +/// Gases PRO +/*! \def SENSOR_GP_CL2 + \brief Chlorine measurement type + */ +/*! \def SENSOR_GP_CO + \brief Carbon Monoxide measurement type + */ +/*! \def SENSOR_GP_ETO + \brief Ethylene Oxide measurement type + */ +/*! \def SENSOR_GP_H2 + \brief Hydrogen measurement type + */ +/*! \def SENSOR_GP_H2S + \brief Hydrogen Sulphide measurement type + */ +/*! \def SENSOR_GP_HCL + \brief Hydrogen Chloride measurement type + */ +/*! \def SENSOR_GP_HCN + \brief Hydrogen Cyanide measurement type + */ +/*! \def SENSOR_GP_NH3 + \brief Ammonia measurement type + */ +/*! \def SENSOR_GP_NO + \brief Nitrogen Monoxide measurement type + */ +/*! \def SENSOR_GP_NO2 + \brief Nitrogen Dioxide measurement type + */ +/*! \def SENSOR_GP_O2 + \brief Oxygen measurement type + */ +/*! \def SENSOR_GP_PH3 + \brief Phospine measurement type + */ +/*! \def SENSOR_GP_SO2 + \brief Sulfur Dioxide measurement type + */ +/*! \def SENSOR_GP_CH4 + \brief Methane and other combustible gases measurement type + */ +/*! \def SENSOR_GP_O3 + \brief Ozone measurement type + */ +/*! \def SENSOR_GP_CO2 + \brief Carbon Dioxide measurement type + */ +/*! \def SENSOR_GP_TC + \brief Temperature Celsius measurement type + */ +/*! \def SENSOR_GP_TF + \brief Temperature Fahrenheit measurement type + */ +/*! \def SENSOR_GP_HUM + \brief Humidity measurement type + */ +/*! \def SENSOR_GP_PRES + \brief Pressure measurement type + */ +/*! \def SENSOR_OPC_TC + \brief Temperature Celsius measurement type + */ +/*! \def SENSOR_OPC_TF + \brief Temperature Fahrenheit measurement type + */ +/*! \def SENSOR_OPC_PM1 + \brief PM1 measurement type + */ +/*! \def SENSOR_OPC_PM2_5 + \brief PM2.5 measurement type + */ +/*! \def SENSOR_OPC_PM10 + \brief PM10 measurement type + */ +/*! \def SENSOR_OPC_PART + \brief Particle bin counter measurement type + */ +/*! \def SENSOR_SWI_CA + \brief Calcium ion measurement type + */ +/*! \def SENSOR_SWI_FL + \brief Fluoride ion measurement type + */ +/*! \def SENSOR_SWI_BF + \brief Tetrafluoroborate ion measurement type + */ +/*! \def SENSOR_SWI_NO + \brief Nitrates ion measurement type + */ +/*! \def SENSOR_SWI_BR + \brief Bromide ion measurement type + */ +/*! \def SENSOR_SWI_CL + \brief Chlorideion measurement type + */ +/*! \def SENSOR_SWI_CU + \brief Cupric ion measurement type + */ +/*! \def SENSOR_SWI_IO + \brief Iodide ion measurement type + */ +/*! \def SENSOR_SWI_PB + \brief Lead ion measurement type + */ +/*! \def SENSOR_SWI_AG + \brief Silver ion measurement type + */ +/*! \def SENSOR_SWI_PH + \brief pH (for Smart Water Ions) measurement type + */ + + +// Gases v20 +#define SENSOR_CO 0 +#define SENSOR_CO2 1 +#define SENSOR_O2 2 +#define SENSOR_CH4 3 +#define SENSOR_LPG 4 +#define SENSOR_NH3 5 +#define SENSOR_AP1 6 +#define SENSOR_AP2 7 +#define SENSOR_SV 8 +#define SENSOR_NO2 9 +#define SENSOR_O3 10 +#define SENSOR_VOC 11 +#define SENSOR_TCA 12 +#define SENSOR_TFA 13 +#define SENSOR_HUMA 14 +#define SENSOR_PA 15 + +// Events v20 +#define SENSOR_PW 16 +#define SENSOR_BEND 17 +#define SENSOR_VBR 18 +#define SENSOR_HALL 19 +#define SENSOR_LP 20 +#define SENSOR_LL 21 +#define SENSOR_LUM 22 +#define SENSOR_PIR 23 +#define SENSOR_ST 24 + +// Smart Cities +#define SENSOR_MCP 25 +#define SENSOR_CDG 26 +#define SENSOR_CPG 27 +#define SENSOR_LD 28 +#define SENSOR_DUST 29 +#define SENSOR_US 30 + +// Smart parking +#define SENSOR_MF 31 +#define SENSOR_PS 32 + +// Agriculture +#define SENSOR_TCB 33 +#define SENSOR_TFB 34 +#define SENSOR_HUMB 35 +#define SENSOR_SOILT 36 +#define SENSOR_SOIL 37 +#define SENSOR_LW 38 +#define SENSOR_PAR 39 +#define SENSOR_UV 40 +#define SENSOR_TD 41 +#define SENSOR_SD 42 +#define SENSOR_FD 43 +#define SENSOR_ANE 44 +#define SENSOR_WV 45 +#define SENSOR_PLV 46 + +// Radiation +#define SENSOR_RAD 47 + +// Smart metering +#define SENSOR_CU 48 +#define SENSOR_WF 49 +#define SENSOR_LC 50 +#define SENSOR_DF 51 + +// Additional +#define SENSOR_BAT 52 +#define SENSOR_GPS 53 +#define SENSOR_RSSI 54 +#define SENSOR_MAC 55 +#define SENSOR_NA 56 +#define SENSOR_NID 57 +#define SENSOR_DATE 58 +#define SENSOR_TIME 59 +#define SENSOR_GMT 60 +#define SENSOR_RAM 61 +#define SENSOR_IN_TEMP 62 +#define SENSOR_ACC 63 +#define SENSOR_MILLIS 64 + +// Special +#define SENSOR_STR 65 + +// Meshlium +#define SENSOR_MBT 66 +#define SENSOR_MWIFI 67 + +// RFID +#define SENSOR_UID 68 +#define SENSOR_RB 69 + +// Smart Water +#define SENSOR_PH 70 +#define SENSOR_ORP 71 +#define SENSOR_DO 72 +#define SENSOR_COND 73 +#define SENSOR_WT 74 +#define SENSOR_DINA 75 +#define SENSOR_DICA 76 +#define SENSOR_DIF 77 +#define SENSOR_DICL 78 +#define SENSOR_DIBR 79 +#define SENSOR_DII 80 +#define SENSOR_DICU2 81 +#define SENSOR_DIK 82 +#define SENSOR_DIMG2 83 +#define SENSOR_DINO3 84 + +// Smart Libelium +#define SENSOR_TX_PWR 85 +#define SENSOR_DM_ST 86 +#define SENSOR_DM_SP 87 +#define SENSOR_LUX 88 + +// GPS +#define SENSOR_SPEED 89 +#define SENSOR_COURSE 90 +#define SENSOR_ALTITUDE 91 +#define SENSOR_HDOP 92 +#define SENSOR_VDOP 93 +#define SENSOR_PDOP 94 + +// Finite State Machine status +#define SENSOR_FSM 95 + +// New pluviometer values +#define SENSOR_PLV1 96 +#define SENSOR_PLV2 97 +#define SENSOR_PLV3 98 + +// P&S watermark sensors (Smart Agriculture) +#define SENSOR_SOIL_C 99 +#define SENSOR_SOIL_D 100 +#define SENSOR_SOIL_E 101 +#define SENSOR_SOIL_F 102 + +// Waspmote OEM watermark sensors +#define SENSOR_SOIL1 103 +#define SENSOR_SOIL2 104 +#define SENSOR_SOIL3 105 + +// DS18B20 +#define SENSOR_TCC 106 + +// P&S Ultrasound depending on socket voltage ref (Smart Cities & Smart Metering) +#define SENSOR_US_3V3 107 +#define SENSOR_US_5V 108 + +// P&S Security sensors depending on socket (Smart Security) +#define SENSOR_LUM_D 109 +#define SENSOR_LUM_E 110 +#define SENSOR_LUM_F 111 +#define SENSOR_LP_D 112 +#define SENSOR_LP_E 113 +#define SENSOR_LP_F 114 +#define SENSOR_LL_D 115 +#define SENSOR_LL_E 116 +#define SENSOR_LL_F 117 +#define SENSOR_HALL_D 118 +#define SENSOR_HALL_E 119 +#define SENSOR_HALL_F 120 + +// P&S liquid flow sensor depending on socket (Smart Metering) +#define SENSOR_WF_C 121 +#define SENSOR_WF_E 122 + +// Unix/Epoch timestamp +#define SENSOR_TST 123 + +// Turbidity sensor +#define SENSOR_TURB 124 + +// Version parameters +#define SENSOR_VAPI 125 +#define SENSOR_VPROG 126 +#define SENSOR_VBOOT 127 + + +// Gases PRO +#define SENSOR_GP_CL2 128 +#define SENSOR_GP_CO 129 +#define SENSOR_GP_ETO 130 +#define SENSOR_GP_H2 131 +#define SENSOR_GP_H2S 132 +#define SENSOR_GP_HCL 133 +#define SENSOR_GP_HCN 134 +#define SENSOR_GP_NH3 135 +#define SENSOR_GP_NO 136 +#define SENSOR_GP_NO2 137 +#define SENSOR_GP_O2 138 +#define SENSOR_GP_PH3 139 +#define SENSOR_GP_SO2 140 +#define SENSOR_GP_CH4 141 +#define SENSOR_GP_O3 142 +#define SENSOR_GP_CO2 143 +#define SENSOR_GP_TC 144 +#define SENSOR_GP_TF 145 +#define SENSOR_GP_HUM 146 +#define SENSOR_GP_PRES 147 + +// OPCN2 Dust Sensor +#define SENSOR_OPC_TC 148 +#define SENSOR_OPC_TF 149 +#define SENSOR_OPC_P 150 +#define SENSOR_OPC_PM1 151 +#define SENSOR_OPC_PM2_5 152 +#define SENSOR_OPC_PM10 153 +#define SENSOR_OPC_PART 154 + +// Smart Water Ions +#define SENSOR_SWI_CA 155 +#define SENSOR_SWI_FL 156 +#define SENSOR_SWI_FB 157 +#define SENSOR_SWI_NO 158 +#define SENSOR_SWI_BR 159 +#define SENSOR_SWI_CL 160 +#define SENSOR_SWI_CU 161 +#define SENSOR_SWI_IO 162 +#define SENSOR_SWI_PB 163 +#define SENSOR_SWI_AG 164 +#define SENSOR_SWI_PH 165 + +// P&S Smart Water sensors depending on socket (Smart Water) +#define SENSOR_PH_A 166 +#define SENSOR_PH_B 167 +#define SENSOR_PH_C 168 +#define SENSOR_ORP_A 169 +#define SENSOR_ORP_B 170 +#define SENSOR_ORP_C 171 + + + /// Flash defines ////////////////////////////////////////////////////////////// @@ -244,13 +998,13 @@ const char str_GP_HUM[] PROGMEM = "GP_HUM"; // 146 const char str_GP_PRES[] PROGMEM = "GP_PRES"; // 147 // OPCN2 Dust Sensor -const char str_OPC_tc[] PROGMEM = "TC"; // 148 -const char str_OPC_tf[] PROGMEM = "TF"; // 149 -const char str_OPC_p[] PROGMEM = "P"; // 150 -const char str_OPC_pm1[] PROGMEM = "PM1"; // 151 -const char str_OPC_pm2_5[] PROGMEM = "PM2_5"; // 152 -const char str_OPC_pm10[] PROGMEM = "PM10"; // 153 -const char str_OPC_part[] PROGMEM = "PART"; // 154 +const char str_OPC_tc[] PROGMEM = "OPC_TC"; // 148 +const char str_OPC_tf[] PROGMEM = "OPC_TF"; // 149 +const char str_OPC_p[] PROGMEM = "OPC_P"; // 150 +const char str_OPC_pm1[] PROGMEM = "OPC_PM1"; // 151 +const char str_OPC_pm2_5[] PROGMEM = "OPC_PM2_5"; // 152 +const char str_OPC_pm10[] PROGMEM = "OPC_PM10"; // 153 +const char str_OPC_part[] PROGMEM = "OPC_PART"; // 154 // Smart Water Ions const char str_SWI_CA[] PROGMEM = "SWICA"; // 155 diff --git a/libraries/Frame/WaspFrameConstantsv15.h b/libraries/Frame/WaspFrameConstantsv15.h new file mode 100644 index 0000000..9b9bf38 --- /dev/null +++ b/libraries/Frame/WaspFrameConstantsv15.h @@ -0,0 +1,1300 @@ +/*! \file WaspFrameConstantsv15.h + \brief Header file for Waspmote v15 Frame Constants + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.1 + Design: David Gascón + Implementation: Yuri Carmona, Javier Siscart, Joaquín Ruiz, Alejandro Gallego + +*/ + + +#ifndef WaspFrameconstantsv15_h +#define WaspFrameconstantsv15_h + + +#include + + + +//////////////////////////////////////////////////////////////////////////////// +// Waspmote v15 FRAME definitions +//////////////////////////////////////////////////////////////////////////////// + + +// Gases v30 +#define SENSOR_GASES_CO 0 +#define SENSOR_GASES_CO2 1 +#define SENSOR_GASES_O2 2 +#define SENSOR_GASES_CH4 3 +#define SENSOR_GASES_O3 4 +#define SENSOR_GASES_NH3 5 +#define SENSOR_GASES_NO2 6 +#define SENSOR_GASES_LPG 7 +#define SENSOR_GASES_AP1 8 +#define SENSOR_GASES_AP2 9 +#define SENSOR_GASES_SV 10 +#define SENSOR_GASES_VOC 11 +#define SENSOR_GASES_TC 74 +#define SENSOR_GASES_TF 75 +#define SENSOR_GASES_HUM 76 +#define SENSOR_GASES_PRES 77 +#define SENSOR_GASES_LUXES 78 +#define SENSOR_GASES_US 79 + +// Gases PRO v30 +#define SENSOR_GASES_PRO_CO 0 +#define SENSOR_GASES_PRO_CO2 1 +#define SENSOR_GASES_PRO_O2 2 +#define SENSOR_GASES_PRO_CH4 3 +#define SENSOR_GASES_PRO_O3 4 +#define SENSOR_GASES_PRO_NH3 5 +#define SENSOR_GASES_PRO_NO2 6 +#define SENSOR_GASES_PRO_NO 12 +#define SENSOR_GASES_PRO_CL2 13 +#define SENSOR_GASES_PRO_ETO 14 +#define SENSOR_GASES_PRO_H2 15 +#define SENSOR_GASES_PRO_H2S 16 +#define SENSOR_GASES_PRO_HCL 17 +#define SENSOR_GASES_PRO_HCN 18 +#define SENSOR_GASES_PRO_PH3 19 +#define SENSOR_GASES_PRO_SO2 20 +#define SENSOR_GASES_PRO_SOCKET_A 30 +#define SENSOR_GASES_PRO_SOCKET_B 31 +#define SENSOR_GASES_PRO_SOCKET_C 32 +#define SENSOR_GASES_PRO_SOCKET_F 35 +#define SENSOR_GASES_PRO_PM1 70 +#define SENSOR_GASES_PRO_PM2_5 71 +#define SENSOR_GASES_PRO_PM10 72 +#define SENSOR_GASES_PRO_PART 73 +#define SENSOR_GASES_PRO_TC 74 +#define SENSOR_GASES_PRO_TF 75 +#define SENSOR_GASES_PRO_HUM 76 +#define SENSOR_GASES_PRO_PRES 77 +#define SENSOR_GASES_PRO_LUXES 78 +#define SENSOR_GASES_PRO_US 79 + +// Events v30 +#define SENSOR_EVENTS_WF 40 +#define SENSOR_EVENTS_PIR 41 +#define SENSOR_EVENTS_LP 42 +#define SENSOR_EVENTS_LL 43 +#define SENSOR_EVENTS_HALL 44 +#define SENSOR_EVENTS_RELAY_IN 45 +#define SENSOR_EVENTS_RELAY_OUT 46 +#define SENSOR_EVENTS_SOCKET_A 47 +#define SENSOR_EVENTS_SOCKET_C 48 +#define SENSOR_EVENTS_SOCKET_D 49 +#define SENSOR_EVENTS_SOCKET_E 50 +#define SENSOR_EVENTS_TC 74 +#define SENSOR_EVENTS_TF 75 +#define SENSOR_EVENTS_HUM 76 +#define SENSOR_EVENTS_PRES 77 +#define SENSOR_EVENTS_LUXES 78 +#define SENSOR_EVENTS_US 79 + + +// Cities PRO v30 +#define SENSOR_CITIES_PRO_CO 0 +#define SENSOR_CITIES_PRO_CO2 1 +#define SENSOR_CITIES_PRO_O2 2 +#define SENSOR_CITIES_PRO_CH4 3 +#define SENSOR_CITIES_PRO_O3 4 +#define SENSOR_CITIES_PRO_NH3 5 +#define SENSOR_CITIES_PRO_NO2 6 +#define SENSOR_CITIES_PRO_NO 12 +#define SENSOR_CITIES_PRO_CL2 13 +#define SENSOR_CITIES_PRO_ETO 14 +#define SENSOR_CITIES_PRO_H2 15 +#define SENSOR_CITIES_PRO_H2S 16 +#define SENSOR_CITIES_PRO_HCL 17 +#define SENSOR_CITIES_PRO_HCN 18 +#define SENSOR_CITIES_PRO_PH3 19 +#define SENSOR_CITIES_PRO_SO2 20 +#define SENSOR_CITIES_PRO_NOISE 21 +#define SENSOR_CITIES_PRO_SOCKET_A 30 +#define SENSOR_CITIES_PRO_SOCKET_B 31 +#define SENSOR_CITIES_PRO_SOCKET_C 32 +#define SENSOR_CITIES_PRO_SOCKET_F 35 +#define SENSOR_CITIES_PRO_PM1 70 +#define SENSOR_CITIES_PRO_PM2_5 71 +#define SENSOR_CITIES_PRO_PM10 72 +#define SENSOR_CITIES_PRO_PART 73 +#define SENSOR_CITIES_PRO_TC 74 +#define SENSOR_CITIES_PRO_TF 75 +#define SENSOR_CITIES_PRO_HUM 76 +#define SENSOR_CITIES_PRO_PRES 77 +#define SENSOR_CITIES_PRO_LUXES 78 +#define SENSOR_CITIES_PRO_US 79 + + +// Smart Water Ions v30 +#define SENSOR_IONS_CA 100 +#define SENSOR_IONS_FL 101 +#define SENSOR_IONS_FB 102 +#define SENSOR_IONS_NO3 103 +#define SENSOR_IONS_BR 104 +#define SENSOR_IONS_CL 105 +#define SENSOR_IONS_CU 106 +#define SENSOR_IONS_IO 107 +#define SENSOR_IONS_NH4 108 +#define SENSOR_IONS_AG 109 +#define SENSOR_IONS_PH 110 +#define SENSOR_IONS_LI 111 +#define SENSOR_IONS_MG 112 +#define SENSOR_IONS_NO2 113 +#define SENSOR_IONS_CLO4 114 +#define SENSOR_IONS_K 115 +#define SENSOR_IONS_NA 116 +#define SENSOR_IONS_SOCKET_A 117 +#define SENSOR_IONS_SOCKET_B 118 +#define SENSOR_IONS_SOCKET_C 119 +#define SENSOR_IONS_SOCKET_D 120 +#define SENSOR_IONS_WT 134 + +// Parking +#define SENSOR_PARKING 128 + +// Radiation +#define SENSOR_RADIATION 129 + + +// Smart Water v30 +#define SENSOR_WATER_PH 130 +#define SENSOR_WATER_ORP 131 +#define SENSOR_WATER_DO 132 +#define SENSOR_WATER_COND 133 +#define SENSOR_WATER_WT 134 +#define SENSOR_WATER_TURB 135 +#define SENSOR_WATER_PH_ 136 +#define SENSOR_WATER_PH_D 137 +#define SENSOR_WATER_ORP_A 138 +#define SENSOR_WATER_ORP_D 139 + + +// Smart Agriculture v30 +#define SENSOR_AGR_SOIL1 150 +#define SENSOR_AGR_SOIL2 151 +#define SENSOR_AGR_SOIL3 152 +#define SENSOR_AGR_SOILTC 153 +#define SENSOR_AGR_SOILTF 154 +#define SENSOR_AGR_LW 155 +#define SENSOR_AGR_ANE 156 +#define SENSOR_AGR_WV 157 +#define SENSOR_AGR_PLV1 158 +#define SENSOR_AGR_PLV2 159 +#define SENSOR_AGR_PLV3 160 +#define SENSOR_AGR_PAR 161 +#define SENSOR_AGR_UV 162 +#define SENSOR_AGR_TD 163 +#define SENSOR_AGR_SD 164 +#define SENSOR_AGR_FD 165 +#define SENSOR_AGR_SOIL_B 166 +#define SENSOR_AGR_SOIL_C 167 +#define SENSOR_AGR_SOIL_E 168 +#define SENSOR_AGR_TC 74 +#define SENSOR_AGR_TF 75 +#define SENSOR_AGR_HUM 76 +#define SENSOR_AGR_PRES 77 +#define SENSOR_AGR_LUXES 78 +#define SENSOR_AGR_US 79 + + +// Ambient Control v30 +#define SENSOR_AMBIENT_TCB 170 +#define SENSOR_AMBIENT_HUMB 171 +#define SENSOR_AMBIENT_LUM 172 +#define SENSOR_AMBIENT_TC 74 +#define SENSOR_AMBIENT_TF 75 +#define SENSOR_AMBIENT_HUM 76 +#define SENSOR_AMBIENT_PRES 77 +#define SENSOR_AMBIENT_LUXES 78 + + +// Common sensors +#define SENSOR_DUST_PM1 70 +#define SENSOR_DUST_PM2_5 71 +#define SENSOR_DUST_PM10 72 +#define SENSOR_DUST_PART 73 +#define SENSOR_BME_TC 74 +#define SENSOR_BME_TF 75 +#define SENSOR_BME_HUM 76 +#define SENSOR_BME_PRES 77 +#define SENSOR_LUXES 78 +#define SENSOR_ULTRASOUND 79 + + + + + + +/// Flash defines ////////////////////////////////////////////////////////////// + + +/******************************************************************************* + * The following Flash strings, define the tags for all Waspmote sensors. + * These TAGs are used in ASCII frames in order to indicate every sensor field + * that has been included inside the frame. + * + ******************************************************************************/ + +// Gases v30 +const char str_frame_00[] PROGMEM = "CO"; +const char str_frame_01[] PROGMEM = "CO2"; +const char str_frame_02[] PROGMEM = "O2"; +const char str_frame_03[] PROGMEM = "CH4"; +const char str_frame_04[] PROGMEM = "O3"; +const char str_frame_05[] PROGMEM = "NH3"; +const char str_frame_06[] PROGMEM = "NO2"; +const char str_frame_07[] PROGMEM = "LPG"; +const char str_frame_08[] PROGMEM = "AP1"; +const char str_frame_09[] PROGMEM = "AP2"; +const char str_frame_10[] PROGMEM = "SV"; +const char str_frame_11[] PROGMEM = "VOC"; + + +// Gases PRO v30 +const char str_frame_12[] PROGMEM = "NO"; +const char str_frame_13[] PROGMEM = "CL2"; +const char str_frame_14[] PROGMEM = "ETO"; +const char str_frame_15[] PROGMEM = "H2"; +const char str_frame_16[] PROGMEM = "H2S"; +const char str_frame_17[] PROGMEM = "HCL"; +const char str_frame_18[] PROGMEM = "HCN"; +const char str_frame_19[] PROGMEM = "PH3"; +const char str_frame_20[] PROGMEM = "SO2"; + + +// Cities PRO v30 +const char str_frame_21[] PROGMEM = "NOISE"; + + +// Reserved +const char str_frame_22[] PROGMEM = ""; +const char str_frame_23[] PROGMEM = ""; +const char str_frame_24[] PROGMEM = ""; +const char str_frame_25[] PROGMEM = ""; +const char str_frame_26[] PROGMEM = ""; +const char str_frame_27[] PROGMEM = ""; +const char str_frame_28[] PROGMEM = ""; +const char str_frame_29[] PROGMEM = ""; + +// Gases PRO v30 (P&S) +const char str_frame_30[] PROGMEM = "GP_A"; +const char str_frame_31[] PROGMEM = "GP_B"; +const char str_frame_32[] PROGMEM = "GP_C"; +const char str_frame_33[] PROGMEM = ""; //reserved +const char str_frame_34[] PROGMEM = ""; //reserved +const char str_frame_35[] PROGMEM = "GP_F"; +const char str_frame_36[] PROGMEM = ""; //reserved +const char str_frame_37[] PROGMEM = ""; //reserved +const char str_frame_38[] PROGMEM = ""; //reserved +const char str_frame_39[] PROGMEM = ""; //reserved + + +// Events v30 +const char str_frame_40[] PROGMEM = "WF"; +const char str_frame_41[] PROGMEM = "PIR"; +const char str_frame_42[] PROGMEM = "LP"; +const char str_frame_43[] PROGMEM = "LL"; +const char str_frame_44[] PROGMEM = "HALL"; +const char str_frame_45[] PROGMEM = "RIN"; +const char str_frame_46[] PROGMEM = "ROUT"; +const char str_frame_47[] PROGMEM = "EV_A"; +const char str_frame_48[] PROGMEM = "EV_C"; +const char str_frame_49[] PROGMEM = "EV_D"; +const char str_frame_50[] PROGMEM = "EV_E"; +const char str_frame_51[] PROGMEM = ""; // reserved + + +// Additional +const char str_frame_52[] PROGMEM = "BAT"; +const char str_frame_53[] PROGMEM = "GPS"; +const char str_frame_54[] PROGMEM = "RSSI"; +const char str_frame_55[] PROGMEM = "MAC"; +const char str_frame_56[] PROGMEM = "NA"; +const char str_frame_57[] PROGMEM = "NID"; +const char str_frame_58[] PROGMEM = "DATE"; +const char str_frame_59[] PROGMEM = "TIME"; +const char str_frame_60[] PROGMEM = "GMT"; +const char str_frame_61[] PROGMEM = "RAM"; +const char str_frame_62[] PROGMEM = "IN_TEMP"; // (deprecated for Waspv15) +const char str_frame_63[] PROGMEM = "ACC"; +const char str_frame_64[] PROGMEM = "MILLIS"; +const char str_frame_65[] PROGMEM = "STR"; +const char str_frame_66[] PROGMEM = ""; // reserved +const char str_frame_67[] PROGMEM = ""; // reserved +const char str_frame_68[] PROGMEM = "UID"; +const char str_frame_69[] PROGMEM = "RB"; +const char str_frame_70[] PROGMEM = "PM1"; +const char str_frame_71[] PROGMEM = "PM2_5"; +const char str_frame_72[] PROGMEM = "PM10"; +const char str_frame_73[] PROGMEM = "PART"; +const char str_frame_74[] PROGMEM = "TC"; +const char str_frame_75[] PROGMEM = "TF"; +const char str_frame_76[] PROGMEM = "HUM"; +const char str_frame_77[] PROGMEM = "PRES"; +const char str_frame_78[] PROGMEM = "LUX"; +const char str_frame_79[] PROGMEM = "US"; +const char str_frame_80[] PROGMEM = ""; // reserved +const char str_frame_81[] PROGMEM = ""; // reserved +const char str_frame_82[] PROGMEM = ""; // reserved +const char str_frame_83[] PROGMEM = ""; // reserved +const char str_frame_84[] PROGMEM = ""; // reserved +const char str_frame_85[] PROGMEM = ""; // reserved +const char str_frame_86[] PROGMEM = ""; // reserved +const char str_frame_87[] PROGMEM = ""; // reserved +const char str_frame_88[] PROGMEM = ""; // reserved +const char str_frame_89[] PROGMEM = "SPEED_OG"; +const char str_frame_90[] PROGMEM = "COURSE_OG"; +const char str_frame_91[] PROGMEM = "ALT"; +const char str_frame_92[] PROGMEM = "HDOP"; +const char str_frame_93[] PROGMEM = "VDOP"; +const char str_frame_94[] PROGMEM = "PDOP"; +const char str_frame_95[] PROGMEM = ""; // reserved +const char str_frame_96[] PROGMEM = ""; // reserved +const char str_frame_97[] PROGMEM = ""; // reserved +const char str_frame_98[] PROGMEM = ""; // reserved +const char str_frame_99[] PROGMEM = ""; // reserved + + +// Smart Water Ions v30 +const char str_frame_100[] PROGMEM = "SWICA"; +const char str_frame_101[] PROGMEM = "SWIFL"; +const char str_frame_102[] PROGMEM = "SWIFB"; +const char str_frame_103[] PROGMEM = "SWINO3"; +const char str_frame_104[] PROGMEM = "SWIBR"; +const char str_frame_105[] PROGMEM = "SWICL"; +const char str_frame_106[] PROGMEM = "SWICU"; +const char str_frame_107[] PROGMEM = "SWIIO"; +const char str_frame_108[] PROGMEM = "SWINH4"; +const char str_frame_109[] PROGMEM = "SWIAG"; +const char str_frame_110[] PROGMEM = "SWIPH"; +const char str_frame_111[] PROGMEM = "SWILI"; +const char str_frame_112[] PROGMEM = "SWIMG"; +const char str_frame_113[] PROGMEM = "SWINO2"; +const char str_frame_114[] PROGMEM = "SWICLO4"; +const char str_frame_115[] PROGMEM = "SWIK"; +const char str_frame_116[] PROGMEM = "SWINA"; +const char str_frame_117[] PROGMEM = "SWI_A"; +const char str_frame_118[] PROGMEM = "SWI_B"; +const char str_frame_119[] PROGMEM = "SWI_C"; +const char str_frame_120[] PROGMEM = "SWI_D"; +const char str_frame_121[] PROGMEM = ""; // reserved +const char str_frame_122[] PROGMEM = ""; // reserved + + +// Additional +const char str_frame_123[] PROGMEM = "TST"; +const char str_frame_124[] PROGMEM = ""; // reserved +const char str_frame_125[] PROGMEM = "VAPI"; +const char str_frame_126[] PROGMEM = "VPROG"; +const char str_frame_127[] PROGMEM = "VBOOT"; +const char str_frame_128[] PROGMEM = "PS"; + +// Radiation +const char str_frame_129[] PROGMEM = "RAD"; + + +// Smart Water v30 +const char str_frame_130[] PROGMEM = "PH"; +const char str_frame_131[] PROGMEM = "ORP"; +const char str_frame_132[] PROGMEM = "DO"; +const char str_frame_133[] PROGMEM = "COND"; +const char str_frame_134[] PROGMEM = "WT"; +const char str_frame_135[] PROGMEM = "TURB"; +const char str_frame_136[] PROGMEM = "PH_A"; +const char str_frame_137[] PROGMEM = "PH_D"; +const char str_frame_138[] PROGMEM = "ORP_A"; +const char str_frame_139[] PROGMEM = "ORP_D"; +const char str_frame_140[] PROGMEM = ""; // reserved +const char str_frame_141[] PROGMEM = ""; // reserved +const char str_frame_142[] PROGMEM = ""; // reserved +const char str_frame_143[] PROGMEM = ""; // reserved +const char str_frame_144[] PROGMEM = ""; // reserved +const char str_frame_145[] PROGMEM = ""; // reserved +const char str_frame_146[] PROGMEM = ""; // reserved +const char str_frame_147[] PROGMEM = ""; // reserved +const char str_frame_148[] PROGMEM = ""; // reserved +const char str_frame_149[] PROGMEM = ""; // reserved + + +// Smart Agriculture v30 +const char str_frame_150[] PROGMEM = "SOIL1"; +const char str_frame_151[] PROGMEM = "SOIL2"; +const char str_frame_152[] PROGMEM = "SOIL3"; +const char str_frame_153[] PROGMEM = "SOILTC"; +const char str_frame_154[] PROGMEM = "SOILTF"; +const char str_frame_155[] PROGMEM = "LW"; +const char str_frame_156[] PROGMEM = "ANE"; +const char str_frame_157[] PROGMEM = "WV"; +const char str_frame_158[] PROGMEM = "PLV1"; +const char str_frame_159[] PROGMEM = "PLV2"; +const char str_frame_160[] PROGMEM = "PLV3"; +const char str_frame_161[] PROGMEM = "PAR"; +const char str_frame_162[] PROGMEM = "UV"; +const char str_frame_163[] PROGMEM = "TD"; +const char str_frame_164[] PROGMEM = "SD"; +const char str_frame_165[] PROGMEM = "FD"; +const char str_frame_166[] PROGMEM = "SOIL_B"; +const char str_frame_167[] PROGMEM = "SOIL_C"; +const char str_frame_168[] PROGMEM = "SOIL_E"; +const char str_frame_169[] PROGMEM = ""; // reserved + +// Ambient Control +const char str_frame_170[] PROGMEM = "TCB"; +const char str_frame_171[] PROGMEM = "HUMB"; +const char str_frame_172[] PROGMEM = "LUM"; + + + +/******************************************************************************* + * SENSOR_TABLE - Sensor label table + * + * This table specifies the tag for each sensor. Every tag has been previously + * defined in Flash memory + ******************************************************************************/ +const char* const FRAME_SENSOR_TABLE[] PROGMEM= +{ + // Gases v30 + str_frame_00, + str_frame_01, + str_frame_02, + str_frame_03, + str_frame_04, + str_frame_05, + str_frame_06, + str_frame_07, + str_frame_08, + str_frame_09, + str_frame_10, + str_frame_11, + str_frame_12, + str_frame_13, + str_frame_14, + str_frame_15, + str_frame_16, + str_frame_17, + str_frame_18, + str_frame_19, + str_frame_20, + str_frame_21, + str_frame_22, + str_frame_23, + str_frame_24, + str_frame_25, + str_frame_26, + str_frame_27, + str_frame_28, + str_frame_29, + str_frame_30, + str_frame_31, + str_frame_32, + str_frame_33, + str_frame_34, + str_frame_35, + str_frame_36, + str_frame_37, + str_frame_38, + str_frame_39, + str_frame_40, + str_frame_41, + str_frame_42, + str_frame_43, + str_frame_44, + str_frame_45, + str_frame_46, + str_frame_47, + str_frame_48, + str_frame_49, + str_frame_50, + str_frame_51, + str_frame_52, + str_frame_53, + str_frame_54, + str_frame_55, + str_frame_56, + str_frame_57, + str_frame_58, + str_frame_59, + str_frame_60, + str_frame_61, + str_frame_62, + str_frame_63, + str_frame_64, + str_frame_65, + str_frame_66, + str_frame_67, + str_frame_68, + str_frame_69, + str_frame_70, + str_frame_71, + str_frame_72, + str_frame_73, + str_frame_74, + str_frame_75, + str_frame_76, + str_frame_77, + str_frame_78, + str_frame_79, + str_frame_80, + str_frame_81, + str_frame_82, + str_frame_83, + str_frame_84, + str_frame_85, + str_frame_86, + str_frame_87, + str_frame_88, + str_frame_89, + str_frame_90, + str_frame_91, + str_frame_92, + str_frame_93, + str_frame_94, + str_frame_95, + str_frame_96, + str_frame_97, + str_frame_98, + str_frame_99, + str_frame_100, + str_frame_101, + str_frame_102, + str_frame_103, + str_frame_104, + str_frame_105, + str_frame_106, + str_frame_107, + str_frame_108, + str_frame_109, + str_frame_110, + str_frame_111, + str_frame_112, + str_frame_113, + str_frame_114, + str_frame_115, + str_frame_116, + str_frame_117, + str_frame_118, + str_frame_119, + str_frame_120, + str_frame_121, + str_frame_122, + str_frame_123, + str_frame_124, + str_frame_125, + str_frame_126, + str_frame_127, + str_frame_128, + str_frame_129, + str_frame_130, + str_frame_131, + str_frame_132, + str_frame_133, + str_frame_134, + str_frame_135, + str_frame_136, + str_frame_137, + str_frame_138, + str_frame_139, + str_frame_140, + str_frame_141, + str_frame_142, + str_frame_143, + str_frame_144, + str_frame_145, + str_frame_146, + str_frame_147, + str_frame_148, + str_frame_149, + str_frame_150, + str_frame_151, + str_frame_152, + str_frame_153, + str_frame_154, + str_frame_155, + str_frame_156, + str_frame_157, + str_frame_158, + str_frame_159, + str_frame_160, + str_frame_161, + str_frame_162, + str_frame_163, + str_frame_164, + str_frame_165, + str_frame_166, + str_frame_167, + str_frame_168, + str_frame_169, + str_frame_170, + str_frame_171, + str_frame_172, + +}; + + +/******************************************************************************* +* SENSOR_TYPE_TABLE - Binary frames sensor types +* +* This table specifies the type of sensor depending on the type of value the +* user must put as input. These are the possibilities: +* +* 0: uint8_t +* 1: int (the same as int16_t) +* 2: double +* 3: char* +* 4: uint32_t +* 5: uint8_t* +******************************************************************************/ +const uint8_t FRAME_SENSOR_TYPE_TABLE[] PROGMEM= +{ + // Gases v30 + 2, // 0 + 2, // 1 + 2, // 2 + 2, // 3 + 2, // 4 + 2, // 5 + 2, // 6 + 2, // 7 + 2, // 8 + 2, // 9 + 2, // 10 + 2, // 11 + + + //// Gases PRO v30 + 2, // 12 + 2, // 13 + 2, // 14 + 2, // 15 + 2, // 16 + 2, // 17 + 2, // 18 + 2, // 19 + 2, // 20 + + //// Cities PRO v30 + 2, // 21 + + //// reserved + 0, // 22 + 0, // 23 + 0, // 24 + 0, // 25 + 0, // 26 + 0, // 27 + 0, // 28 + 0, // 29 + + //// Gases PRO v30 + 2, // 30 + 2, // 31 + 2, // 32 + 2, // 33 + 2, // 34 + 2, // 35 + + //// reserved + 0, // 36 + 0, // 37 + 0, // 38 + 0, // 39 + + //// Events v30 + 2, // 40 + 0, // 41 + 0, // 42 + 0, // 43 + 0, // 44 + 0, // 45 + 0, // 46 + 0, // 47 + 0, // 48 + 0, // 49 + 0, // 50 + 0, // 51 + + // Additional + 0, // str_BAT, // 52 + 2, // str_GPS, // 53 + 1, // str_RSSI, // 54 + 3, // str_MAC, // 55 + 3, // str_NA, // 56 + 3, // str_NID, // 57 + 0, // str_DATE, // 58 + 0, // str_TIME, // 59 + 1, // str_GMT, // 60 + 1, // str_RAM, // 61 + 2, // str_IN_TEMP, // 62 + 1, // str_ACC, // 63 + 4, // str_MILLIS, // 64 + 3, // str_STR // 65 + 3, // str_MBT // 66 + 3, // str_MWIFI // 67 + 3, // str_UID // 68 + 3, // str_RB // 69 + 2, // 70 + 2, // 71 + 2, // 72 + 4, // 73 + 2, // 74 + 2, // 75 + 2, // 76 + 2, // 77 + 4, // 78 + 1, // 79 + 0, // 80 + 0, // 81 + 0, // 82 + 0, // 83 + 0, // 84 + 0, // 85 + 0, // 86 + 0, // 87 + 0, // 88 + 2, // 89 + 2, // 90 + 2, // 91 + 2, // 92 + 2, // 93 + 2, // 94 + 0, // 95 + 0, // 96 + 0, // 97 + 0, // 98 + 0, // 99 + + //// Smart Water Ions + 2, // 100 + 2, // 101 + 2, // 102 + 2, // 103 + 2, // 104 + 2, // 105 + 2, // 106 + 2, // 107 + 2, // 108 + 2, // 109 + 2, // 110 + 2, // 111 + 2, // 112 + 2, // 113 + 2, // 114 + 2, // 115 + 2, // 116 + 2, // 117 + 2, // 118 + 2, // 119 + 2, // 120 + 0, // 121 + 0, // 122 + + //// Additional + 4, // 123 + 0, // 124 + 0, // 125 + 0, // 126 + 0, // 127 + 0, // 128 + + //// Radiation + 2, // 129 + + //// Smart Water + 2, // 130 + 2, // 131 + 2, // 132 + 2, // 133 + 2, // 134 + 2, // 135 + 2, // 136 + 2, // 137 + 2, // 138 + 2, // 139 + 0, // 140 + 0, // 141 + 0, // 142 + 0, // 143 + 0, // 144 + 0, // 145 + 0, // 146 + 0, // 147 + 0, // 148 + 0, // 149 + + //// Smart Agriculture + 2, // 150 + 2, // 151 + 2, // 152 + 2, // 153 + 2, // 154 + 2, // 155 + 2, // 156 + 0, // 157 + 2, // 158 + 2, // 159 + 2, // 160 + 2, // 161 + 2, // 162 + 2, // 163 + 2, // 164 + 2, // 165 + 2, // 166 + 2, // 167 + 2, // 168 + 0, // 169 + + //// Ambient Control + 2, // 170 + 2, // 171 + 2, // 172 +}; + + + +/******************************************************************************* +* SENSOR_FIELD_TABLE - Sensor fields +* +* This table specifies the number of fields per sensor. +* +* For example, a temperature sensor indicates the temperature in a single field. +* On the other hand, the GPS module indicates the position with two fields: +* latitude and longitude +******************************************************************************/ +const uint8_t FRAME_SENSOR_FIELD_TABLE[] PROGMEM= +{ + //// Gases v30 + 1, // 0 + 1, // 1 + 1, // 2 + 1, // 3 + 1, // 4 + 1, // 5 + 1, // 6 + 1, // 7 + 1, // 8 + 1, // 9 + 1, // 10 + 1, // 11 + + //// Gases PRO v30 + 1, // 12 + 1, // 13 + 1, // 14 + 1, // 15 + 1, // 16 + 1, // 17 + 1, // 18 + 1, // 19 + 1, // 20 + + //// Cities PRO v30 + 1, // 21 + + //// reserved + 1, // 22 + 1, // 23 + 1, // 24 + 1, // 25 + 1, // 26 + 1, // 27 + 1, // 28 + 1, // 29 + + //// Gases PRO v30 + 1, // 30 + 1, // 31 + 1, // 32 + 1, // 33 + 1, // 34 + 1, // 35 + + //// reserved + 1, // 36 + 1, // 37 + 1, // 38 + 1, // 39 + + //// Events v30 + 1, // 40 + 1, // 41 + 1, // 42 + 1, // 43 + 1, // 44 + 1, // 45 + 1, // 46 + 1, // 47 + 1, // 48 + 1, // 49 + 1, // 50 + 1, // 51 + + //// Additional + 1, // 52 + 2, // 53 + 1, // 54 + 1, // 55 + 1, // 56 + 1, // 57 + 3, // 58 + 3, // 59 + 1, // 60 + 1, // 61 + 1, // 62 + 3, // 63 + 1, // 64 + 1, // 65 + 1, // 66 + 1, // 67 + 1, // 68 + 1, // 69 + 1, // 70 + 1, // 71 + 1, // 72 + 2, // 73 + 1, // 74 + 1, // 75 + 1, // 76 + 1, // 77 + 1, // 78 + 1, // 79 + 1, // 80 + 1, // 81 + 1, // 82 + 1, // 83 + 1, // 84 + 1, // 85 + 1, // 86 + 1, // 87 + 1, // 88 + 1, // 89 + 1, // 90 + 1, // 91 + 1, // 92 + 1, // 93 + 1, // 94 + 1, // 95 + 1, // 96 + 1, // 97 + 1, // 98 + 1, // 99 + + //// Smart Water Ions + 1, // 100 + 1, // 101 + 1, // 102 + 1, // 103 + 1, // 104 + 1, // 105 + 1, // 106 + 1, // 107 + 1, // 108 + 1, // 109 + 1, // 110 + 1, // 111 + 1, // 112 + 1, // 113 + 1, // 114 + 1, // 115 + 1, // 116 + 1, // 117 + 1, // 118 + 1, // 119 + 1, // 120 + 1, // 121 + 1, // 122 + + //// Additional + 1, // 123 + 1, // 124 + 1, // 125 + 1, // 126 + 1, // 127 + 1, // 128 + + //// Radiation + 1, // 129 + + //// Smart Water + 1, // 130 + 1, // 131 + 1, // 132 + 1, // 133 + 1, // 134 + 1, // 135 + 1, // 136 + 1, // 137 + 1, // 138 + 1, // 139 + 1, // 140 + 1, // 141 + 1, // 142 + 1, // 143 + 1, // 144 + 1, // 145 + 1, // 146 + 1, // 147 + 1, // 148 + 1, // 149 + + //// Smart Agriculture + 1, // 150 + 1, // 151 + 1, // 152 + 1, // 153 + 1, // 154 + 1, // 155 + 1, // 156 + 1, // 157 + 1, // 158 + 1, // 159 + 1, // 160 + 1, // 161 + 1, // 162 + 1, // 163 + 1, // 164 + 1, // 165 + 1, // 166 + 1, // 167 + 1, // 168 + 1, // 169 + + //// Ambient Control + 1, // 170 + 1, // 171 + 1, // 172 + +}; + + + +/******************************************************************************* +* DECIMAL_TABLE - number of default decimals for each sensor for ASCII frames +* +* This table specifies the number of decimals for each sensor for ASCII frames +******************************************************************************/ +const uint8_t FRAME_DECIMAL_TABLE[] PROGMEM = +{ + // Gases + 3, // 0 + 3, // 1 + 3, // 2 + 3, // 3 + 3, // 4 + 3, // 5 + 3, // 6 + 3, // 7 + 3, // 8 + 3, // 9 + 3, // 10 + 3, // 11 + + //// Gases PRO v30 + 3, // 12 + 3, // 13 + 3, // 14 + 3, // 15 + 3, // 16 + 3, // 17 + 3, // 18 + 3, // 19 + 3, // 20 + + //// Cities PRO v30 + 2, // 21 + + //// reserved + 0, // 22 + 0, // 23 + 0, // 24 + 0, // 25 + 0, // 26 + 0, // 27 + 0, // 28 + 0, // 29 + + //// Gases PRO v30 + 3, // 30 + 3, // 31 + 3, // 32 + 3, // 33 + 3, // 34 + 3, // 35 + + //// reserved + 0, // 36 + 0, // 37 + 0, // 38 + 0, // 39 + + //// Events v30 + 3, // 40 + 0, // 41 + 0, // 42 + 0, // 43 + 0, // 44 + 0, // 45 + 0, // 46 + 0, // 47 + 0, // 48 + 0, // 49 + 0, // 50 + 0, // 51 + + //// Additional + 0, // str_BAT, // 52 + 6, // str_GPS, // 53 + 0, // str_RSSI, // 54 + 0, // str_MAC, // 55 + 0, // str_NA, // 56 + 0, // str_NID, // 57 + 0, // str_DATE, // 58 + 0, // str_TIME, // 59 + 0, // str_GMT, // 60 + 0, // str_RAM, // 61 + 2, // str_IN_TEMP, // 62 + 0, // str_ACC, // 63 + 0, // str_MILLIS, // 64 + 0, // str_STR // 65 + 0, // 66 + 0, // 67 + 0, //str_UID // 68 + 0, //str_RB // 69 + 4, // 70 + 4, // 71 + 4, // 72 + 0, // 73 + 2, // 74 + 2, // 75 + 1, // 76 + 2, // 77 + 0, // 78 + 0, // 79 + 0, // 80 + 0, // 81 + 0, // 82 + 0, // 83 + 0, // 84 + 0, // 85 + 0, // 86 + 0, // 87 + 0, // 88 + 2, // 89 + 2, // 90 + 2, // 91 + 3, // 92 + 3, // 93 + 3, // 94 + 0, // 95 + 0, // 96 + 0, // 97 + 0, // 98 + 0, // 99 + + //// Smart Water Ions + 3, // 100 + 3, // 101 + 3, // 102 + 3, // 103 + 3, // 104 + 3, // 105 + 3, // 106 + 3, // 107 + 3, // 108 + 3, // 109 + 3, // 110 + 3, // 111 + 3, // 112 + 3, // 113 + 3, // 114 + 3, // 115 + 3, // 116 + 3, // 117 + 3, // 118 + 3, // 119 + 3, // 120 + 3, // 121 + 3, // 122 + + //// Additional + 0, // 123 + 0, // 124 + 0, // 125 + 0, // 126 + 0, // 127 + 0, // 128 + + //// Radiation + 6, // 129 + + //// Smart Water + 2, // 130 + 3, // 131 + 1, // 132 + 1, // 133 + 2, // 134 + 1, // 135 + 2, // 136 + 2, // 137 + 3, // 138 + 3, // 139 + 0, // 140 + 0, // 141 + 0, // 142 + 0, // 143 + 0, // 144 + 0, // 145 + 0, // 146 + 0, // 147 + 0, // 148 + 0, // 149 + + //// Smart Agriculture + 2, // 150 + 2, // 151 + 2, // 152 + 2, // 153 + 2, // 154 + 3, // 155 + 2, // 156 + 0, // 157 + 2, // 158 + 2, // 159 + 2, // 160 + 2, // 161 + 2, // 162 + 3, // 163 + 3, // 164 + 3, // 165 + 2, // 166 + 2, // 167 + 2, // 168 + 0, // 169 + + //// Ambient Control + 2, // 170 + 1, // 171 + 3, // 172 + + +}; + + #endif + diff --git a/libraries/Frame/keywords.txt b/libraries/Frame/keywords.txt index 6e68096..9a380bc 100644 --- a/libraries/Frame/keywords.txt +++ b/libraries/Frame/keywords.txt @@ -1,4 +1,4 @@ -# Frame-related keywords # +TYPE_FLOAT# Frame-related keywords # setFrameSize KEYWORD2 getFrameSize KEYWORD2 @@ -24,7 +24,19 @@ setID KEYWORD2 getID KEYWORD2 addTimestamp KEYWORD2 decrementSequence KEYWORD2 -frame KEYWORD3 + + +_serial_id KEYWORD2 +storeSequence KEYWORD2 +readSequence KEYWORD2 +checkLength KEYWORD2 +sequence KEYWORD2 +numFields KEYWORD2 +_mode KEYWORD2 +_maxSize KEYWORD2 +_waspmoteID KEYWORD2 + +frame KEYWORD1 MAX_FRAME LITERAL1 UNICAST_16B LITERAL1 @@ -42,17 +54,23 @@ AES192_ECB_FRAME LITERAL1 AES256_ECB_FRAME LITERAL1 TYPE_UINT8 LITERAL1 TYPE_INT LITERAL1 -TYPE_FLOAT LITERAL1 +TYPE_FLOAT LITERAL1 TYPE_CHAR LITERAL1 TYPE_ULONG LITERAL1 BINARY LITERAL1 ASCII LITERAL1 ENCRYPTED_FRAME LITERAL1 +AES128_ECB_FRAME_V15 LITERAL1 +AES192_ECB_FRAME_V15 LITERAL1 +AES256_ECB_FRAME_V15 LITERAL1 +AES128_ECB_FRAME_V12 LITERAL1 +AES192_ECB_FRAME_V12 LITERAL1 +AES256_ECB_FRAME_V12 LITERAL1 -#SENSOR CONSTANTS +#SENSOR CONSTANTS v12 SENSOR_CO LITERAL1 Constants SENSOR_CO2 LITERAL1 Constants @@ -228,3 +246,191 @@ SENSOR_ORP_B LITERAL1 Constants SENSOR_ORP_C LITERAL1 Constants + + +# SENSOR LABELS FOR WASPMOTE V15 + +SENSOR_GASES_CO LITERAL1 +SENSOR_GASES_CO2 LITERAL1 +SENSOR_GASES_O2 LITERAL1 +SENSOR_GASES_CH4 LITERAL1 +SENSOR_GASES_O3 LITERAL1 +SENSOR_GASES_NH3 LITERAL1 +SENSOR_GASES_NO2 LITERAL1 +SENSOR_GASES_LPG LITERAL1 +SENSOR_GASES_AP1 LITERAL1 +SENSOR_GASES_AP2 LITERAL1 +SENSOR_GASES_SV LITERAL1 +SENSOR_GASES_VOC LITERAL1 +SENSOR_GASES_TC LITERAL1 +SENSOR_GASES_TF LITERAL1 +SENSOR_GASES_HUM LITERAL1 +SENSOR_GASES_PRES LITERAL1 +SENSOR_GASES_LUXES LITERAL1 +SENSOR_GASES_US LITERAL1 + +SENSOR_GASES_PRO_CO LITERAL1 +SENSOR_GASES_PRO_CO2 LITERAL1 +SENSOR_GASES_PRO_O2 LITERAL1 +SENSOR_GASES_PRO_CH4 LITERAL1 +SENSOR_GASES_PRO_O3 LITERAL1 +SENSOR_GASES_PRO_NH3 LITERAL1 +SENSOR_GASES_PRO_NO2 LITERAL1 +SENSOR_GASES_PRO_NO LITERAL1 +SENSOR_GASES_PRO_CL2 LITERAL1 +SENSOR_GASES_PRO_ETO LITERAL1 +SENSOR_GASES_PRO_H2 LITERAL1 +SENSOR_GASES_PRO_H2S LITERAL1 +SENSOR_GASES_PRO_HCL LITERAL1 +SENSOR_GASES_PRO_HCN LITERAL1 +SENSOR_GASES_PRO_PH3 LITERAL1 +SENSOR_GASES_PRO_SO2 LITERAL1 +SENSOR_GASES_PRO_SOCKET_A LITERAL1 +SENSOR_GASES_PRO_SOCKET_B LITERAL1 +SENSOR_GASES_PRO_SOCKET_C LITERAL1 +SENSOR_GASES_PRO_SOCKET_F LITERAL1 +SENSOR_GASES_PRO_PM1 LITERAL1 +SENSOR_GASES_PRO_PM2_5 LITERAL1 +SENSOR_GASES_PRO_PM10 LITERAL1 +SENSOR_GASES_PRO_PART LITERAL1 +SENSOR_GASES_PRO_TC LITERAL1 +SENSOR_GASES_PRO_TF LITERAL1 +SENSOR_GASES_PRO_HUM LITERAL1 +SENSOR_GASES_PRO_PRES LITERAL1 +SENSOR_GASES_PRO_LUXES LITERAL1 +SENSOR_GASES_PRO_US LITERAL1 + +SENSOR_EVENTS_WF LITERAL1 +SENSOR_EVENTS_PIR LITERAL1 +SENSOR_EVENTS_LP LITERAL1 +SENSOR_EVENTS_LL LITERAL1 +SENSOR_EVENTS_HALL LITERAL1 +SENSOR_EVENTS_RELAY_IN LITERAL1 +SENSOR_EVENTS_RELAY_OUT LITERAL1 +SENSOR_EVENTS_SOCKET_A LITERAL1 +SENSOR_EVENTS_SOCKET_C LITERAL1 +SENSOR_EVENTS_SOCKET_D LITERAL1 +SENSOR_EVENTS_SOCKET_E LITERAL1 +SENSOR_EVENTS_TC LITERAL1 +SENSOR_EVENTS_TF LITERAL1 +SENSOR_EVENTS_HUM LITERAL1 +SENSOR_EVENTS_PRES LITERAL1 +SENSOR_EVENTS_LUXES LITERAL1 +SENSOR_EVENTS_US LITERAL1 + +SENSOR_CITIES_PRO_CO LITERAL1 +SENSOR_CITIES_PRO_CO2 LITERAL1 +SENSOR_CITIES_PRO_O2 LITERAL1 +SENSOR_CITIES_PRO_CH4 LITERAL1 +SENSOR_CITIES_PRO_O3 LITERAL1 +SENSOR_CITIES_PRO_NH3 LITERAL1 +SENSOR_CITIES_PRO_NO2 LITERAL1 +SENSOR_CITIES_PRO_NO LITERAL1 +SENSOR_CITIES_PRO_CL2 LITERAL1 +SENSOR_CITIES_PRO_ETO LITERAL1 +SENSOR_CITIES_PRO_H2 LITERAL1 +SENSOR_CITIES_PRO_H2S LITERAL1 +SENSOR_CITIES_PRO_HCL LITERAL1 +SENSOR_CITIES_PRO_HCN LITERAL1 +SENSOR_CITIES_PRO_PH3 LITERAL1 +SENSOR_CITIES_PRO_SO2 LITERAL1 +SENSOR_CITIES_PRO_AUDIO LITERAL1 +SENSOR_CITIES_PRO_SOCKET_A LITERAL1 +SENSOR_CITIES_PRO_SOCKET_B LITERAL1 +SENSOR_CITIES_PRO_SOCKET_C LITERAL1 +SENSOR_CITIES_PRO_SOCKET_F LITERAL1 +SENSOR_CITIES_PRO_PM1 LITERAL1 +SENSOR_CITIES_PRO_PM2_5 LITERAL1 +SENSOR_CITIES_PRO_PM10 LITERAL1 +SENSOR_CITIES_PRO_PART LITERAL1 +SENSOR_CITIES_PRO_TC LITERAL1 +SENSOR_CITIES_PRO_TF LITERAL1 +SENSOR_CITIES_PRO_HUM LITERAL1 +SENSOR_CITIES_PRO_PRES LITERAL1 +SENSOR_CITIES_PRO_LUXES LITERAL1 +SENSOR_CITIES_PRO_US LITERAL1 + +SENSOR_IONS_CA LITERAL1 +SENSOR_IONS_FL LITERAL1 +SENSOR_IONS_FB LITERAL1 +SENSOR_IONS_NO3 LITERAL1 +SENSOR_IONS_BR LITERAL1 +SENSOR_IONS_CL LITERAL1 +SENSOR_IONS_CU LITERAL1 +SENSOR_IONS_IO LITERAL1 +SENSOR_IONS_NH4 LITERAL1 +SENSOR_IONS_AG LITERAL1 +SENSOR_IONS_PH LITERAL1 +SENSOR_IONS_LI LITERAL1 +SENSOR_IONS_MG LITERAL1 +SENSOR_IONS_NO2 LITERAL1 +SENSOR_IONS_CLO4 LITERAL1 +SENSOR_IONS_K LITERAL1 +SENSOR_IONS_NA LITERAL1 +SENSOR_IONS_SOCKET_A LITERAL1 +SENSOR_IONS_SOCKET_B LITERAL1 +SENSOR_IONS_SOCKET_C LITERAL1 +SENSOR_IONS_SOCKET_D LITERAL1 +SENSOR_IONS_WT LITERAL1 + +SENSOR_PARKING LITERAL1 +SENSOR_RADIATION LITERAL1 + +SENSOR_WATER_PH LITERAL1 +SENSOR_WATER_ORP LITERAL1 +SENSOR_WATER_DO LITERAL1 +SENSOR_WATER_COND LITERAL1 +SENSOR_WATER_WT LITERAL1 +SENSOR_WATER_TURB LITERAL1 +SENSOR_WATER_PH_A LITERAL1 +SENSOR_WATER_PH_D LITERAL1 +SENSOR_WATER_ORP_A LITERAL1 +SENSOR_WATER_ORP_D LITERAL1 + +SENSOR_AGR_SOIL1 LITERAL1 +SENSOR_AGR_SOIL2 LITERAL1 +SENSOR_AGR_SOIL3 LITERAL1 +SENSOR_AGR_SOIL_B LITERAL1 +SENSOR_AGR_SOIL_C LITERAL1 +SENSOR_AGR_SOIL_E LITERAL1 +SENSOR_AGR_SOILTC LITERAL1 +SENSOR_AGR_SOILTF LITERAL1 +SENSOR_AGR_LW LITERAL1 +SENSOR_AGR_ANE LITERAL1 +SENSOR_AGR_WV LITERAL1 +SENSOR_AGR_PLV1 LITERAL1 +SENSOR_AGR_PLV2 LITERAL1 +SENSOR_AGR_PLV3 LITERAL1 +SENSOR_AGR_PAR LITERAL1 +SENSOR_AGR_UV LITERAL1 +SENSOR_AGR_TD LITERAL1 +SENSOR_AGR_SD LITERAL1 +SENSOR_AGR_FD LITERAL1 +SENSOR_AGR_TC LITERAL1 +SENSOR_AGR_TF LITERAL1 +SENSOR_AGR_HUM LITERAL1 +SENSOR_AGR_PRES LITERAL1 +SENSOR_AGR_LUXES LITERAL1 +SENSOR_AGR_US LITERAL1 + +SENSOR_AMBIENT_TCB LITERAL1 +SENSOR_AMBIENT_HUMB LITERAL1 +SENSOR_AMBIENT_LUM LITERAL1 +SENSOR_AMBIENT_LUXES LITERAL1 +SENSOR_AMBIENT_TC LITERAL1 +SENSOR_AMBIENT_HUM LITERAL1 +SENSOR_AMBIENT_PRES LITERAL1 + +SENSOR_DUST_PM1 LITERAL1 +SENSOR_DUST_PM2_5 LITERAL1 +SENSOR_DUST_PM10 LITERAL1 +SENSOR_DUST_PART LITERAL1 +SENSOR_BME_TC LITERAL1 +SENSOR_BME_TF LITERAL1 +SENSOR_BME_HUM LITERAL1 +SENSOR_BME_PRES LITERAL1 +SENSOR_LUXES LITERAL1 +SENSOR_ULTRASOUND LITERAL1 + + + diff --git a/libraries/GPRS_Pro/WaspGPRS_Pro.cpp b/libraries/GPRS_Pro/WaspGPRS_Pro.cpp index fd2539e..ada596b 100755 --- a/libraries/GPRS_Pro/WaspGPRS_Pro.cpp +++ b/libraries/GPRS_Pro/WaspGPRS_Pro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.0 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ diff --git a/libraries/GPRS_Pro/WaspGPRS_Pro.h b/libraries/GPRS_Pro/WaspGPRS_Pro.h index e4a0878..2047625 100755 --- a/libraries/GPRS_Pro/WaspGPRS_Pro.h +++ b/libraries/GPRS_Pro/WaspGPRS_Pro.h @@ -1,7 +1,7 @@ /*! \file WaspGPRS_Pro.h \brief Library for managing the SIM900 module - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 2.0 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego diff --git a/libraries/GPRS_Pro/keywords.txt b/libraries/GPRS_Pro/keywords.txt index 8acbad9..ce533f2 100644 --- a/libraries/GPRS_Pro/keywords.txt +++ b/libraries/GPRS_Pro/keywords.txt @@ -1,2 +1,2 @@ -GPRS_Pro KEYWORD3 +GPRS_Pro KEYWORD1 WaspGPRS_Pro KEYWORD2 diff --git a/libraries/GPRS_SIM908/WaspGPRS_SIM908.cpp b/libraries/GPRS_SIM908/WaspGPRS_SIM908.cpp index 3e75c82..36568fe 100755 --- a/libraries/GPRS_SIM908/WaspGPRS_SIM908.cpp +++ b/libraries/GPRS_SIM908/WaspGPRS_SIM908.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ diff --git a/libraries/GPRS_SIM908/WaspGPRS_SIM908.h b/libraries/GPRS_SIM908/WaspGPRS_SIM908.h index 0e413a9..f305836 100755 --- a/libraries/GPRS_SIM908/WaspGPRS_SIM908.h +++ b/libraries/GPRS_SIM908/WaspGPRS_SIM908.h @@ -1,7 +1,7 @@ /*! \file WaspGPRS_SIM908.h \brief Library for managing the SIM900 module - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego diff --git a/libraries/GPRS_SIM908/keywords.txt b/libraries/GPRS_SIM908/keywords.txt index d9d724b..e5e296b 100644 --- a/libraries/GPRS_SIM908/keywords.txt +++ b/libraries/GPRS_SIM908/keywords.txt @@ -1,6 +1,6 @@ # GPRS_SIM908 keywords # -GPRS_SIM908 KEYWORD3 +GPRS_SIM908 KEYWORD1 BASIC LITERAL1 GGA LITERAL1 @@ -98,7 +98,6 @@ GPRS_MAX_DATA LITERAL1 FRAME_DISABLED LITERAL1 FRAME_ENABLED LITERAL1 -flag KEYWORD2 tlfIN KEYWORD2 _baudRate KEYWORD2 _pwrMode KEYWORD2 diff --git a/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.cpp b/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.cpp index b2e5f73..44800e3 100755 --- a/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.cpp +++ b/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ diff --git a/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.h b/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.h index 71ed0a3..5638e2c 100755 --- a/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.h +++ b/libraries/GPRS_SIM928A/WaspGPRS_SIM928A.h @@ -1,7 +1,7 @@ /*! \file WaspGPRS_SIM928A.h \brief Library for managing the SIM928A module - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego @@ -28,7 +28,7 @@ */ #ifndef WaspGPRS_SIM928A_h -#define WaspGPRS_SIM92A8_h +#define WaspGPRS_SIM928A_h /****************************************************************************** * Includes diff --git a/libraries/GPRS_SIM928A/keywords.txt b/libraries/GPRS_SIM928A/keywords.txt index 26944f0..19ab4bc 100644 --- a/libraries/GPRS_SIM928A/keywords.txt +++ b/libraries/GPRS_SIM928A/keywords.txt @@ -1,6 +1,6 @@ # GPRS_SIM928A keywords # -GPRS_SIM928A KEYWORD3 +GPRS_SIM928A KEYWORD1 longitude KEYWORD2 latitude KEYWORD2 @@ -85,7 +85,6 @@ GPRS_MAX_DATA LITERAL1 FRAME_DISABLED LITERAL1 FRAME_ENABLED LITERAL1 -flag KEYWORD2 tlfIN KEYWORD2 _baudRate KEYWORD2 _pwrMode KEYWORD2 diff --git a/libraries/GPS/WaspGPS.cpp b/libraries/GPS/WaspGPS.cpp index 732dad0..c4d774a 100755 --- a/libraries/GPS/WaspGPS.cpp +++ b/libraries/GPS/WaspGPS.cpp @@ -1,7 +1,7 @@ /* * Library for managing the GPS v2.0 JN3 receiver * - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.4 + * Version: 3.0 * Design: David Gascón * Implementation: Javier Siscart */ @@ -117,7 +117,7 @@ void WaspGPS::close() closeSerial(_uart); // Disable UART1's multiplexer - Utils.setMux(MUX_TO_LOW,MUX_TO_LOW); + Utils.setMux(LOW,LOW); } diff --git a/libraries/GPS/WaspGPS.h b/libraries/GPS/WaspGPS.h index 3740386..2330d4d 100755 --- a/libraries/GPS/WaspGPS.h +++ b/libraries/GPS/WaspGPS.h @@ -1,7 +1,7 @@ /*! \file WaspGPS.h \brief Library for managing the GPS v2.0 JN3 receiver - Copyright (C) 2013 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.3 + Version: 3.0 Design: David Gascón Implementation: Javier Siscart diff --git a/libraries/GPS/keywords.txt b/libraries/GPS/keywords.txt index c43403c..7305d8d 100644 --- a/libraries/GPS/keywords.txt +++ b/libraries/GPS/keywords.txt @@ -1,6 +1,6 @@ # GPS keywords # -GPS KEYWORD3 +GPS KEYWORD1 OSP_MODE LITERAL1 NMEA_MODE LITERAL1 @@ -13,7 +13,6 @@ MAX_SIZE LITERAL1 FILE_EPHEMERIS LITERAL1 WaspGPS KEYWORD2 -flag KEYWORD2 timeGPS KEYWORD2 dateGPS KEYWORD2 clkOffset KEYWORD2 diff --git a/libraries/LoRaWAN/WaspLoRaWAN.cpp b/libraries/LoRaWAN/WaspLoRaWAN.cpp index 55053e3..55bd6f8 100755 --- a/libraries/LoRaWAN/WaspLoRaWAN.cpp +++ b/libraries/LoRaWAN/WaspLoRaWAN.cpp @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 0.3 + * Version: 3.1 * Design: David Gascón * Implementation: Luis Miguel Martí */ @@ -111,6 +111,16 @@ const char command_78[] PROGMEM = "mac set rx2 %u %lu\r\n"; const char command_79[] PROGMEM = "mac set rxdelay1 %u\r\n"; const char command_80[] PROGMEM = "mac reset\r\n"; + const char command_81[] PROGMEM = "mac get status\r\n"; + const char command_82[] PROGMEM = "mac tx cnf %u "; + const char command_83[] PROGMEM = "mac tx uncnf %u "; + const char command_84[] PROGMEM = "sys sleep %lu\r\n"; + const char command_85[] PROGMEM = "mac set ar %s\r\n"; + const char command_86[] PROGMEM = "mac get ar\r\n"; + const char command_87[] PROGMEM = "mac get rxdelay1\r\n"; + const char command_88[] PROGMEM = "mac get rxdelay2\r\n"; + const char command_89[] PROGMEM = "mac get rx2 %s\r\n"; + const char* const table_LoRaWAN_COMMANDS[] PROGMEM= @@ -195,7 +205,16 @@ const char* const table_LoRaWAN_COMMANDS[] PROGMEM= command_77, command_78, command_79, - command_80 + command_80, + command_81, + command_82, + command_83, + command_84, + command_85, + command_86, + command_87, + command_88, + command_89 }; /****************************************************************************** @@ -277,50 +296,17 @@ uint8_t WaspLoRaWAN::ON(uint8_t socket) OFF(socket); delay(200); + + // select multiplexer + if (_uart == SOCKET0) Utils.setMuxSocket0(); + if (_uart == SOCKET1) Utils.setMuxSocket1(); + + // Open UART + beginUART(); + + // power on the socket + PWR.powerSocket(_uart, HIGH); - if (socket == SOCKET0) - { - _uart = SOCKET0; - - // Set multiplexer - Utils.setMuxSocket0(); - - // Open UART - beginUART(); - - // power up - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - } - else - { - // check RTC int pin to disable line in order to communicate - if (digitalRead(RTC_INT_PIN_MON) == HIGH) - { - if (RTC.isON == 0 ) - { - RTC.ON(); - RTC.clearAlarmFlag(); - RTC.OFF(); - } - else - { - RTC.clearAlarmFlag(); - } - } - - _uart = SOCKET1; - - // Set multiplexer - Utils.setMuxSocket1(); - - // Open UART - beginUART(); - - // power up - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,HIGH); - } delay(300); error = check(); return error; @@ -336,32 +322,18 @@ uint8_t WaspLoRaWAN::ON(uint8_t socket) */ uint8_t WaspLoRaWAN::OFF(uint8_t socket) { - if (socket == SOCKET0) - { - _uart = SOCKET0; - - // Set multiplexer - Utils.setMuxUSB(); - - // close UART0 - closeUART(); - - // power down - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW, LOW); - } - else - { - _uart = SOCKET1; - - // close UART1 - closeUART(); - - // power down - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,LOW); - } + _uart = socket; + + // close uart + closeUART(); + // unselect multiplexer + if (_uart == SOCKET0) Utils.setMuxUSB(); + if (_uart == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uart, LOW); + return LORAWAN_ANSWER_OK; } @@ -430,10 +402,12 @@ uint8_t WaspLoRaWAN::factoryReset() uint8_t status; char ans1[15]; char ans2[15]; + char carr[5]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); + memset(carr,0x00,sizeof(carr)); // create "sys factoryRESET" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[1]))); @@ -441,19 +415,21 @@ uint8_t WaspLoRaWAN::factoryReset() sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[5]))); // create "RN2903" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[20]))); + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); //send command and wait for ans status = sendCommand(_command,ans1,ans2,5000); if (status == 1) { - waitFor("\r\n",1000); + waitFor(carr,1000); _version = RN2483_MODULE; return LORAWAN_ANSWER_OK; } else if (status == 2) { - waitFor("\r\n",1000); + waitFor(carr,1000); _version = RN2903_MODULE; return LORAWAN_ANSWER_OK; } @@ -476,18 +452,22 @@ uint8_t WaspLoRaWAN::factoryReset() uint8_t WaspLoRaWAN::getEUI() { uint8_t status; - char ans1[15]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "sys get hweui" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[2]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 0) { @@ -495,7 +475,7 @@ uint8_t WaspLoRaWAN::getEUI() } else if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); + char* pch = strtok((char*)_buffer,ans1); if (pch != NULL) { memset(_eui,0x00,sizeof(_eui)); @@ -525,18 +505,22 @@ uint8_t WaspLoRaWAN::getEUI() uint8_t WaspLoRaWAN::getAddr() { uint8_t status; - char ans1[15]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "sys get hweui" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[2]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 0) { @@ -544,7 +528,7 @@ uint8_t WaspLoRaWAN::getAddr() } else if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); + char* pch = strtok((char*)_buffer,ans1); if (pch != NULL) { memset(_devAddr,0x00,sizeof(_devAddr)); @@ -574,18 +558,22 @@ uint8_t WaspLoRaWAN::getAddr() uint8_t WaspLoRaWAN::getSupplyPower() { uint8_t status; - char ans1[15]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "sys get vdd" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[3]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { @@ -849,18 +837,22 @@ uint8_t WaspLoRaWAN::setDeviceEUI(char* eui) uint8_t WaspLoRaWAN::getDeviceEUI() { uint8_t status; - char ans1[50]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "mac get deveui" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[25]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,300); if (status == 0) { @@ -868,7 +860,7 @@ uint8_t WaspLoRaWAN::getDeviceEUI() } else if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); + char* pch = strtok((char*)_buffer,ans1); if (pch != NULL) { memset(_devEUI,0x00,sizeof(_devEUI)); @@ -959,7 +951,7 @@ uint8_t WaspLoRaWAN::setDeviceAddr(char* addr) strncpy(_devAddr,addr,sizeof(_devAddr)); return LORAWAN_ANSWER_OK; } - else if (status = 2) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } @@ -982,18 +974,22 @@ uint8_t WaspLoRaWAN::setDeviceAddr(char* addr) uint8_t WaspLoRaWAN::getDeviceAddr() { uint8_t status; - char ans1[50]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "mac get devaddr" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[24]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,300); if (status == 0) { @@ -1001,7 +997,7 @@ uint8_t WaspLoRaWAN::getDeviceAddr() } else if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); + char* pch = strtok((char*)_buffer,ans1); if (pch != NULL) { memset(_devAddr,0x00,sizeof(_devAddr)); @@ -1166,18 +1162,22 @@ uint8_t WaspLoRaWAN::setAppEUI(char* eui) uint8_t WaspLoRaWAN::getAppEUI() { uint8_t status; - char ans1[50]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "mac get appeui" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[26]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,300); if (status == 0) { @@ -1185,7 +1185,7 @@ uint8_t WaspLoRaWAN::getAppEUI() } else if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); + char* pch = strtok((char*)_buffer,ans1); if (pch != NULL) { memset(_appEUI,0x00,sizeof(_appEUI)); @@ -1381,9 +1381,11 @@ uint8_t WaspLoRaWAN::setPower(uint8_t index) case 868: if ((index > 5) || (index < 1)) return LORAWAN_INPUT_ERROR; else break; + case 433: if (index > 5) return LORAWAN_INPUT_ERROR; else break; + default: return LORAWAN_VERSION_ERROR; } @@ -1430,18 +1432,22 @@ uint8_t WaspLoRaWAN::setPower(uint8_t index) uint8_t WaspLoRaWAN::getPower() { uint8_t status; - char ans1[15]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "mac get pwrindx" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[29]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { @@ -1550,18 +1556,22 @@ uint8_t WaspLoRaWAN::setDataRate(uint8_t datarate) uint8_t WaspLoRaWAN::getDataRate() { uint8_t status; - char ans1[15]; + char ans1[5]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); // create "mac get dr" command sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[27]))); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { @@ -1610,6 +1620,18 @@ uint8_t WaspLoRaWAN::saveConfig() if (status == 1) { + status = LoRaWAN.getUpCounter(); + if (status == 1) + { + status = LoRaWAN.getUpCounter(); + status = LoRaWAN.getDownCounter(); + return LORAWAN_ANSWER_OK; + } + status = LoRaWAN.getDownCounter(); + if (status == 1) + { + return LORAWAN_ANSWER_OK; + } return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -1665,6 +1687,8 @@ uint8_t WaspLoRaWAN::joinABP() //wait for response if (waitFor(ans1,800) == 1) { + setUpCounter(_upCounter); + setDownCounter(_downCounter); return LORAWAN_ANSWER_OK; } else @@ -1702,42 +1726,90 @@ uint8_t WaspLoRaWAN::joinOTAA() char ans1[15]; char ans2[15]; char ans3[15]; + uint8_t dev_addr[] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00}; + uint8_t nwk_s_key[] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00}; + uint8_t app_s_key[] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00}; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); memset(ans3,0x00,sizeof(ans3)); - // create "mac join otaa" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[76]))); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - // create "keys_not_init" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[17]))); + //initialize devAddr so field is not empty + status = setDeviceAddr((char*)dev_addr); + if ( status != 0) + { + return LORAWAN_ANSWER_ERROR; + } - //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3,500); - - if (status == 1) + //initialize NwkSKey so field is not empty + status = setNwkSessionKey((char*)nwk_s_key); + if ( status != 0) { - memset(ans1,0x00,sizeof(ans1)); - // create "accepted" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[6]))); - memset(ans2,0x00,sizeof(ans2)); - // create "denied" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[19]))); + return LORAWAN_ANSWER_ERROR; + } + + //initialize AppSKey so field is not empty + status = setAppSessionKey((char*)app_s_key); + if ( status != 0) + { + return LORAWAN_ANSWER_ERROR; + } + - //wait for response - if (waitFor(ans1,ans2,20000) == 1) - { - return LORAWAN_ANSWER_OK; - } - else + // try to join via OTAA + int retries = 3; + do + { + // create "mac join otaa" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[76]))); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + // create "keys_not_init" answer + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[17]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,ans3,1000); + + if (status == 1) { - return LORAWAN_ANSWER_ERROR; - } + // create "accepted" answer + memset(ans1,0x00,sizeof(ans1)); + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[6]))); + // create "denied" answer + memset(ans2,0x00,sizeof(ans2)); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[19]))); + + //wait for response + if (waitFor(ans1,ans2,20000) == 1) + { + status = saveConfig(); + if (status == 0) + { + return LORAWAN_ANSWER_OK; + } + else + { + return LORAWAN_ANSWER_ERROR; + } + } + else + { + // continue with next attempt + //return LORAWAN_ANSWER_ERROR; + } + } + + retries--; + + } while (retries > 0); + + + if (status == 1) + { + return LORAWAN_ANSWER_ERROR; } else if (status == 2) { @@ -1750,7 +1822,7 @@ uint8_t WaspLoRaWAN::joinOTAA() else { return LORAWAN_NO_ANSWER; - } + } } @@ -1783,6 +1855,7 @@ uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, char* payload) char ans2[20]; char ans3[20]; char ans4[20]; + char carr[5]; // clear data received flag _dataReceived = false; @@ -1826,6 +1899,7 @@ uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, char* payload) memset(ans2,0x00,sizeof(ans2)); memset(ans3,0x00,sizeof(ans3)); memset(ans4,0x00,sizeof(ans4)); + memset(carr,0x00,sizeof(carr)); // mac_rx sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[3]))); @@ -1835,13 +1909,15 @@ uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, char* payload) strcpy_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[15]))); // invalid_data_len strcpy_P(ans4,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[16]))); + // \r\n + strcpy_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); //wait for response status = waitFor(ans1, ans2, ans3, ans4, 20000); if (status == 1) { - waitFor("\r\n",500); + waitFor(carr,500); if (_length > 0) { char* pch = strtok((char*) _buffer," \r\n"); @@ -1901,11 +1977,9 @@ uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, char* payload) } - - /*! * - * @brief This function sends a LoRaWAN packet without ACK + * @brief This function sends a LoRaWAN packet and waits for ACK * * @param char* data: data to be sent * uint8_t port: port number to send data @@ -1925,47 +1999,51 @@ uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, char* payload) * @arg '6' if module hasn't joined to a network * @arg '7' if input port parameter error */ -uint8_t WaspLoRaWAN::sendUnconfirmed(uint8_t port, char* payload) +uint8_t WaspLoRaWAN::sendConfirmed(uint8_t port, uint8_t* payload, uint16_t length) { uint8_t status; char ans1[20]; char ans2[20]; char ans3[20]; char ans4[20]; + char byte2send[3]; + char carr[5]; // clear data received flag _dataReceived = false; + // clear buffers memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); memset(ans3,0x00,sizeof(ans3)); + memset(byte2send,0x00,sizeof(byte2send)); + memset(carr,0x00,sizeof(carr)); // check port if (port > 223) return LORAWAN_INPUT_ERROR; - // check if payload is a hexadecimal string - for (uint8_t i=0;i '9')) && - ((payload[i] < 'A') || (payload[i] > 'F')) && - ((payload[i] < 'a') || (payload[i] > 'f'))) - { - return LORAWAN_INPUT_ERROR; - } - } - - // create "mac tx uncnf " command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[6])),port,payload); + // create "mac tx cnf " command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[82])),port); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); // create "not_joined" answer sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[18]))); - + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3,500); + printString(_command,_uart); + for (uint16_t i=0; i + + // mac_rx sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[3]))); // mac_tx_ok - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[8]))); + strcpy_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[8]))); // mac_err - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[15]))); + strcpy_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[15]))); // invalid_data_len - sprintf_P(ans4,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[16]))); + strcpy_P(ans4,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[16]))); //wait for response status = waitFor(ans1, ans2, ans3, ans4, 20000); if (status == 1) { - waitFor("\r\n",500); - + waitFor(carr,500); if (_length > 0) { char* pch = strtok((char*) _buffer," \r\n"); @@ -2050,47 +2127,350 @@ uint8_t WaspLoRaWAN::sendUnconfirmed(uint8_t port, char* payload) } - -/*! - * @brief This function is used to set the ADR status from module +/*! * - * @param char* state: "on"/"off" + * @brief This function sends a LoRaWAN packet without ACK + * + * @param char* data: data to be sent + * uint8_t port: port number to send data * - * @return + * @remarks data is a sequence of digit representing the value of byte stream + * expressed in hexadecimal value (i.e.: payload =12A435 – the payload + * is composed by the following byte stream: 0x12, 0xA4, 0x35 – 6 digit + * converted in 3 bytes). The maximum length of frame is 584 digit (292 Bytes). + * User can check _datareceived to know if a downlink was performed + * + * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error + * @arg '4' if data length error + * @arg '5' if error when sending data + * @arg '6' if module hasn't joined to a network + * @arg '7' if input port parameter error */ -uint8_t WaspLoRaWAN::setADR(char* state) +uint8_t WaspLoRaWAN::sendUnconfirmed(uint8_t port, char* payload) { uint8_t status; - char ans1[15]; - char ans2[15]; - - // check state - if ((strcmp(state, "on")) && (strcmp(state, "off"))) return LORAWAN_INPUT_ERROR; + char ans1[20]; + char ans2[20]; + char ans3[20]; + char ans4[20]; + char carr[5]; + + // clear data received flag + _dataReceived = false; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); - // create "mac set adr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[19])),state); + // check port + if (port > 223) return LORAWAN_INPUT_ERROR; + + // check if payload is a hexadecimal string + for (uint8_t i=0;i '9')) && + ((payload[i] < 'A') || (payload[i] > 'F')) && + ((payload[i] < 'a') || (payload[i] > 'f'))) + { + return LORAWAN_INPUT_ERROR; + } + } + + // create "mac tx uncnf " command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[6])),port,payload); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + // create "not_joined" answer + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[18]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); - + status = sendCommand(_command,ans1,ans2,ans3,500); + if (status == 1) { - if (strcmp(state, "on") == 0) _adr = true; - if (strcmp(state, "off") == 0) _adr = false; - return LORAWAN_ANSWER_OK; - } + // clear buffer + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); + memset(ans4,0x00,sizeof(ans4)); + memset(carr,0x00,sizeof(carr)); + + // mac_rx + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[3]))); + // mac_tx_ok + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[8]))); + // mac_err + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[15]))); + // invalid_data_len + sprintf_P(ans4,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[16]))); + // \r\n + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + + //wait for response + status = waitFor(ans1, ans2, ans3, ans4, 20000); + + if (status == 1) + { + waitFor(carr,500); + + if (_length > 0) + { + char* pch = strtok((char*) _buffer," \r\n"); + _port = atoi(pch); + + pch = strtok(NULL," \r\n"); + + memset(_data,0x00,sizeof(_data)); + strncpy(_data, pch, sizeof(_data)-1); + + saveConfig(); + _dataReceived = true; + return LORAWAN_ANSWER_OK; + } + else + { + saveConfig(); + return LORAWAN_ANSWER_OK; + } + } + else if (status == 2) + { + saveConfig(); + return LORAWAN_ANSWER_OK; + } + else if (status == 3) + { + saveConfig(); + return LORAWAN_SENDING_ERROR; + } + else if (status == 4) + { + saveConfig(); + return LORAWAN_LENGTH_ERROR; + } + else + { + saveConfig(); + return LORAWAN_NO_ANSWER; + } + } + else if (status == 2) + { + saveConfig(); + return LORAWAN_ANSWER_ERROR; + } + else if (status == 3) + { + saveConfig(); + return LORAWAN_NOT_JOINED; + } + else + { + saveConfig(); + return LORAWAN_NO_ANSWER; + } +} + + +/*! + * + * @brief This function sends a LoRaWAN packet and waits for ACK + * + * @param char* data: data to be sent + * uint8_t port: port number to send data + * + * @remarks data is a sequence of digit representing the value of byte stream + * expressed in hexadecimal value (i.e.: payload =12A435 – the payload + * is composed by the following byte stream: 0x12, 0xA4, 0x35 – 6 digit + * converted in 3 bytes). The maximum length of frame is 584 digit (292 Bytes). + * User can check _datareceived to know if a downlink was performed + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + * @arg '4' if data length error + * @arg '5' if error when sending data + * @arg '6' if module hasn't joined to a network + * @arg '7' if input port parameter error + */ +uint8_t WaspLoRaWAN::sendUnconfirmed(uint8_t port, uint8_t* payload, uint16_t length) +{ + uint8_t status; + char ans1[20]; + char ans2[20]; + char ans3[20]; + char ans4[20]; + char byte2send[3]; + char carr[5]; + + // clear data received flag + _dataReceived = false; + + // clear buffers + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); + memset(carr,0x00,sizeof(carr)); + memset(byte2send,0x00,sizeof(byte2send)); + + // check port + if (port > 223) return LORAWAN_INPUT_ERROR; + + // create "mac tx uncnf " command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[83])),port); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + // create "not_joined" answer + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[18]))); + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + + //send command and wait for ans + printString(_command,_uart); + for (uint16_t i=0; i 0) + { + char* pch = strtok((char*) _buffer," \r\n"); + _port = atoi(pch); + + pch = strtok(NULL," \r\n"); + + memset(_data,0x00,sizeof(_data)); + strncpy(_data, pch, sizeof(_data)-1); + + saveConfig(); + _dataReceived = true; + return LORAWAN_ANSWER_OK; + } + else + { + saveConfig(); + return LORAWAN_ANSWER_OK; + } + } + else if (status == 2) + { + saveConfig(); + return LORAWAN_ANSWER_OK; + } + else if (status == 3) + { + saveConfig(); + return LORAWAN_SENDING_ERROR; + } + else if (status == 4) + { + saveConfig(); + return LORAWAN_LENGTH_ERROR; + } + else + { + saveConfig(); + return LORAWAN_NO_ANSWER; + } + } + else if (status == 2) + { + saveConfig(); + return LORAWAN_ANSWER_ERROR; + } + else if (status == 3) + { + saveConfig(); + return LORAWAN_NOT_JOINED; + } + else + { + saveConfig(); + return LORAWAN_NO_ANSWER; + } +} + + +/*! + * @brief This function is used to set the ADR status from module + * + * @param char* state: "on"/"off" + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + * @arg '7' if input parameter error + */ +uint8_t WaspLoRaWAN::setADR(char* state) +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + + // check state + if ((strcmp(state, "on")) && (strcmp(state, "off"))) return LORAWAN_INPUT_ERROR; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac set adr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[19])),state); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) + { + if (strcmp(state, "on") == 0) _adr = true; + if (strcmp(state, "off") == 0) _adr = false; + return LORAWAN_ANSWER_OK; + } else if (status == 2) { return LORAWAN_ANSWER_ERROR; @@ -2111,84 +2491,435 @@ uint8_t WaspLoRaWAN::setADR(char* state) * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getADR() +uint8_t WaspLoRaWAN::getADR() +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + char ans3[15]; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); + + // create "mac get adr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[30]))); + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); + // create "invalid_param" answer + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,ans3,500); + + if (status == 1) + { + _adr = true; + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + _adr = false; + return LORAWAN_ANSWER_OK; + } + else if (status == 3) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + + +/*! + * @brief This function is used to read the duty cycle prescaler from module + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::getDutyCyclePrescaler() +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac get dcycle" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[31]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) + { + _dCyclePS = parseIntValue(); + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + + +/*! + * @brief This function pauses MAC functionality so the module is able + * to use radio functions. + * + * @remarks This function must be called before using radio RX and TX + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::macPause() +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac pause" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[9]))); + // create "4294967245" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[14]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) + { + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + +/*! + * @brief This function resumes MAC functionality + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::macResume() +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac resume" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[10]))); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) + { + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + + +/*! + * @brief This function sets the frequency on the given channel ID + * + * @param uint32_t freq: frequency to be set [863250000..869750000] + * [433250000..434550000] + * uint8_t channel: channel to be set [3..15] + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' if module does not support function + */ +uint8_t WaspLoRaWAN::setChannelFreq(uint8_t channel, uint32_t freq) +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + + //check module (this function is only available for RN2483) + if (_version == RN2903_MODULE) + { + return LORAWAN_VERSION_ERROR; + } + + // check channel + if (channel > 15 || channel <3) return LORAWAN_INPUT_ERROR; + + // check frequency settings + if (freq < 433250000) return LORAWAN_INPUT_ERROR; + if ((freq > 434550000)&&(freq < 863250000)) return LORAWAN_INPUT_ERROR; + if (freq > 869750000) return LORAWAN_INPUT_ERROR; + + // clear buffers + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac set ch freq" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[20])),channel,freq); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) + { + _freq[channel] = freq; + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + + +/*! + * @brief This function gets the operating frequency on the given channel + * + * @param uint8_t channel + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' if unrecognized module + */ +uint8_t WaspLoRaWAN::getChannelFreq(uint8_t channel) +{ + uint8_t status; + char ans2[15]; + char ans1[15]; + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + switch (_version) + { + case RN2483_MODULE: + if (channel > 15) + { + return LORAWAN_INPUT_ERROR; + } + break; + + case RN2903_MODULE: + if (channel > 71) + { + return LORAWAN_INPUT_ERROR; + } + break; + + default: + return LORAWAN_VERSION_ERROR; + } + + // create "mac get ch freq" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[35])),channel); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,300); + + if (status == 1) + { + _freq[channel] = parseValue(10); + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + + +/*! + * @brief This function sets the duty cycle on the given channel ID + * + * @param uint16_t dcycle: frequency to be set [0..65535] + * uint8_t channel: channel to be set [0..15] + * + * @remarks The "dcycle" value that needs to be configured can be obtained + * from the actual duty cycle X (in percentage) using the following formula: + * dcycle = (100/X) – 1 + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + * @arg '7' if input channel parameter error + * @arg '8' module does not support function + */ +uint8_t WaspLoRaWAN::setChannelDutyCycle(uint8_t channel, uint16_t dcycle) { uint8_t status; + float dutycycle; char ans1[15]; char ans2[15]; - char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - memset(ans3,0x00,sizeof(ans3)); - // create "mac get adr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[30]))); - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); + //check module (this function is only available for RN2483) + if (_version == RN2903_MODULE) + { + return LORAWAN_VERSION_ERROR; + } + + // check channel + if (channel > 15) return LORAWAN_INPUT_ERROR; + + // create "mac set ch dcycle" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[21])),channel,dcycle); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3,500); + status = sendCommand(_command,ans1,ans2); if (status == 1) { - _adr = true; + _dCycle[channel] = dcycle; return LORAWAN_ANSWER_OK; } else if (status == 2) - { - _adr = false; - return LORAWAN_ANSWER_OK; - } - else if (status == 3) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - -/*! - * @brief This function is used to read the duty cycle prescaler from module +/*! + * @brief This function gets the operating duty channel on the given channel + * + * @param uint8_t channel * - * @return + * @remarks The "dcycle" value obtained from the module helps us to calculate + * duty cycle percentage "X" using the following formula: + * dcycle = (100/X) – 1 + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '8' module does not support function */ -uint8_t WaspLoRaWAN::getDutyCyclePrescaler() +uint8_t WaspLoRaWAN::getChannelDutyCycle(uint8_t channel) { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "mac get dcycle" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[31]))); + //check module (this function is only available for RN2483) + if (_version == RN2903_MODULE) + { + return LORAWAN_VERSION_ERROR; + } + + // check channel + if (channel > 15) return LORAWAN_INPUT_ERROR; + + // create "mac get ch dcycle" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[36])),channel); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,300); if (status == 1) { - _dCyclePS = parseIntValue(); + _dCycle[channel] = parseValue(10); return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } @@ -2196,39 +2927,73 @@ uint8_t WaspLoRaWAN::getDutyCyclePrescaler() -/*! - * @brief This function pauses MAC functionality so the module is able - * to use radio functions. + +/*! + * @brief This function sets the data rate range on the given channel ID * - * @remarks This function must be called before using radio RX and TX - * - * @return + * @param uint8_t minDR: datarate to be set + * uint8_t maxDR: datarate to be set + * uint8_t channel: channel to be set + * @remarks + * For RN2483: + * minDR [0..5] + * maxDR [0..5] + * channel [0..15] + * For RN2903: + * minDR [0..3] + * maxDR [0..3] + * channel [0..63] + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::macPause() +uint8_t WaspLoRaWAN::setChannelDRRange(uint8_t channel, uint8_t minDR, uint8_t maxDR) { uint8_t status; char ans1[15]; char ans2[15]; - + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac pause" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[9]))); - // create "4294967245" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[14]))); + switch (_version) + { + case RN2483_MODULE: + if ((channel > 15) || (minDR > 5) || (maxDR > 5)) + { + return LORAWAN_INPUT_ERROR; + } + break; + + case RN2903_MODULE: + if ((channel > 63) || (minDR > 3) || (maxDR > 3)) + { + return LORAWAN_INPUT_ERROR; + } + break; + + default: + return LORAWAN_VERSION_ERROR; + } + + // create "mac set ch drrange" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[22])),channel,minDR,maxDR); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans status = sendCommand(_command,ans1,ans2,500); if (status == 1) { + _drrMin[channel] = minDR; + _drrMax[channel] = maxDR; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -2241,15 +3006,21 @@ uint8_t WaspLoRaWAN::macPause() } } -/*! - * @brief This function resumes MAC functionality + +/*! + * @brief This function gets the data rate range on the given channel * - * @return + * @param uint8_t channel + * For RN2483: channel [0..15] + * For RN2903: channel [0..71] + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::macResume() +uint8_t WaspLoRaWAN::getChannelDRRange(uint8_t channel) { uint8_t status; char ans1[15]; @@ -2259,19 +3030,53 @@ uint8_t WaspLoRaWAN::macResume() memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac resume" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[10]))); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + switch (_version) + { + case RN2483_MODULE: + if (channel > 15) + { + return LORAWAN_INPUT_ERROR; + } + break; + + case RN2903_MODULE: + if (channel > 71) + { + return LORAWAN_INPUT_ERROR; + } + break; + + default: + return LORAWAN_VERSION_ERROR; + } + + // create "mac get ch drrange" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[37])),channel); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); + status = sendCommand(_command,ans1,ans2,300); if (status == 1) { - return LORAWAN_ANSWER_OK; + char * pch; + pch = strtok((char*) _buffer," \r\n"); + if (pch != NULL) + { + _drrMin[channel] = strtoul(pch,NULL, 10); + pch = strtok(NULL," \r\n"); + if (pch != NULL) + { + _drrMax[channel] = strtoul(pch,NULL, 10); + pch = strtok(pch," \r\n"); + return LORAWAN_ANSWER_OK; + } + return LORAWAN_ANSWER_ERROR; + } + return LORAWAN_ANSWER_ERROR; } else if (status == 2) { @@ -2284,58 +3089,73 @@ uint8_t WaspLoRaWAN::macResume() } - /*! - * @brief This function sets the frequency on the given channel ID + * @brief This function sets the status on the given channel ID + * + * @param char* state: state "on"/"off" + * uint8_t channel: channel to be set [0..15] * - * @param uint32_t freq: frequency to be set [863250000..869750000] - * [433250000..434550000] - * uint8_t channel: channel to be set [3..15] * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' if module does not support function + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::setChannelFreq(uint8_t channel, uint32_t freq) +uint8_t WaspLoRaWAN::setChannelStatus(uint8_t channel, char* state) { uint8_t status; char ans1[15]; char ans2[15]; - //check module (this function is only available for RN2483) - if (_version == RN2903_MODULE) - { - return LORAWAN_VERSION_ERROR; - } - - // check channel - if (channel > 15 || channel <3) return LORAWAN_INPUT_ERROR; + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // check frequency settings - if (freq < 433250000) return LORAWAN_INPUT_ERROR; - if ((freq > 434550000)&&(freq < 863250000)) return LORAWAN_INPUT_ERROR; - if (freq > 869750000) return LORAWAN_INPUT_ERROR; + // create "on" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); + // create "off" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); + + // check state + if ((strcmp(state, ans1)) && (strcmp(state, ans2))) return LORAWAN_INPUT_ERROR; + + switch (_version) + { + case RN2483_MODULE: + if (channel > 15) + { + return LORAWAN_INPUT_ERROR; + } + break; + + case RN2903_MODULE: + if (channel > 71) + { + return LORAWAN_INPUT_ERROR; + } + break; + + default: + return LORAWAN_VERSION_ERROR; + } - // clear buffers - memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set ch freq" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[20])),channel,freq); + // create "mac set ch state" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[23])),channel,state); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _freq[channel] = freq; + _status[channel] = state; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -2351,7 +3171,7 @@ uint8_t WaspLoRaWAN::setChannelFreq(uint8_t channel, uint32_t freq) /*! - * @brief This function gets the operating frequency on the given channel + * @brief This function gets the status of the given channel * * @param uint8_t channel * @@ -2359,16 +3179,20 @@ uint8_t WaspLoRaWAN::setChannelFreq(uint8_t channel, uint32_t freq) * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' if unrecognized module + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::getChannelFreq(uint8_t channel) +uint8_t WaspLoRaWAN::getChannelStatus(uint8_t channel) { uint8_t status; - char ans1[50]; + char ans1[15]; + char ans2[15]; + char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); switch (_version) { @@ -2390,20 +3214,29 @@ uint8_t WaspLoRaWAN::getChannelFreq(uint8_t channel) return LORAWAN_VERSION_ERROR; } - // create "mac get ch freq" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[35])),channel); + // create "mac get ch status" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[38])),channel); + // create "on" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); + // create "off" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,ans3,500); if (status == 1) { - _freq[channel] = parseValue(10); + _status[channel] = true; return LORAWAN_ANSWER_OK; } - else if (status == 2) + if (status == 2) + { + _status[channel] = false; + return LORAWAN_ANSWER_OK; + } + else if (status == 3) { return LORAWAN_ANSWER_ERROR; } @@ -2414,28 +3247,20 @@ uint8_t WaspLoRaWAN::getChannelFreq(uint8_t channel) } - /*! - * @brief This function sets the duty cycle on the given channel ID - * - * @param uint16_t dcycle: frequency to be set [0..65535] - * uint8_t channel: channel to be set [0..15] - * - * @remarks The "dcycle" value that needs to be configured can be obtained - * from the actual duty cycle X (in percentage) using the following formula: - * dcycle = (100/X) – 1 + * @brief This function is used to configure number of retransmisions + * for an uplink confirmed packet * - * @return + * @param uint8_t retries: number of retries [0..255] + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input channel parameter error - * @arg '8' module does not support function + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setChannelDutyCycle(uint8_t channel, uint16_t dcycle) +uint8_t WaspLoRaWAN::setRetries(uint8_t retries) { - uint8_t status; - float dutycycle; + uint8_t status; char ans1[15]; char ans2[15]; @@ -2443,91 +3268,69 @@ uint8_t WaspLoRaWAN::setChannelDutyCycle(uint8_t channel, uint16_t dcycle) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - //check module (this function is only available for RN2483) - if (_version == RN2903_MODULE) - { - return LORAWAN_VERSION_ERROR; - } - - // check channel - if (channel > 15) return LORAWAN_INPUT_ERROR; - - // create "mac set ch dcycle" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[21])),channel,dcycle); + // create "mac set retx" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[69])),retries); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { - _dCycle[channel] = dcycle; + _retries = retries; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } -/*! - * @brief This function gets the operating duty channel on the given channel - * - * @param uint8_t channel - * - * @remarks The "dcycle" value obtained from the module helps us to calculate - * duty cycle percentage "X" using the following formula: - * dcycle = (100/X) – 1 +/*! + * @brief This function is used to read the power index from module * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '8' module does not support function + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getChannelDutyCycle(uint8_t channel) +uint8_t WaspLoRaWAN::getRetries() { - uint8_t status; - char ans1[50]; + uint8_t status; + char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); - //check module (this function is only available for RN2483) - if (_version == RN2903_MODULE) - { - return LORAWAN_VERSION_ERROR; - } - - // check channel - if (channel > 15) return LORAWAN_INPUT_ERROR; - - // create "mac get ch dcycle" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[36])),channel); + // create "mac get retx" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[70]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { - _dCycle[channel] = parseValue(10); + _retries = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } @@ -2536,72 +3339,47 @@ uint8_t WaspLoRaWAN::getChannelDutyCycle(uint8_t channel) -/*! - * @brief This function sets the data rate range on the given channel ID + + +/*! + * @brief This function gets current band of operation * - * @param uint8_t minDR: datarate to be set - * uint8_t maxDR: datarate to be set - * uint8_t channel: channel to be set - * @remarks - * For RN2483: - * minDR [0..5] - * maxDR [0..5] - * channel [0..15] - * For RN2903: - * minDR [0..3] - * maxDR [0..3] - * channel [0..63] - * @return + * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module + * @arg '8' module does not support function */ -uint8_t WaspLoRaWAN::setChannelDRRange(uint8_t channel, uint8_t minDR, uint8_t maxDR) +uint8_t WaspLoRaWAN::getBand() { uint8_t status; char ans1[15]; char ans2[15]; - + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - switch (_version) + //check module (this function is only available for RN2483) + if (_version == RN2903_MODULE) { - case RN2483_MODULE: - if ((channel > 15) || (minDR > 5) || (maxDR > 5)) - { - return LORAWAN_INPUT_ERROR; - } - break; - - case RN2903_MODULE: - if ((channel > 63) || (minDR > 3) || (maxDR > 3)) - { - return LORAWAN_INPUT_ERROR; - } - break; - - default: - return LORAWAN_VERSION_ERROR; - } + return LORAWAN_VERSION_ERROR; + } - // create "mac set ch drrange" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[22])),channel,minDR,maxDR); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "mac get band" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[28]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); + status = sendCommand(_command,ans1,ans2,300); if (status == 1) { - _drrMin[channel] = minDR; - _drrMax[channel] = maxDR; + memset(_band, 0x00, sizeof(_band)); + strncpy(_band,(char*)_buffer, sizeof(_band)); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -2616,97 +3394,59 @@ uint8_t WaspLoRaWAN::setChannelDRRange(uint8_t channel, uint8_t minDR, uint8_t m /*! - * @brief This function gets the data rate range on the given channel + * @brief This function gets the demodulation margin from the module * - * @param uint8_t channel - * For RN2483: channel [0..15] - * For RN2903: channel [0..71] * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::getChannelDRRange(uint8_t channel) +uint8_t WaspLoRaWAN::getMargin() { uint8_t status; - char ans1[50]; + char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - switch (_version) - { - case RN2483_MODULE: - if (channel > 15) - { - return LORAWAN_INPUT_ERROR; - } - break; - - case RN2903_MODULE: - if (channel > 71) - { - return LORAWAN_INPUT_ERROR; - } - break; - - default: - return LORAWAN_VERSION_ERROR; - } - - // create "mac get ch drrange" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[37])),channel); + // create "mac get mrgn" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[32]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - - //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - if (status == 1) - { - char * pch; - pch = strtok((char*) _buffer," \r\n"); - if (pch != NULL) - { - _drrMin[channel] = strtoul(pch,NULL, 10); - pch = strtok(NULL," \r\n"); - if (pch != NULL) - { - _drrMax[channel] = strtoul(pch,NULL, 10); - pch = strtok(pch," \r\n"); - return LORAWAN_ANSWER_OK; - } - return LORAWAN_ANSWER_ERROR; - } - return LORAWAN_ANSWER_ERROR; + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,300); + + if (status == 1) + { + uint8_t value = parseValue(10); + _margin = value; + return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - /*! - * @brief This function sets the status on the given channel ID - * - * @param char* state: state "on"/"off" - * uint8_t channel: channel to be set [0..15] - * + * @brief This function gets the number of gateways that successfully + * received the last Linck Check Request from the module + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::setChannelStatus(uint8_t channel, char* state) +uint8_t WaspLoRaWAN::getGatewayNumber() { uint8_t status; char ans1[15]; @@ -2716,34 +3456,55 @@ uint8_t WaspLoRaWAN::setChannelStatus(uint8_t channel, char* state) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // check state - if ((strcmp(state, "on")) && (strcmp(state, "off"))) return LORAWAN_INPUT_ERROR; + // create "mac get gwnb" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[33]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - switch (_version) + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,300); + + if (status == 1) { - case RN2483_MODULE: - if (channel > 15) - { - return LORAWAN_INPUT_ERROR; - } - break; - - case RN2903_MODULE: - if (channel > 71) - { - return LORAWAN_INPUT_ERROR; - } - break; - - default: - return LORAWAN_VERSION_ERROR; + _gwNumber = parseValue(10); + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; } + else + { + return LORAWAN_NO_ANSWER; + } +} + + +/*! + * @brief This function sets the value of the uplink frame counter that will + * be used for the next uplink transmission. + * + * @param uint8_t counter: + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::setUpCounter(uint32_t counter) +{ + uint8_t status; + char ans1[15]; + char ans2[15]; + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set ch state" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[23])),channel,state); + // create "mac set upctr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[72])),counter); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -2754,110 +3515,125 @@ uint8_t WaspLoRaWAN::setChannelStatus(uint8_t channel, char* state) if (status == 1) { - _status[channel] = state; + _upCounter = counter; + saveConfig(); return LORAWAN_ANSWER_OK; } - else if (status == 2) + else if(status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - -/*! - * @brief This function gets the status of the given channel - * - * @param uint8_t channel +/*! + * @brief This function is used to get the value of the uplink frame counter + * that will be used for the next uplink transmission. * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getChannelStatus(uint8_t channel) +uint8_t WaspLoRaWAN::getUpCounter() { - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; - char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - memset(ans3,0x00,sizeof(ans3)); - switch (_version) + // create "mac get upctr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[73]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,100); + + if (status == 1) { - case RN2483_MODULE: - if (channel > 15) - { - return LORAWAN_INPUT_ERROR; - } - break; - - case RN2903_MODULE: - if (channel > 71) - { - return LORAWAN_INPUT_ERROR; - } - break; - - default: - return LORAWAN_VERSION_ERROR; + _upCounter = parseValue(10); + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; } +} + + +/*! + * @brief This function sets the value of the downlink frame counter that will + * be used for the next downlink transmission. + * + * @param uint8_t counter: + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::setDownCounter(uint32_t counter) +{ + uint8_t status; + char ans1[15]; + char ans2[15]; - // create "mac get ch status" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[38])),channel); - // create "on" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); - // create "off" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "mac set dnctr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[74])),counter); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _status[channel] = true; - return LORAWAN_ANSWER_OK; - } - if (status == 2) - { - _status[channel] = false; + _downCounter = counter; + saveConfig(); return LORAWAN_ANSWER_OK; } - else if (status == 3) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - /*! - * @brief This function is used to configure number of retransmisions - * for an uplink confirmed packet + * @brief This function sets the time interval for the link check + * process to be triggered periodically * - * @param uint8_t retries: number of retries [0..255] + * @param uint8_t counter: * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRetries(uint8_t retries) +uint8_t WaspLoRaWAN::setLinkCheck(uint16_t time) { uint8_t status; char ans1[15]; @@ -2867,19 +3643,18 @@ uint8_t WaspLoRaWAN::setRetries(uint8_t retries) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set retx" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[69])),retries); + // create "mac set dnctr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[77])),time); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,100); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _retries = retries; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -2894,32 +3669,37 @@ uint8_t WaspLoRaWAN::setRetries(uint8_t retries) /*! - * @brief This function is used to read the power index from module + * @brief This function is used to get the value of the downlink frame counter + * that will be used for the next downlink transmission. * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRetries() +uint8_t WaspLoRaWAN::getDownCounter() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "mac get retx" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[70]))); + // create "mac get dnctr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[75]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { - _retries = parseIntValue(); + _downCounter = parseValue(10); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -2933,46 +3713,84 @@ uint8_t WaspLoRaWAN::getRetries() } +//////////////////////////////////////////////////////////////////////////////// +// Radio P2P functions +//////////////////////////////////////////////////////////////////////////////// - - -/*! - * @brief This function gets current band of operation +/*! + * @brief Send a packet via radio * - * @return + * @param char* message: char array that will be send + * + * @remarks data is a sequence of digit representing the value of byte stream + * expressed in hexadecimal value (i.e. radio tx 12A435 – the payload + * is composed by the following byte stream: 0x12, 0xA4, 0x35 – 6 digit + * converted in 3 bytes). The maximum length of frame is 510 digit (255 Bytes) + * for LoRa modulation and 128 digit (64 bytes) FSK modulation + * + * @return * @arg '0' if OK - * @arg '1' if error + * @arg '1' if there was an error * @arg '2' if no answer - * @arg '8' module does not support function - */ -uint8_t WaspLoRaWAN::getBand() -{ + * @arg '7' if input parameter error + */ +uint8_t WaspLoRaWAN::sendRadio(char * message) +{ + char ans1[15]; + char ans2[15]; uint8_t status; - char ans1[50]; + // clear buffers memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - //check module (this function is only available for RN2483) - if (_version == RN2903_MODULE) + // check if payload is a hexadecimal string + for (uint8_t i=0;i '9')) && + ((message[i] < 'A') || (message[i] > 'F')) && + ((message[i] < 'a') || (message[i] > 'f'))) + { + return LORAWAN_INPUT_ERROR; + } + } - // create "mac get band" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[28]))); + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[40])), message); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); - + status = sendCommand(_command,ans1,ans2,600); + if (status == 1) { - memset(_band, 0x00, sizeof(_band)); - strncpy(_band,(char*)_buffer, sizeof(_band)); - return LORAWAN_ANSWER_OK; + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "radio_tx_ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[4]))); + // create "radio_err" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[12]))); + + //wait for response + status = waitFor(ans1,ans2,3000); + + if (status == 1) + { + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } } else if (status == 2) { @@ -2985,101 +3803,191 @@ uint8_t WaspLoRaWAN::getBand() } + /*! - * @brief This function gets the demodulation margin from the module - * + * @brief Receive a packet via radio + * + * @param uint32_t timeout: time to wait for data + * * @return * @arg '0' if OK - * @arg '1' if error - * @arg '2' if no answer + * @arg '1' if there was an error + * @arg '2' it no answer + * */ -uint8_t WaspLoRaWAN::getMargin() +uint8_t WaspLoRaWAN::receiveRadio(uint32_t timeout) +{ + uint8_t error; + uint8_t status; + char ans1[15]; + char ans2[15]; + char ans3[15]; + + //set watch dog radio to timeout + error = setRadioWDT(timeout); + if (error == 0) + { + //start radio receiving + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "radio rx" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[39]))); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,100); + + if (status == 1) + { + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "radio_rx " answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[7]))); + // create "\r\n" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "radio_err" answer + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[12]))); + + //wait for response + status = waitFor(ans1,ans3,timeout); + + if (status == 1) + { + //wait for response + status = waitFor(ans2,1000); + + _buffer[_length-1] = 0x00; + _buffer[_length-2] = 0x00; + _length -= 2; + + return LORAWAN_ANSWER_OK; + } + return LORAWAN_NO_ANSWER; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + } + return LORAWAN_NO_ANSWER; +} + + +/*! + * @brief This function is used to radiate continuous wave without any modulation + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' it no answer + */ +uint8_t WaspLoRaWAN::test_ON() { uint8_t status; - char ans1[50]; + char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "mac get mrgn" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[32]))); + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[41]))); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2); if (status == 1) { - uint8_t value = parseValue(10); - _margin = value; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } + /*! - * @brief This function gets the number of gateways that successfully - * received the last Linck Check Request from the module - * + * @brief Stops the continuous wave mode, this function works with module + * identical to "reset()" + * * @return * @arg '0' if OK - * @arg '1' if error - * @arg '2' if no answer + * @arg '1' if error + * @arg '2' it no answer + * */ -uint8_t WaspLoRaWAN::getGatewayNumber() +uint8_t WaspLoRaWAN::test_OFF() { - uint8_t status; - char ans1[50]; + uint8_t status; + char ans1[15]; + char ans2[15]; + char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); - // create "mac get gwnb" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[33]))); + // create "radio cw off" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[42]))); + // create "RN2483" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[5]))); + // create "RN2903" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[20]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,300); + status = sendCommand(_command,ans1,ans2,ans3); if (status == 1) { - _gwNumber = parseValue(10); + _version = RN2483_MODULE; return LORAWAN_ANSWER_OK; } else if (status == 2) + { + _version = RN2903_MODULE; + return LORAWAN_ANSWER_OK; + } + else if (status == 3) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } + /*! - * @brief This function sets the value of the uplink frame counter that will - * be used for the next uplink transmission. + * @brief This function is used to read the SNR for the last receive packet * - * @param uint8_t counter: - * - * @return + * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setUpCounter(uint32_t counter) +uint8_t WaspLoRaWAN::getRadioSNR() { - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; @@ -3087,23 +3995,26 @@ uint8_t WaspLoRaWAN::setUpCounter(uint32_t counter) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set upctr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[72])),counter); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "radio get snr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[65]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans status = sendCommand(_command,ans1,ans2,500); - + if (status == 1) { - _upCounter = counter; - saveConfig(); + _radioSNR = parseValue(10); + if (_radioSNR > 31) + { + _radioSNR = 64 - _radioSNR; + } return LORAWAN_ANSWER_OK; } - else if(status == 2) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } @@ -3114,61 +4025,67 @@ uint8_t WaspLoRaWAN::setUpCounter(uint32_t counter) } -/*! - * @brief This function is used to get the value of the uplink frame counter - * that will be used for the next uplink transmission. + +/*! * - * @return + * @brief This function sets spreading factor for radio mode + * + * @param char* sprfact: spreading factor to be set [SF7..SF12] + * + * + * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getUpCounter() +uint8_t WaspLoRaWAN::setRadioSF(char* sprfact) { - uint8_t status; + uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "mac get upctr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[73]))); + // create "radio set sf" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[46])),sprfact); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _upCounter = parseValue(10); return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } + + /*! - * @brief This function sets the value of the downlink frame counter that will - * be used for the next downlink transmission. + * @brief This function gets the operating radio spreading factor from module * - * @param uint8_t counter: - * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setDownCounter(uint32_t counter) +uint8_t WaspLoRaWAN::getRadioSF() { - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; @@ -3176,10 +4093,10 @@ uint8_t WaspLoRaWAN::setDownCounter(uint32_t counter) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set dnctr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[74])),counter); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "radio get sf" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[59]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); @@ -3188,8 +4105,8 @@ uint8_t WaspLoRaWAN::setDownCounter(uint32_t counter) if (status == 1) { - _downCounter = counter; - saveConfig(); + memset(_radioSF,0x00,sizeof(_radioSF)); + strncpy(_radioSF,(char*)_buffer,sizeof(_radioSF)); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3202,29 +4119,47 @@ uint8_t WaspLoRaWAN::setDownCounter(uint32_t counter) } } + + /*! - * @brief This function sets the time interval for the link check - * process to be triggered periodically * - * @param uint8_t counter: + * @brief This function sets tx power for radio mode * - * @return + * @param uint8_t pwr: power to be set [-3..15] + * + * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::setLinkCheck(uint16_t time) +uint8_t WaspLoRaWAN::setRadioPower(int8_t pwr) { - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; + // create "radio set pwr" command memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "mac set dnctr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[77])),time); + switch (_version) + { + case RN2483_MODULE: + if ((pwr < -3) || (pwr > 15)) return LORAWAN_INPUT_ERROR; + break; + + case RN2903_MODULE: + if ((pwr < 2) || (pwr > 20)) return LORAWAN_INPUT_ERROR; + break; + + default: + return LORAWAN_VERSION_ERROR; + } + + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[45])),pwr); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -3235,47 +4170,51 @@ uint8_t WaspLoRaWAN::setLinkCheck(uint16_t time) if (status == 1) { + _radioPower = pwr; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } -/*! - * @brief This function is used to get the value of the downlink frame counter - * that will be used for the next downlink transmission. +/*! + * @brief This function gets the operating radio power from module * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getDownCounter() +uint8_t WaspLoRaWAN::getRadioPower() { - uint8_t status; + uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "mac get dnctr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[75]))); + // create "radio get pwr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[58]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _downCounter = parseValue(10); + _radioPower = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3289,90 +4228,47 @@ uint8_t WaspLoRaWAN::getDownCounter() } -//////////////////////////////////////////////////////////////////////////////// -// Radio P2P functions -//////////////////////////////////////////////////////////////////////////////// - - /*! - * @brief Send a packet via radio - * - * @param char* message: char array that will be send - * - * @remarks data is a sequence of digit representing the value of byte stream - * expressed in hexadecimal value (i.e. radio tx 12A435 – the payload - * is composed by the following byte stream: 0x12, 0xA4, 0x35 – 6 digit - * converted in 3 bytes). The maximum length of frame is 510 digit (255 Bytes) - * for LoRa modulation and 128 digit (64 bytes) FSK modulation + * @brief This function sets the operating mode for transceiver use + * + * @param char* mode: "lora"/"fsk" * * @return * @arg '0' if OK - * @arg '1' if there was an error + * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::sendRadio(char * message) -{ - char ans1[15]; - char ans2[15]; +uint8_t WaspLoRaWAN::setRadioMode(char* mode) +{ uint8_t status; + char ans1[50]; + char ans2[50]; - // clear buffers memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // check if payload is a hexadecimal string - for (uint8_t i=0;i '9')) && - ((message[i] < 'A') || (message[i] > 'F')) && - ((message[i] < 'a') || (message[i] > 'f'))) - { - return LORAWAN_INPUT_ERROR; - } - } - - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[40])), message); + // create "radio set mod" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[43])),mode); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,600); - + status = sendCommand(_command,ans1,ans2,300); + if (status == 1) { - memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); - - // create "radio_tx_ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[4]))); - // create "radio_err" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[12]))); - - //wait for response - status = waitFor(ans1,ans2,3000); - - if (status == 1) - { - return LORAWAN_ANSWER_OK; - } - else if (status == 2) - { - return LORAWAN_ANSWER_ERROR; - } - else - { - return LORAWAN_NO_ANSWER; - } + memset(_radioMode, 0x00, sizeof(_radioMode)); + strncpy(_radioMode,mode,sizeof(_radioMode)); + return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } @@ -3381,171 +4277,229 @@ uint8_t WaspLoRaWAN::sendRadio(char * message) /*! - * @brief Receive a packet via radio - * - * @param uint32_t timeout: time to wait for data + * @brief This function gets the operating radio mode from module * * @return * @arg '0' if OK - * @arg '1' if there was an error - * @arg '2' it no answer - * + * @arg '1' if error + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::receiveRadio(uint32_t timeout) +uint8_t WaspLoRaWAN::getRadioMode() { - uint8_t error; - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; - char ans3[15]; - - //set watch dog radio to timeout - error = setRadioWDT(timeout); - if (error == 0) + + memset(_command,0x00,sizeof(_command)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + + // create "radio get mod" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[56]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + + if (status == 1) { - //start radio receiving - memset(_command,0x00,sizeof(_command)); - memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); - - // create "radio rx" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[39]))); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - - //send command and wait for ans - status = sendCommand(_command,ans1,ans2,100); - - if (status == 1) - { - memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); - - // create "radio_rx " answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[7]))); - // create "\r\n" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); - // create "radio_err" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[12]))); - - //wait for response - status = waitFor(ans1,ans3,timeout); - - if (status == 1) - { - //wait for response - status = waitFor(ans2,1000); - - _buffer[_length-1] = 0x00; - _buffer[_length-2] = 0x00; - _length -= 2; - - return LORAWAN_ANSWER_OK; - } - return LORAWAN_NO_ANSWER; - } - else if (status == 2) - { - return LORAWAN_ANSWER_ERROR; - } + memset(_radioMode,0x00,sizeof(_radioMode)); + strncpy(_radioMode, (char*)_buffer, sizeof(_radioMode)); + return LORAWAN_ANSWER_OK; + } + else if (status == 2) + { + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; } - return LORAWAN_NO_ANSWER; } - - + + /*! - * @brief This function is used to radiate continuous wave without any modulation - * + * @brief This function sets the operating frequency for transceiver use + * + * @param uint32_t freq: operating frequency [863250000..869750000] (RN2483) + * [433250000..434550000] + * uint32_t freq: operating frequency [923550000..927250000] (RN2903) * @return * @arg '0' if OK - * @arg '1' if error - * @arg '2' it no answer + * @arg '1' if error + * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::test_ON() +uint8_t WaspLoRaWAN::setRadioFreq(uint32_t freq) { uint8_t status; - char ans1[15]; - char ans2[15]; + char ans1[50]; + char ans2[50]; + switch (_version) + { + case RN2483_MODULE: + if (freq < 433250000) return LORAWAN_INPUT_ERROR; + if ((freq > 434550000)&&(freq < 863250000)) return LORAWAN_INPUT_ERROR; + if (freq > 869750000) return LORAWAN_INPUT_ERROR; + break; + + case RN2903_MODULE: + if ((freq < 902250000)||(freq > 927750000)) return LORAWAN_INPUT_ERROR; + break; + + default: + return LORAWAN_VERSION_ERROR; + } + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[41]))); + // create "radio set freq" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[44])),freq); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { + _radioFreq = freq; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } + + /*! - * @brief Stops the continuous wave mode, this function works with module - * identical to "reset()" + * @brief This function gets the operating radio frequency from module * * @return * @arg '0' if OK - * @arg '1' if error - * @arg '2' it no answer - * + * @arg '1' if error + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::test_OFF() +uint8_t WaspLoRaWAN::getRadioFreq() { - uint8_t status; + uint8_t status; char ans1[15]; char ans2[15]; - char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); - memset(ans3,0x00,sizeof(ans3)); - // create "radio cw off" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[42]))); - // create "RN2483" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[5]))); - // create "RN2903" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[20]))); + // create "radio get freq" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[57]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _version = RN2483_MODULE; + _radioFreq = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) { - _version = RN2903_MODULE; + return LORAWAN_ANSWER_ERROR; + } + else + { + return LORAWAN_NO_ANSWER; + } +} + + +/*! + * @brief This function sets the signal bandwidth for receiver use + * + * @param float bandwidth: [250,125,62.5,31.3,15.6,7.8,3.9,200,100,50,25, + * 12.5,6.3,3.1,166.7,83.3,41.7,20.8,10.4,5.2,2.6] + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::setRadioReceivingBW(float bandwidth) +{ + uint8_t status; + char bandw[6]; + char ans1[15]; + char ans2[15]; + char integer[4]; + char decimal[4]; + + memset(_command,0x00,sizeof(_command)); + memset(bandw,0x00,sizeof(bandw)); + memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(integer,0x00,sizeof(integer)); + memset(decimal,0x00,sizeof(decimal)); + + dtostrf (bandwidth,NULL,1,bandw); + + char* pch = strtok(bandw,".\r\n"); + snprintf(integer, sizeof(integer), "%s",pch); + pch = strtok(NULL,"\r\n"); + snprintf(decimal, sizeof(decimal), "%s",pch); + + if (decimal == "0") + { + // create "radio set rxbw" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[47])),integer); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + } + else + { + // create "radio set rxbw" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[48])),integer,decimal); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); + } + + if (status == 1) + { + _radioRxBW = bandwidth; return LORAWAN_ANSWER_OK; } - else if (status == 3) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } @@ -3554,14 +4508,14 @@ uint8_t WaspLoRaWAN::test_OFF() /*! - * @brief This function is used to read the SNR for the last receive packet + * @brief This function gets the operating receiving bandwidth from module * * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioSNR() +uint8_t WaspLoRaWAN::getRadioReceivingBW() { uint8_t status; char ans1[15]; @@ -3569,22 +4523,21 @@ uint8_t WaspLoRaWAN::getRadioSNR() memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get snr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[65]))); + // create "radio get rxbw" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[60]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); - + status = sendCommand(_command,ans1,ans2,500); + if (status == 1) { - _radioSNR = parseValue(10); - if (_radioSNR > 31) - { - _radioSNR = 64 - _radioSNR; - } + _radioRxBW = parseFloatValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3600,18 +4553,17 @@ uint8_t WaspLoRaWAN::getRadioSNR() /*! - * - * @brief This function sets spreading factor for radio mode + * @brief This function sets the FSK bit rate value for transceiver use * - * @param char* sprfact: spreading factor to be set [SF7..SF12] + * @param uint16_t bitrate: [0..65535] * - * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioSF(char* sprfact) +uint8_t WaspLoRaWAN::setRadioBitRateFSK(uint32_t bitrate) { uint8_t status; char ans1[15]; @@ -3621,8 +4573,11 @@ uint8_t WaspLoRaWAN::setRadioSF(char* sprfact) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "radio set sf" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[46])),sprfact); + //check bit rate + if ((bitrate > 300000)&&(bitrate < 1)) return LORAWAN_INPUT_ERROR; + + // create "radio set bitrate" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[49])),bitrate); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -3633,6 +4588,7 @@ uint8_t WaspLoRaWAN::setRadioSF(char* sprfact) if (status == 1) { + _radioBitRate = bitrate; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3649,33 +4605,36 @@ uint8_t WaspLoRaWAN::setRadioSF(char* sprfact) /*! - * @brief This function gets the operating radio spreading factor from module + * @brief This function gets the bit rate for FSK modulation from module * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioSF() +uint8_t WaspLoRaWAN::getRadioBitRateFSK() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get sf" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[59]))); + // create "radio get bitrate" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[61]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - memset(_radioSF,0x00,sizeof(_radioSF)); - strncpy(_radioSF,(char*)_buffer,sizeof(_radioSF)); + _radioBitRate = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3689,46 +4648,32 @@ uint8_t WaspLoRaWAN::getRadioSF() } - /*! - * - * @brief This function sets tx power for radio mode - * - * @param uint8_t pwr: power to be set [-3..15] + * @brief This function sets the frequency deviation for transceiver use * - * @return + * @param uint16_t freqdeviation: [0..65535] + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioPower(int8_t pwr) +uint8_t WaspLoRaWAN::setRadioFreqDeviation(uint32_t freqdeviation) { uint8_t status; char ans1[15]; char ans2[15]; - // create "radio set pwr" command memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - switch (_version) - { - case RN2483_MODULE: - if ((pwr < -3) || (pwr > 15)) return LORAWAN_INPUT_ERROR; - break; - - case RN2903_MODULE: - if ((pwr < 2) || (pwr > 20)) return LORAWAN_INPUT_ERROR; - break; - - default: - return LORAWAN_VERSION_ERROR; - } + //check freqdeviation + if (freqdeviation > 200000) return LORAWAN_INPUT_ERROR; - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[45])),pwr); + // create "radio set fdev" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[50])),freqdeviation); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -3739,47 +4684,50 @@ uint8_t WaspLoRaWAN::setRadioPower(int8_t pwr) if (status == 1) { - _radioPower = pwr; + _radioFreqDev = freqdeviation; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - /*! - * @brief This function gets the operating radio power from module - * + * @brief This function gets the frequency deviation from the module + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioPower() +uint8_t WaspLoRaWAN::getRadioFreqDeviation() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get pwr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[58]))); + // create "radio get fdev" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[71]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioPower = parseIntValue(); + _radioFreqDev = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3793,136 +4741,130 @@ uint8_t WaspLoRaWAN::getRadioPower() } + /*! - * @brief This function sets the operating mode for transceiver use + * @brief This function sets the CRC header state for transceiver use * - * @param char* mode: "lora"/"fsk" + * @param uint16_t state: "on"/"off" * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRadioMode(char* mode) +uint8_t WaspLoRaWAN::setRadioCRC(char* state) { uint8_t status; - char ans1[50]; - char ans2[50]; + char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "radio set mod" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[43])),mode); + // create "radio set crc" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[52])),state); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,300); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - memset(_radioMode, 0x00, sizeof(_radioMode)); - strncpy(_radioMode,mode,sizeof(_radioMode)); - return LORAWAN_ANSWER_OK; + if (state == ans1) _crcStatus = true; + else _crcStatus = false; + + return LORAWAN_ANSWER_OK; } - else if (status == 2) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - - /*! - * @brief This function gets the operating radio mode from module - * + * @brief This function gets the CRC header state from module + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioMode() +uint8_t WaspLoRaWAN::getRadioCRC() { uint8_t status; char ans1[15]; + char ans2[15]; + char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans3,0x00,sizeof(ans3)); - // create "radio get mod" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[56]))); + // create "radio get crc" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[66]))); + // create "on" anwser + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); + // create "off" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,ans3,500); if (status == 1) { - memset(_radioMode,0x00,sizeof(_radioMode)); - strncpy(_radioMode, (char*)_buffer, sizeof(_radioMode)); + _crcStatus = true; return LORAWAN_ANSWER_OK; } else if (status == 2) + { + _crcStatus = false; + return LORAWAN_ANSWER_OK; + } + else if (status == 3) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } + /*! - * @brief This function sets the operating frequency for transceiver use + * @brief This function sets the preamble length for transceiver use * - * @param uint32_t freq: operating frequency [863250000..869750000] (RN2483) - * [433250000..434550000] - * uint32_t freq: operating frequency [923550000..927250000] (RN2903) + * @param uint16_t length: preamble length [0..65535] + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::setRadioFreq(uint32_t freq) +uint8_t WaspLoRaWAN::setRadioPreamble(uint16_t length) { uint8_t status; - char ans1[50]; - char ans2[50]; + char ans1[15]; + char ans2[15]; - switch (_version) - { - case RN2483_MODULE: - if (freq < 433250000) return LORAWAN_INPUT_ERROR; - if ((freq > 434550000)&&(freq < 863250000)) return LORAWAN_INPUT_ERROR; - if (freq > 869750000) return LORAWAN_INPUT_ERROR; - break; - - case RN2903_MODULE: - if ((freq < 902250000)||(freq > 927750000)) return LORAWAN_INPUT_ERROR; - break; - - default: - return LORAWAN_VERSION_ERROR; - } - memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "radio set freq" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[44])),freq); + // create "radio set prlen" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[51])),length); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -3933,7 +4875,7 @@ uint8_t WaspLoRaWAN::setRadioFreq(uint32_t freq) if (status == 1) { - _radioFreq = freq; + _preambleLength = length; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3948,34 +4890,37 @@ uint8_t WaspLoRaWAN::setRadioFreq(uint32_t freq) - /*! - * @brief This function gets the operating radio frequency from module - * + * @brief This function gets the preamble length from module + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioFreq() +uint8_t WaspLoRaWAN::getRadioPreamble() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get freq" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[57]))); + // create "radio get prlen" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[67]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioFreq = parseIntValue(); + _preambleLength = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -3989,110 +4934,97 @@ uint8_t WaspLoRaWAN::getRadioFreq() } + + /*! - * @brief This function sets the signal bandwidth for receiver use + * @brief This function sets the coding rate for transceiver use * - * @param float bandwidth: [250,125,62.5,31.3,15.6,7.8,3.9,200,100,50,25, - * 12.5,6.3,3.1,166.7,83.3,41.7,20.8,10.4,5.2,2.6] + * @param char* codingrate: "4/5","4/6","4/7","4/8" * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRadioReceivingBW(float bandwidth) +uint8_t WaspLoRaWAN::setRadioCR(char* codingrate) { uint8_t status; - char bandw[6]; char ans1[15]; char ans2[15]; - char integer[4]; - char decimal[4]; - + memset(_command,0x00,sizeof(_command)); - memset(bandw,0x00,sizeof(bandw)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - memset(integer,0x00,sizeof(integer)); - memset(decimal,0x00,sizeof(decimal)); - - dtostrf (bandwidth,NULL,1,bandw); - char* pch = strtok(bandw,".\r\n"); - snprintf(integer, sizeof(integer), "%s",pch); - pch = strtok(NULL,"\r\n"); - snprintf(decimal, sizeof(decimal), "%s",pch); + // create "radio set cr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[53])),codingrate); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "invalid_param" answer + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + + //send command and wait for ans + status = sendCommand(_command,ans1,ans2,500); - if (decimal == "0") - { - // create "radio set rxbw" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[47])),integer); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - - //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); - } - else - { - // create "radio set rxbw" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[48])),integer,decimal); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - - //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); - } - if (status == 1) { - _radioRxBW = bandwidth; + memset(_radioCR, 0x00, sizeof(_radioCR)); + strncpy(_radioCR,codingrate,sizeof(_radioCR)); return LORAWAN_ANSWER_OK; } - else if (status == 2) + else if (status == 2) { - return LORAWAN_ANSWER_ERROR; + return LORAWAN_NO_ANSWER; } - else + else { - return LORAWAN_NO_ANSWER; + return LORAWAN_ANSWER_ERROR; } } /*! - * @brief This function gets the operating receiving bandwidth from module + * @brief This function gets the operating coding rate from module * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioReceivingBW() +uint8_t WaspLoRaWAN::getRadioCR() { uint8_t status; char ans1[15]; - + char ans2[15]; + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get rxbw" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[60]))); + // create "radio get cr" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[62]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,100); if (status == 1) { - _radioRxBW = parseFloatValue(); - return LORAWAN_ANSWER_OK; + char* pch = strtok((char*)_buffer,ans1); + if (pch != NULL) + { + memset(_radioCR, 0x00, sizeof(_radioCR)); + strncpy(_radioCR, pch, sizeof(_radioCR)); + return LORAWAN_ANSWER_OK; + } + else + { + return LORAWAN_ANSWER_ERROR; + } } else if (status == 2) { @@ -4107,17 +5039,16 @@ uint8_t WaspLoRaWAN::getRadioReceivingBW() /*! - * @brief This function sets the FSK bit rate value for transceiver use + * @brief This function sets the time for the radio watch dog timer * - * @param uint16_t bitrate: [0..65535] + * @param uint32_t time: [0..4294967295] time in milliseconds * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioBitRateFSK(uint32_t bitrate) +uint8_t WaspLoRaWAN::setRadioWDT(uint32_t time) { uint8_t status; char ans1[15]; @@ -4127,11 +5058,8 @@ uint8_t WaspLoRaWAN::setRadioBitRateFSK(uint32_t bitrate) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - //check bit rate - if ((bitrate > 300000)&&(bitrate < 1)) return LORAWAN_INPUT_ERROR; - - // create "radio set bitrate" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[49])),bitrate); + // create "radio set wdt" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[54])),time); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -4142,14 +5070,14 @@ uint8_t WaspLoRaWAN::setRadioBitRateFSK(uint32_t bitrate) if (status == 1) { - _radioBitRate = bitrate; + _radioWDT = time; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } @@ -4157,34 +5085,37 @@ uint8_t WaspLoRaWAN::setRadioBitRateFSK(uint32_t bitrate) - /*! - * @brief This function gets the bit rate for FSK modulation from module + * @brief This function gets the watch dog timer's time from module * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioBitRateFSK() +uint8_t WaspLoRaWAN::getRadioWDT() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get bitrate" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[61]))); + // create "radio get wdt" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[63]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioBitRate = parseIntValue(); + _radioWDT = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -4198,18 +5129,19 @@ uint8_t WaspLoRaWAN::getRadioBitRateFSK() } + /*! - * @brief This function sets the frequency deviation for transceiver use + * @brief This function sets the bandwidth for transceiver use * - * @param uint16_t freqdeviation: [0..65535] + * @param uint16_t bandwitdh: 125,250,500 * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer - * @arg '7' if input parameter error + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioFreqDeviation(uint32_t freqdeviation) +uint8_t WaspLoRaWAN::setRadioBW(uint16_t bandwidth) { uint8_t status; char ans1[15]; @@ -4219,11 +5151,12 @@ uint8_t WaspLoRaWAN::setRadioFreqDeviation(uint32_t freqdeviation) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - //check freqdeviation - if (freqdeviation > 200000) return LORAWAN_INPUT_ERROR; + //check bandwidth + if ((bandwidth == 125) || (bandwidth == 250) || (bandwidth == 500)){} + else return LORAWAN_INPUT_ERROR; - // create "radio set fdev" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[50])),freqdeviation); + // create "radio set bw" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[55])),bandwidth); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -4234,7 +5167,7 @@ uint8_t WaspLoRaWAN::setRadioFreqDeviation(uint32_t freqdeviation) if (status == 1) { - _radioFreqDev = freqdeviation; + _radioBW = bandwidth; return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -4247,33 +5180,40 @@ uint8_t WaspLoRaWAN::setRadioFreqDeviation(uint32_t freqdeviation) } } + + + /*! - * @brief This function gets the frequency deviation from the module - * + * @brief This function gets the operating radio bandwidth from module + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioFreqDeviation() +uint8_t WaspLoRaWAN::getRadioBW() { uint8_t status; char ans1[15]; + char ans2[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get fdev" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[71]))); + // create "radio get bw" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[64]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioFreqDev = parseIntValue(); + _radioBW = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -4287,20 +5227,28 @@ uint8_t WaspLoRaWAN::getRadioFreqDeviation() } - /*! - * @brief This function sets the CRC header state for transceiver use - * - * @param uint16_t state: "on"/"off" + * @brief This function sets data rate and frecuency used for the + * second receive window. + * + * @remarks The configuration of the receive window parameters should + * be in concordance with the server configuration + * + * @param uint8_t datarate: datarate to be set [0..5] + * uint32_t frequency: frequency to be set [863000000..870000000] + * [433050000..434790000] * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer + * @arg '7' if input parameter error + * @arg '8' unrecognized module */ -uint8_t WaspLoRaWAN::setRadioCRC(char* state) +uint8_t WaspLoRaWAN::setRX2Parameters(uint8_t datarate, uint32_t frequency) { uint8_t status; + float dutycycle; char ans1[15]; char ans2[15]; @@ -4308,24 +5256,44 @@ uint8_t WaspLoRaWAN::setRadioCRC(char* state) memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "radio set crc" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[52])),state); + switch (_version) + { + case RN2483_MODULE: + if (datarate > 7) return LORAWAN_INPUT_ERROR; + if (frequency < 433250000) return LORAWAN_INPUT_ERROR; + if ((frequency > 434550000)&&(frequency < 863250000)) return LORAWAN_INPUT_ERROR; + if (frequency > 869750000) return LORAWAN_INPUT_ERROR; + break; + + case RN2903_MODULE: + if ((datarate > 13) || (datarate < 8)) + { + return LORAWAN_INPUT_ERROR; + } + if ((frequency < 923550000) || (frequency > 927250000)) return LORAWAN_INPUT_ERROR; + break; + + default: + return LORAWAN_VERSION_ERROR; + } + + // create "mac set rx2" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[78])),datarate,frequency); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); + status = sendCommand(_command,ans1,ans2); if (status == 1) { - if (state == ans1) _crcStatus = true; - else _crcStatus = false; - + _rx2DataRate = datarate; + _rx2Frequency = frequency; return LORAWAN_ANSWER_OK; } - else if (status == 2) + else if (status == 2) { return LORAWAN_ANSWER_ERROR; } @@ -4335,49 +5303,48 @@ uint8_t WaspLoRaWAN::setRadioCRC(char* state) } } + /*! - * @brief This function gets the CRC header state from module - * + * @brief This function sets the delay used for the first receive window + * + * @param uint16_t delay: delay to be set [0..65535] + * + * @remarks The "dcycle" value that needs to be configured can be obtained + * from the actual duty cycle X (in percentage) using the following formula: + * dcycle = (100/X) – 1 + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioCRC() +uint8_t WaspLoRaWAN::setRX1Delay(uint16_t delay) { uint8_t status; + float dutycycle; char ans1[15]; char ans2[15]; - char ans3[15]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - memset(ans3,0x00,sizeof(ans3)); - // create "radio get crc" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[66]))); - // create "on" anwser - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); - // create "off" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); + // create "mac set rx1delay" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[79])),delay); + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer - sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,ans3,500); + status = sendCommand(_command,ans1,ans2); if (status == 1) { - _crcStatus = true; + _rx1Delay = delay; return LORAWAN_ANSWER_OK; } else if (status == 2) - { - _crcStatus = false; - return LORAWAN_ANSWER_OK; - } - else if (status == 3) { return LORAWAN_ANSWER_ERROR; } @@ -4390,214 +5357,245 @@ uint8_t WaspLoRaWAN::getRadioCRC() /*! - * @brief This function sets the preamble length for transceiver use - * - * @param uint16_t length: preamble length [0..65535] + * @brief This function gets MAC status from the module + * + * @remarks This functino is necessary before showing MAC status with + * showMACStatus() function * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRadioPreamble(uint16_t length) +uint8_t WaspLoRaWAN::getMACStatus() { uint8_t status; char ans1[15]; - char ans2[15]; + char carr[5]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); + memset(carr,0x00,sizeof(carr)); - // create "radio set prlen" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[51])),length); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "mac get status" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[81]))); // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); - + status = sendCommand(_command,"000",ans1); + if (status == 1) { - _preambleLength = length; + status = waitFor(carr,ans1); + char* pointer = strtok((char*)_buffer,carr); + memset(ans1,0x00,sizeof(ans1)); + memcpy(ans1,pointer,sizeof(ans1)); + uint8_t aux[5]; + for (uint8_t i=0; i<5; i++) + { + if (ans1[i]>='0' && ans1[i]<='9') + { + aux[4-i] = ans1[i] - '0'; + } + else if (ans1[i]>='A' && ans1[i]<='F') + { + aux[4-i] = ans1[i] - 'A' + 10; + } + else + { + return LORAWAN_ANSWER_ERROR; + } + } + + _macStatus = (aux[4]*(16^4))+(aux[3]*(16^3))+(aux[2]*(16^2))+(aux[1]*16)+aux[0]; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - /*! - * @brief This function gets the preamble length from module - * + * @brief This function returns MAC status verbose + * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioPreamble() +uint8_t WaspLoRaWAN::showMACStatus() { - uint8_t status; - char ans1[15]; + if (_macStatus&0x01) USB.println(F("Module joined to a network")); + else USB.println(F("Module not joined to a network")); + + if (_macStatus&0x10) USB.println(F("Automatic reply status enabled")); + else USB.println(F("Automatic reply status disabled")); - memset(_command,0x00,sizeof(_command)); - memset(ans1,0x00,sizeof(ans1)); + if (_macStatus&0x20) USB.println(F("ADR status enabled")); + else USB.println(F("ADR status disabled")); - // create "radio get prlen" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[67]))); - // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + if (_macStatus&0x40) USB.println(F("Silent inmediately status enabled")); + else USB.println(F("Silent inmediately status disabled")); - //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + if (_macStatus&0x80) USB.println(F("MAC paused")); + else USB.println(F("MAC not paused")); + + if (_macStatus&0x200) USB.println(F("Link check status enabled")); + else USB.println(F("Link check status disabled")); + + if (_macStatus&0x400) USB.println(F("Channels updated via NewChannelReq or CFList")); + else USB.println(F("Channels not updated")); + + if (_macStatus&0x800) USB.println(F("Output power updated")); + else USB.println(F("Output power not updated")); + + if (_macStatus&0x1000) USB.println(F("Number of repetitions updated")); + else USB.println(F("Number of repetitions not updated")); + + if (_macStatus&=0x2000) USB.println(F("Prescaler updated")); + else USB.println(F("Prescaler not updated")); + + if (_macStatus&=0x4000) USB.println(F("RX2 window parameter updated")); + else USB.println(F("RX2 window not updated")); + + if (_macStatus&=0x8000) USB.println(F("TX timing updated")); + else USB.println(F("TX timing not updated")); + + if (_macStatus&=0x10000) USB.println(F("Rejoin needed")); + else USB.println(F("End device functional")); - if (status == 1) - { - _preambleLength = parseIntValue(); - return LORAWAN_ANSWER_OK; - } - else if (status == 2) - { - return LORAWAN_ANSWER_ERROR; - } - else - { - return LORAWAN_NO_ANSWER; - } } +void WaspLoRaWAN::convertString(char* string2convert, char* outputString) +{ + Utils.hex2str((uint8_t*)string2convert, outputString, strlen(string2convert)); +} +void WaspLoRaWAN::convertString(uint8_t* string2convert, char* outputString) +{ + Utils.hex2str(string2convert, outputString, strlen((char*)string2convert)); +} +/*! + * @brief This function puts the module to sleep + * + * @return + * @arg '0' if OK + * @arg '1' if error + * @arg '2' if no answer + */ +uint8_t WaspLoRaWAN::sleep() +{ + return sleep(4294967295); +} /*! - * @brief This function sets the coding rate for transceiver use - * - * @param char* codingrate: "4/5","4/6","4/7","4/8" + * @brief This function puts the module to sleep + * + * @param uint32_t time: 100..4294967295 * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRadioCR(char* codingrate) +uint8_t WaspLoRaWAN::sleep(uint32_t time) { uint8_t status; - char ans1[15]; - char ans2[15]; + char ans1[25]; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); - // create "radio set cr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[53])),codingrate); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "mac get status" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[84])),time); // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2,500); - + status = sendCommand(_command,ans1,1000); + if (status == 1) { - memset(_radioCR, 0x00, sizeof(_radioCR)); - strncpy(_radioCR,codingrate,sizeof(_radioCR)); - return LORAWAN_ANSWER_OK; - } - else if (status == 2) - { - return LORAWAN_NO_ANSWER; - } - else - { - return LORAWAN_ANSWER_ERROR; + return 1; } + return 0; } - - /*! - * @brief This function gets the operating coding rate from module + * @brief This function force the module to wake up * * @return * @arg '0' if OK * @arg '1' if error * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::getRadioCR() +uint8_t WaspLoRaWAN::wakeUp() { uint8_t status; - char ans1[15]; - - memset(_command,0x00,sizeof(_command)); + char ans1[25]; + memset(ans1,0x00,sizeof(ans1)); - // create "radio get cr" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[62]))); - // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + beginUART(); + + // create "ok" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,100); + printByte(0x00,_uart); + printByte(0x55,_uart); + + delay(500); + + sleep(100); + status = waitFor(ans1,500); if (status == 1) { - char* pch = strtok((char*)_buffer,"\r\n"); - if (pch != NULL) - { - memset(_radioCR, 0x00, sizeof(_radioCR)); - strncpy(_radioCR, pch, sizeof(_radioCR)); - return LORAWAN_ANSWER_OK; - } - else - { - return LORAWAN_ANSWER_ERROR; - } + return LORAWAN_ANSWER_OK; } - else if (status == 2) + else { return LORAWAN_ANSWER_ERROR; } - else - { - return LORAWAN_NO_ANSWER; - } } - -/*! - * @brief This function sets the time for the radio watch dog timer - * - * @param uint32_t time: [0..4294967295] time in milliseconds +/*! + * @brief This function is used to set the automatic reply status from module * - * @return + * @param char* state: "on"/"off" + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioWDT(uint32_t time) +uint8_t WaspLoRaWAN::setAR(char* state) { uint8_t status; char ans1[15]; char ans2[15]; + + // check state + if ((strcmp(state, "on")) && (strcmp(state, "off"))) return LORAWAN_INPUT_ERROR; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - // create "radio set wdt" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[54])),time); + // create "mac set ar" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[85])),state); // create "ok" answer sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); // create "invalid_param" answer @@ -4605,54 +5603,68 @@ uint8_t WaspLoRaWAN::setRadioWDT(uint32_t time) //send command and wait for ans status = sendCommand(_command,ans1,ans2,500); - + if (status == 1) { - _radioWDT = time; + if (strcmp(state, "on") == 0) _ar = true; + if (strcmp(state, "off") == 0) _ar = false; return LORAWAN_ANSWER_OK; } else if (status == 2) { return LORAWAN_ANSWER_ERROR; } - else + else { return LORAWAN_NO_ANSWER; } } - -/*! - * @brief This function gets the watch dog timer's time from module +/*! + * @brief This function is used to get the automatic reply status from module * - * @return + * @param char* state: "on"/"off" + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::getRadioWDT() +uint8_t WaspLoRaWAN::getAR() { uint8_t status; char ans1[15]; - + char ans2[15]; + char ans3[15]; + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); + memset(ans2,0x00,sizeof(ans3)); - // create "radio get wdt" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[63]))); + // create "mac get ar" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[86]))); + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[9]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[10]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans3,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,ans3,500); if (status == 1) { - _radioWDT = parseIntValue(); + _ar = true; return LORAWAN_ANSWER_OK; } else if (status == 2) + { + _ar = false; + return LORAWAN_ANSWER_OK; + } + else if (status == 3) { return LORAWAN_ANSWER_ERROR; } @@ -4663,45 +5675,38 @@ uint8_t WaspLoRaWAN::getRadioWDT() } - -/*! - * @brief This function sets the bandwidth for transceiver use - * - * @param uint16_t bandwitdh: 125,250,500 +/*! + * @brief This function is used to get the first receive window delay * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input parameter error + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRadioBW(uint16_t bandwidth) +uint8_t WaspLoRaWAN::getRX1Delay() { uint8_t status; char ans1[15]; char ans2[15]; - + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - //check bandwidth - if ((bandwidth == 125) || (bandwidth == 250) || (bandwidth == 500)){} - else return LORAWAN_INPUT_ERROR; - - // create "radio set bw" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[55])),bandwidth); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "mac get rxdelay1" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[87]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); - + //send command and wait for ans status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioBW = bandwidth; + _rx1Delay = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -4715,35 +5720,38 @@ uint8_t WaspLoRaWAN::setRadioBW(uint16_t bandwidth) } - - -/*! - * @brief This function gets the operating radio bandwidth from module +/*! + * @brief This function is used to get the second receive window delay * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::getRadioBW() +uint8_t WaspLoRaWAN::getRX2Delay() { uint8_t status; char ans1[15]; - + char ans2[15]; + memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); + memset(ans2,0x00,sizeof(ans2)); - // create "radio get bw" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[64]))); + // create "mac get rxdelay2" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[88]))); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,"\r\n",ans1,500); + status = sendCommand(_command,ans1,ans2,500); if (status == 1) { - _radioBW = parseIntValue(); + _rx2Delay = parseIntValue(); return LORAWAN_ANSWER_OK; } else if (status == 2) @@ -4757,71 +5765,56 @@ uint8_t WaspLoRaWAN::getRadioBW() } -/*! - * @brief This function sets data rate and frecuency used for the - * second receive window. - * - * @remarks The configuration of the receive window parameters should - * be in concordance with the server configuration +/*! + * @brief This function is used to set the automatic reply status from module * - * @param uint8_t datarate: datarate to be set [0..5] - * uint32_t frequency: frequency to be set [863000000..870000000] - * [433050000..434790000] + * @param char* state: "on"/"off" * - * @return + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer - * @arg '7' if input parameter error - * @arg '8' unrecognized module + * @arg '2' if no answer + * @arg '7' if input parameter error */ -uint8_t WaspLoRaWAN::setRX2Parameters(uint8_t datarate, uint32_t frequency) +uint8_t WaspLoRaWAN::getRX2Parameters(char* band) { uint8_t status; - float dutycycle; char ans1[15]; char ans2[15]; + + // check state + if ((strcmp(band, "868")) && (strcmp(band, "433"))) return LORAWAN_INPUT_ERROR; memset(_command,0x00,sizeof(_command)); memset(ans1,0x00,sizeof(ans1)); memset(ans2,0x00,sizeof(ans2)); - switch (_version) - { - case RN2483_MODULE: - if (datarate > 7) return LORAWAN_INPUT_ERROR; - if (frequency < 433250000) return LORAWAN_INPUT_ERROR; - if ((frequency > 434550000)&&(frequency < 863250000)) return LORAWAN_INPUT_ERROR; - if (frequency > 869750000) return LORAWAN_INPUT_ERROR; - break; - - case RN2903_MODULE: - if ((datarate > 13) || (datarate < 8)) - { - return LORAWAN_INPUT_ERROR; - } - if ((frequency < 923550000) || (frequency > 927250000)) return LORAWAN_INPUT_ERROR; - break; - - default: - return LORAWAN_VERSION_ERROR; - } - - // create "mac set rx2" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[78])),datarate,frequency); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); + // create "mac set ar" command + sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[89])),band); + // create "\r\n" answer + sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); // create "invalid_param" answer sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); //send command and wait for ans - status = sendCommand(_command,ans1,ans2); - + status = sendCommand(_command,ans1,ans2,500); + if (status == 1) { - _rx2DataRate = datarate; - _rx2Frequency = frequency; - return LORAWAN_ANSWER_OK; + char * pch; + pch = strtok((char*) _buffer," \r\n"); + if (pch != NULL) + { + _rx2DataRate = strtoul(pch,NULL, 10); + pch = strtok(NULL,"\r\n"); + if (pch != NULL) + { + _rx2Frequency = strtoul(pch,NULL, 10); + return LORAWAN_ANSWER_OK; + } + return LORAWAN_ANSWER_ERROR; + } + return LORAWAN_ANSWER_ERROR; } else if (status == 2) { @@ -4834,57 +5827,77 @@ uint8_t WaspLoRaWAN::setRX2Parameters(uint8_t datarate, uint32_t frequency) } -/*! - * @brief This function sets the delay used for the first receive window - * - * @param uint16_t delay: delay to be set [0..65535] - * - * @remarks The "dcycle" value that needs to be configured can be obtained - * from the actual duty cycle X (in percentage) using the following formula: - * dcycle = (100/X) – 1 - * - * @return + + + +/*! + * @brief This function calculates the maximum payload for current settings + * + * @return * @arg '0' if OK * @arg '1' if error - * @arg '2' if no answer */ -uint8_t WaspLoRaWAN::setRX1Delay(uint16_t delay) +uint8_t WaspLoRaWAN::getMaxPayload() { - uint8_t status; - float dutycycle; - char ans1[15]; - char ans2[15]; - - memset(_command,0x00,sizeof(_command)); - memset(ans1,0x00,sizeof(ans1)); - memset(ans2,0x00,sizeof(ans2)); + uint8_t error; + _maxPayload = 0; - // create "mac set rx1delay" command - sprintf_P(_command,(char*)pgm_read_word(&(table_LoRaWAN_COMMANDS[79])),delay); - // create "ok" answer - sprintf_P(ans1,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[0]))); - // create "invalid_param" answer - sprintf_P(ans2,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[1]))); + // get current data rate + error = getDataRate(); - //send command and wait for ans - status = sendCommand(_command,ans1,ans2); - - if (status == 1) - { - _rx1Delay = delay; - return LORAWAN_ANSWER_OK; - } - else if (status == 2) + if (error == 0) { - return LORAWAN_ANSWER_ERROR; + if (_version == RN2483_MODULE) + { + switch (_dataRate) + { + case 0: + case 1: + case 2: _maxPayload = 51; + break; + case 3: _maxPayload = 115; + break; + case 4: + case 5: + case 6: + case 7: _maxPayload = 242; + break; + default:_maxPayload = 0; + return 1; + break; + } + } + else if (_version == RN2903_MODULE) + { + switch (_dataRate) + { + case 0: _maxPayload = 11; + break; + case 1: _maxPayload = 53; + break; + case 2: _maxPayload = 129; + break; + case 3: + case 4: _maxPayload = 242; + break; + default:_maxPayload = 0; + return 1; + break; + } + } + else + { + return 1; + } } else { - return LORAWAN_NO_ANSWER; + return 1; } + + return 0; } - //////////////////////////////////////////////////////////////////////////////// // Private functions //////////////////////////////////////////////////////////////////////////////// @@ -4912,7 +5925,13 @@ uint32_t WaspLoRaWAN::parseValue(uint8_t base) uint32_t WaspLoRaWAN::parseIntValue() { char * pch; - pch = strtok((char*) _buffer,"\r\n"); + char carr[5]; + + memset(carr,0x00,sizeof(carr)); + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + + pch = strtok((char*) _buffer,carr); if (pch != NULL) { return atol(pch); @@ -4928,7 +5947,13 @@ uint32_t WaspLoRaWAN::parseIntValue() float WaspLoRaWAN::parseFloatValue() { char * pch; - pch = strtok((char*) _buffer,"\r\n"); + char carr[5]; + + memset(carr,0x00,sizeof(carr)); + // create "\r\n" answer + sprintf_P(carr,(char*)pgm_read_word(&(table_LoRaWAN_ANSWERS[13]))); + + pch = strtok((char*) _buffer,carr); if (pch != NULL) { return atof(pch); @@ -4937,7 +5962,5 @@ float WaspLoRaWAN::parseFloatValue() } - - // Preinstantiate Objects ///////////////////////////////////////////////////// WaspLoRaWAN LoRaWAN = WaspLoRaWAN(); diff --git a/libraries/LoRaWAN/WaspLoRaWAN.h b/libraries/LoRaWAN/WaspLoRaWAN.h index 9c5be92..f709a37 100755 --- a/libraries/LoRaWAN/WaspLoRaWAN.h +++ b/libraries/LoRaWAN/WaspLoRaWAN.h @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 0.3 + Version: 3.1 Design: David Gascón Implementation: Luis Miguel Martí @@ -74,6 +74,7 @@ class WaspLoRaWAN : public WaspUART public: bool _adr; + bool _ar; char _eui[17]; char _devEUI[17]; char _appEUI[17]; @@ -115,8 +116,10 @@ class WaspLoRaWAN : public WaspUART uint8_t _rx2DataRate; uint32_t _rx2Frequency; uint16_t _rx1Delay; + uint16_t _rx2Delay; uint8_t _version; - + uint32_t _macStatus; + uint8_t _maxPayload; // constructor WaspLoRaWAN() {}; @@ -178,7 +181,9 @@ class WaspLoRaWAN : public WaspUART uint8_t getDownCounter(); uint8_t setRX2Parameters(uint8_t datarate, uint32_t frequency); uint8_t setRX1Delay(uint16_t delay); - + uint8_t getMACStatus(); + uint8_t showMACStatus(); + // Radio functions uint8_t sendRadio(char * buff); uint8_t receiveRadio(uint32_t timeout); @@ -210,7 +215,20 @@ class WaspLoRaWAN : public WaspUART uint8_t setRadioBW(uint16_t bandwidth); uint8_t getRadioBW(); uint8_t setLinkCheck(uint16_t counter); - + void convertString(char* string2convert, char* outputString); + void convertString(uint8_t* string2convert, char* outputString); + uint8_t sendConfirmed(uint8_t port, uint8_t* payload, uint16_t length); + uint8_t sendUnconfirmed(uint8_t port, uint8_t* payload, uint16_t length); + uint8_t sleep(); + uint8_t sleep(uint32_t time); + uint8_t wakeUp(); + uint8_t setAR(char* state); + uint8_t getAR(); + uint8_t getRX1Delay(); + uint8_t getRX2Delay(); + uint8_t getRX2Parameters(char* band); + uint8_t getMaxPayload(); + private: // Utils uint32_t parseValue(uint8_t base); diff --git a/libraries/LoRaWAN/keywords.txt b/libraries/LoRaWAN/keywords.txt index dfe50f8..10b0849 100644 --- a/libraries/LoRaWAN/keywords.txt +++ b/libraries/LoRaWAN/keywords.txt @@ -1,6 +1,7 @@ -LoRaWAN KEYWORD3 +LoRaWAN KEYWORD1 WaspLoRaWAN KEYWORD2 _adr KEYWORD2 +_ar KEYWORD2 _eui KEYWORD2 _devEUI KEYWORD2 _appEUI KEYWORD2 @@ -58,6 +59,8 @@ sendConfirmed KEYWORD2 sendUnconfirmed KEYWORD2 getADR KEYWORD2 setADR KEYWORD2 +getAR KEYWORD2 +setAR KEYWORD2 getDutyCyclePrescaler KEYWORD2 macPause KEYWORD2 macResume KEYWORD2 @@ -117,6 +120,22 @@ setLinkCheck KEYWORD2 _port KEYWORD2 _data KEYWORD2 _dataReceived KEYWORD2 +_supplyPower KEYWORD2 +_rx2DataRate KEYWORD2 +_rx2Frequency KEYWORD2 +_rx1Delay KEYWORD2 +_version KEYWORD2 +_macStatus KEYWORD2 +getAddr KEYWORD2 +setRX2Parameters KEYWORD2 +setRX1Delay KEYWORD2 +getMACStatus KEYWORD2 +showMACStatus KEYWORD2 +setRadioReceivingBW KEYWORD2 +setRadioBitRateFSK KEYWORD2 +getRadioBitRateFSK KEYWORD2 +setRadioFreqDeviation KEYWORD2 +getRadioFreqDeviation KEYWORD2 LORAWAN_ANSWER_OK LITERAL1 LORAWAN_ANSWER_ERROR LITERAL1 @@ -125,3 +144,7 @@ LORAWAN_INIT_ERROR LITERAL1 LORAWAN_LENGTH_ERROR LITERAL1 LORAWAN_SENDING_ERROR LITERAL1 LORAWAN_NOT_JOINED LITERAL1 +LORAWAN_INPUT_ERROR LITERAL1 +LORAWAN_VERSION_ERROR LITERAL1 +RN2483_MODULE LITERAL1 +RN2903_MODULE LITERAL1 diff --git a/libraries/ModbusMaster/ModbusMaster.cpp b/libraries/ModbusMaster/ModbusMaster.cpp new file mode 100755 index 0000000..fc0ac33 --- /dev/null +++ b/libraries/ModbusMaster/ModbusMaster.cpp @@ -0,0 +1,943 @@ +/* + ModbusMaster.cpp - Waspmote library for communicating with Modbus slaves + over RS-232/485 (via RTU protocol). + This file is part of ModbusMaster. + + ModbusMaster is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ModbusMaster is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ModbusMaster. If not, see . + + Written by Doc Walker (Rx) + Copyright © 2009-2013 Doc Walker <4-20ma at wvfans dot net> + Modified for Waspmote by Libelium, 2016 + + Version: 3.1 +*/ + +#include "ModbusMaster.h" + + +#ifndef __WPROGRAM_H__ + #include "WaspClasses.h" +#endif + + +//************************************************************************************************** +// PUBLIC FUNCTIONS +//************************************************************************************************** + +/*********************************************************************** +Constructor. +Creates class object using default serial port 0, Modbus slave ID 1. + +@ingroup setup +************************************************************************/ +ModbusMaster::ModbusMaster() +{ + _protocol = RS485_COM; + _u8MBSlave = 0x00; +} + + +/*********************************************************************** +Constructor. +Creates class object using default serial port 0, Modbus slave ID 1. + +@ingroup setup +************************************************************************/ +ModbusMaster::ModbusMaster(uint8_t protocol) +{ + _protocol = protocol; + _u8MBSlave = 0x00; +} + + +/*********************************************************************** +Constructor. +Creates class object using default serial port 0, specified Modbus slave ID. + +@overload void ModbusMaster::ModbusMaster(uint8_t u8MBSlave) +@param u8MBSlave Modbus slave ID (1..255) +@ingroup setup +************************************************************************/ +ModbusMaster::ModbusMaster(uint8_t protocol, uint8_t u8MBSlave) +{ + + _protocol = protocol; + _u8MBSlave = u8MBSlave; +} + + +/*********************************************************************** +Initialize class object. +Sets up the serial port using default 19200 baud rate. +Call once class has been instantiated, typically within setup(). + +@ingroup setup +***********************************************************************/ +void ModbusMaster::begin(void) +{ + _u8SerialPort = 0; + begin(9600, _u8SerialPort); + +} + + +/*********************************************************************** +Initialize class object. +Sets up the serial port using default 19200 baud rate. +Call once class has been instantiated, typically within setup(). + +@ingroup setup +***********************************************************************/ +void ModbusMaster::begin(unsigned long BaudRate) +{ + _u8SerialPort = 0; + begin(BaudRate, _u8SerialPort); +} + + +/*********************************************************************** +Initialize class object. +Sets up the serial port using specified baud rate. +Call once class has been instantiated, typically within setup(). + +@overload ModbusMaster::begin(uint16_t u16BaudRate) +@param u16BaudRate baud rate, in standard increments (300..115200) +@ingroup setup +***********************************************************************/ +void ModbusMaster::begin(unsigned long BaudRate , uint8_t socket) +{ + // txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t)); + _u8TransmitBufferIndex = 0; + u16TransmitBufferLength = 0; + + if (_protocol == RS232_COM) + { + _u8SerialPort = socket; + beginSerial(BaudRate, _u8SerialPort); + } + else + { + W485.ON(); + delay(100); + + // Configure the baud rate of the module + W485.baudRateConfig(BaudRate); + // Configure the parity bit as disabled + W485.parityBit(DISABLE); + // Use one stop bit configuration + W485.stopBitConfig(1); + } +} + + +/*********************************************************************** +Begin the transmission. +Sets up the serial port using specified baud rate. +Call once class has been instantiated, typically within setup(). + +@overload ModbusMaster::begin(uint16_t u16BaudRate) +@param u16BaudRate baud rate, in standard increments (300..115200) +@ingroup setup +***********************************************************************/ +void ModbusMaster::beginTransmission(uint16_t u16Address) +{ + _u16WriteAddress = u16Address; + _u8TransmitBufferIndex = 0; + u16TransmitBufferLength = 0; +} + + +/*********************************************************************** +Set idle time callback function (cooperative multitasking). + +This function gets called in the idle time between transmission of data +and response from slave. Do not call functions that read from the serial +buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other +serial ports, etc. is permitted within callback function. + +@see ModbusMaster::ModbusMasterTransaction() +***********************************************************************/ +void ModbusMaster::idle(void (*idle)()) +{ + _idle = idle; +} + + +/************************************************************************ +Retrieve data from response buffer. + +@see ModbusMaster::clearResponseBuffer() +@param u8Index index of response buffer array (0x00..0x3F) +@return value in position u8Index of response buffer (0x0000..0xFFFF) +@ingroup buffer +***********************************************************************/ +uint16_t ModbusMaster::getResponseBuffer(uint8_t u8Index) +{ + if (u8Index < ku8MaxBufferSize) + { + return _u16ResponseBuffer[u8Index]; + } + else + { + return 0xFFFF; + } +} + + +/*********************************************************************** +Clear Modbus response buffer. + +@see ModbusMaster::getResponseBuffer(uint8_t u8Index) +@ingroup buffer +***********************************************************************/ +void ModbusMaster::clearResponseBuffer() +{ + uint8_t i; + + for (i = 0; i < ku8MaxBufferSize; i++) + { + _u16ResponseBuffer[i] = 0; + } +} + + +/*********************************************************************** +Place data in transmit buffer. + +@see ModbusMaster::clearTransmitBuffer() +@param u8Index index of transmit buffer array (0x00..0x3F) +@param u16Value value to place in position u8Index of transmit buffer (0x0000..0xFFFF) +@return 0 on success; exception number on failure +@ingroup buffer +***********************************************************************/ +uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value) +{ + if (u8Index < ku8MaxBufferSize) { + _u16TransmitBuffer[u8Index] = u16Value; + return ku8MBSuccess; + } else { + return ku8MBIllegalDataAddress; + } +} + + +/************************************************************************ +Clear Modbus transmit buffer. + +@see ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value) +@ingroup buffer +***********************************************************************/ +void ModbusMaster::clearTransmitBuffer() +{ + uint8_t i; + + for (i = 0; i < ku8MaxBufferSize; i++) { + _u16TransmitBuffer[i] = 0; + } +} + + +/************************************************************************ +Modbus function 0x01 Read Coils. + +This function code is used to read from 1 to 2000 contiguous status of +coils in a remote device. The request specifies the starting address, +i.e. the address of the first coil specified, and the number of coils. +Coils are addressed starting at zero. + +The coils in the response buffer are packed as one coil per bit of the +data field. Status is indicated as 1=ON and 0=OFF. The LSB of the first +data word contains the output addressed in the query. The other coils +follow toward the high order end of this word and from low order to high +order in subsequent words. + +If the returned quantity is not a multiple of sixteen, the remaining +bits in the final data word will be padded with zeros (toward the high +order end of the word). + +@param u16ReadAddress address of first coil (0x0000..0xFFFF) +@param u16BitQty quantity of coils to read (1..2000, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup discrete +***********************************************************************/ +uint8_t ModbusMaster::readCoils(uint16_t u16ReadAddress, uint16_t u16BitQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16BitQty; + + return ModbusMasterTransaction(ku8MBReadCoils); +} + + +/*********************************************************************** +Modbus function 0x02 Read Discrete Inputs. + +This function code is used to read from 1 to 2000 contiguous status of +discrete inputs in a remote device. The request specifies the starting +address, i.e. the address of the first input specified, and the number +of inputs. Discrete inputs are addressed starting at zero. + +The discrete inputs in the response buffer are packed as one input per +bit of the data field. Status is indicated as 1=ON; 0=OFF. The LSB of +the first data word contains the input addressed in the query. The other +inputs follow toward the high order end of this word, and from low order +to high order in subsequent words. + +If the returned quantity is not a multiple of sixteen, the remaining +bits in the final data word will be padded with zeros (toward the high +order end of the word). + +@param u16ReadAddress address of first discrete input (0x0000..0xFFFF) +@param u16BitQty quantity of discrete inputs to read (1..2000, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup discrete +***********************************************************************/ +uint8_t ModbusMaster::readDiscreteInputs(uint16_t u16ReadAddress, uint16_t u16BitQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16BitQty; + + return ModbusMasterTransaction(ku8MBReadDiscreteInputs); +} + + +/*********************************************************************** +Modbus function 0x03 Read Holding Registers. + +This function code is used to read the contents of a contiguous block of +holding registers in a remote device. The request specifies the starting +register address and the number of registers. Registers are addressed +starting at zero. + +The register data in the response buffer is packed as one word per +register. + +@param u16ReadAddress address of the first holding register (0x0000..0xFFFF) +@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::readHoldingRegisters(uint16_t u16ReadAddress, + uint16_t u16ReadQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16ReadQty; + return ModbusMasterTransaction(ku8MBReadHoldingRegisters); +} + + +/*********************************************************************** +Modbus function 0x04 Read Input Registers. + +This function code is used to read from 1 to 125 contiguous input +registers in a remote device. The request specifies the starting +register address and the number of registers. Registers are addressed +starting at zero. + +The register data in the response buffer is packed as one word per +register. + +@param u16ReadAddress address of the first input register (0x0000..0xFFFF) +@param u16ReadQty quantity of input registers to read (1..125, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::readInputRegisters(uint16_t u16ReadAddress, uint8_t u16ReadQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16ReadQty; + + return ModbusMasterTransaction(ku8MBReadInputRegisters); +} + + +/*********************************************************************** +Modbus function 0x05 Write Single Coil. + +This function code is used to write a single output to either ON or OFF +in a remote device. The requested ON/OFF state is specified by a +constant in the state field. A non-zero value requests the output to be +ON and a value of 0 requests it to be OFF. The request specifies the +address of the coil to be forced. Coils are addressed starting at zero. + +@param u16WriteAddress address of the coil (0x0000..0xFFFF) +@param u8State 0=OFF, non-zero=ON (0x00..0xFF) +@return 0 on success; exception number on failure +@ingroup discrete +***********************************************************************/ +uint8_t ModbusMaster::writeSingleCoil(uint16_t u16WriteAddress, uint8_t u8State) +{ + _u16WriteAddress = u16WriteAddress; + _u16WriteQty = (u8State ? 0xFF00 : 0x0000); + return ModbusMasterTransaction(ku8MBWriteSingleCoil); +} + + +/*********************************************************************** +Modbus function 0x06 Write Single Register. + +This function code is used to write a single holding register in a +remote device. The request specifies the address of the register to be +written. Registers are addressed starting at zero. + +@param u16WriteAddress address of the holding register (0x0000..0xFFFF) +@param u16WriteValue value to be written to holding register (0x0000..0xFFFF) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress, uint16_t u16WriteValue) +{ + _u16WriteAddress = u16WriteAddress; + _u16WriteQty = 0; + _u16TransmitBuffer[0] = u16WriteValue; + return ModbusMasterTransaction(ku8MBWriteSingleRegister); +} + + +/*********************************************************************** +Modbus function 0x0F Write Multiple Coils. + +This function code is used to force each coil in a sequence of coils to +either ON or OFF in a remote device. The request specifies the coil +references to be forced. Coils are addressed starting at zero. + +The requested ON/OFF states are specified by contents of the transmit +buffer. A logical '1' in a bit position of the buffer requests the +corresponding output to be ON. A logical '0' requests it to be OFF. + +@param u16WriteAddress address of the first coil (0x0000..0xFFFF) +@param u16BitQty quantity of coils to write (1..2000, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup discrete +***********************************************************************/ +uint8_t ModbusMaster::writeMultipleCoils(uint16_t u16WriteAddress, uint16_t u16BitQty) +{ + _u16WriteAddress = u16WriteAddress; + _u16WriteQty = u16BitQty; + return ModbusMasterTransaction(ku8MBWriteMultipleCoils); +} + +uint8_t ModbusMaster::writeMultipleCoils() +{ + _u16WriteQty = u16TransmitBufferLength; + return ModbusMasterTransaction(ku8MBWriteMultipleCoils); +} + + +/*********************************************************************** +Modbus function 0x10 Write Multiple Registers. + +This function code is used to write a block of contiguous registers (1 +to 123 registers) in a remote device. + +The requested written values are specified in the transmit buffer. Data +is packed as one word per register. + +@param u16WriteAddress address of the holding register (0x0000..0xFFFF) +@param u16WriteQty quantity of holding registers to write (1..123, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::writeMultipleRegisters(uint16_t u16WriteAddress, uint16_t u16WriteQty) +{ + _u16WriteAddress = u16WriteAddress; + _u16WriteQty = u16WriteQty; + return ModbusMasterTransaction(ku8MBWriteMultipleRegisters); +} + +// new version based on Wire.h +uint8_t ModbusMaster::writeMultipleRegisters() +{ + _u16WriteQty = _u8TransmitBufferIndex; + return ModbusMasterTransaction(ku8MBWriteMultipleRegisters); +} + + +/*********************************************************************** +Modbus function 0x16 Mask Write Register. + +This function code is used to modify the contents of a specified holding +register using a combination of an AND mask, an OR mask, and the +register's current contents. The function can be used to set or clear +individual bits in the register. + +The request specifies the holding register to be written, the data to be +used as the AND mask, and the data to be used as the OR mask. Registers +are addressed starting at zero. + +The function's algorithm is: + +Result = (Current Contents && And_Mask) || (Or_Mask && (~And_Mask)) + +@param u16WriteAddress address of the holding register (0x0000..0xFFFF) +@param u16AndMask AND mask (0x0000..0xFFFF) +@param u16OrMask OR mask (0x0000..0xFFFF) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::maskWriteRegister(uint16_t u16WriteAddress, + uint16_t u16AndMask, + uint16_t u16OrMask) +{ + _u16WriteAddress = u16WriteAddress; + _u16TransmitBuffer[0] = u16AndMask; + _u16TransmitBuffer[1] = u16OrMask; + return ModbusMasterTransaction(ku8MBMaskWriteRegister); +} + + +/*********************************************************************** +Modbus function 0x17 Read Write Multiple Registers. + +This function code performs a combination of one read operation and one +write operation in a single MODBUS transaction. The write operation is +performed before the read. Holding registers are addressed starting at +zero. + +The request specifies the starting address and number of holding +registers to be read as well as the starting address, and the number of +holding registers. The data to be written is specified in the transmit +buffer. + +@param u16ReadAddress address of the first holding register (0x0000..0xFFFF) +@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device) +@param u16WriteAddress address of the first holding register (0x0000..0xFFFF) +@param u16WriteQty quantity of holding registers to write (1..121, enforced by remote device) +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress, + uint16_t u16ReadQty, + uint16_t u16WriteAddress, + uint16_t u16WriteQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16ReadQty; + _u16WriteAddress = u16WriteAddress; + _u16WriteQty = u16WriteQty; + return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters); +} + +uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress, + uint16_t u16ReadQty) +{ + _u16ReadAddress = u16ReadAddress; + _u16ReadQty = u16ReadQty; + _u16WriteQty = _u8TransmitBufferIndex; + return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters); +} + + +/*********************************************************************** +Modbus function for general registers read +The request specifies the address and number of registers to be read +@param u16ReadAddress address of the first holding register (0x0000..0xFFFF) +@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device) +@param functionCode the read function to execute + +@return 0 on success; exception number on failure +@ingroup register +***********************************************************************/ +uint8_t ModbusMaster::readRegiters(uint16_t u16ReadAddress, uint16_t u16ReadQty, uint8_t functionCode) +{ + if (functionCode == ku8MBReadCoils) + { + //return readCoils(u16ReadAddress,u16ReadQty); + + } + else if (functionCode == ku8MBReadDiscreteInputs) + { + return readDiscreteInputs(u16ReadAddress,u16ReadQty); + + } + else if (functionCode == ku8MBReadHoldingRegisters) + { + return readHoldingRegisters(u16ReadAddress,u16ReadQty); + + } + else if (functionCode == ku8MBReadInputRegisters) + { + return readInputRegisters(u16ReadAddress,u16ReadQty); + } + else + { + return 2; + } +} + + +//********************************************************************** +// PRIVATE FUNCTIONS +//********************************************************************** +/*********************************************************************** +Modbus transaction engine. +Sequence: + - assemble Modbus Request Application Data Unit (ADU), + based on particular function called + - transmit request over selected serial port + - wait for/retrieve response + - evaluate/disassemble response + - return status (success/exception) + +@param u8MBFunction Modbus function (0x01..0xFF) +@return 0 on success; exception number on failure +***********************************************************************/ +uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) +{ + + uint8_t u8ModbusADU[256]; + uint8_t u8ModbusADUSize = 0; + uint8_t i, u8Qty; + uint16_t u16CRC; + uint32_t u32StartTime; + uint8_t u8BytesLeft = 8; + uint8_t u8MBStatus = ku8MBSuccess; + + // assemble Modbus Request Application Data Unit + u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave; + u8ModbusADU[u8ModbusADUSize++] = u8MBFunction; + + + switch(u8MBFunction) + { + case ku8MBReadCoils: + case ku8MBReadDiscreteInputs: + case ku8MBReadInputRegisters: + case ku8MBReadHoldingRegisters: + case ku8MBReadWriteMultipleRegisters: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress); + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty); + break; + } + + switch(u8MBFunction) + { + case ku8MBWriteSingleCoil: + case ku8MBMaskWriteRegister: + case ku8MBWriteMultipleCoils: + case ku8MBWriteSingleRegister: + case ku8MBWriteMultipleRegisters: + case ku8MBReadWriteMultipleRegisters: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteAddress); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteAddress); + break; + } + + switch(u8MBFunction) + { + case ku8MBWriteSingleCoil: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); + break; + + case ku8MBWriteSingleRegister: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]); + break; + + case ku8MBWriteMultipleCoils: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); + u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1) : (_u16WriteQty >> 3); + u8ModbusADU[u8ModbusADUSize++] = u8Qty; + + for (i = 0; i < u8Qty; i++) { + switch(i % 2) { + case 0: // i is even + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i >> 1]); + break; + + case 1: // i is odd + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i >> 1]); + break; + } + } + break; + + case ku8MBWriteMultipleRegisters: + case ku8MBReadWriteMultipleRegisters: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty << 1); + + for (i = 0; i < lowByte(_u16WriteQty); i++) { + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i]); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i]); + } + break; + + case ku8MBMaskWriteRegister: + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]); + u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[1]); + u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[1]); + break; + } + + // append CRC + u16CRC = 0xFFFF; + for (i = 0; i < u8ModbusADUSize; i++) { + u16CRC = _crc16_update(u16CRC, u8ModbusADU[i]); + } + + u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC); + u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC); + u8ModbusADU[u8ModbusADUSize] = 0; + + if (_protocol == RS232_COM) + { + for (i = 0; i < u8ModbusADUSize; i++) { + printByte(u8ModbusADU[i], _u8SerialPort); + } + } + else + { + for (i = 0; i < u8ModbusADUSize; i++) { + W485.send(u8ModbusADU[i], _u8SerialPort); + } + } + + u8ModbusADUSize = 1; + + // loop until we run out of time or bytes, or an error occurs + u32StartTime = millis(); + + int val = 0xFF; + long cont = 0; + + if (_protocol == RS232_COM) + { + while((val != _u8MBSlave) && (cont < 200)) + { + val = serialRead(_u8SerialPort); + delay(5); + cont ++; + } + } + else + { + while((val != _u8MBSlave) && (cont < 200)) + { + val = W485.read(); + delay(5); + cont ++; + } + } + + u8ModbusADU[u8ModbusADUSize] = val; + + + while (u8BytesLeft && !u8MBStatus) + { + + if (_protocol == RS232_COM) + { + if (serialAvailable(_u8SerialPort)) + { + u8ModbusADU[u8ModbusADUSize] = serialRead(_u8SerialPort); + u8BytesLeft--; + u8ModbusADUSize ++; + } + else + { + delay(10); + } + } + else + { + if (W485.available()) + { + u8ModbusADU[u8ModbusADUSize] = W485.read(); + u8BytesLeft--; + u8ModbusADUSize ++; + } + else + { + delay(10); + } + } + + // evaluate slave ID, function code once enough bytes have been read + if (u8ModbusADUSize == 5) { + + // verify response is for correct Modbus slave + if (u8ModbusADU[0] != _u8MBSlave) { + u8MBStatus = ku8MBInvalidSlaveID; + break; + } + + // verify response is for correct Modbus function code (mask exception bit 7) + if ((u8ModbusADU[1] & 0x7F) != u8MBFunction) { + u8MBStatus = ku8MBInvalidFunction; + break; + } + + // check whether Modbus exception occurred; return Modbus Exception Code + if (bitRead(u8ModbusADU[1], 7)) { + u8MBStatus = u8ModbusADU[2]; + break; + } + + // evaluate returned Modbus function code + switch(u8ModbusADU[1]) + { + case ku8MBReadCoils: + case ku8MBReadDiscreteInputs: + case ku8MBReadInputRegisters: + case ku8MBReadHoldingRegisters: + case ku8MBReadWriteMultipleRegisters: + u8BytesLeft = u8ModbusADU[2]; + break; + + case ku8MBWriteSingleCoil: + case ku8MBWriteMultipleCoils: + case ku8MBWriteSingleRegister: + case ku8MBWriteMultipleRegisters: + u8BytesLeft = 3; + break; + + case ku8MBMaskWriteRegister: + u8BytesLeft = 5; + break; + } + } + + if (millis() > (u32StartTime + ku8MBResponseTimeout)) { + u8MBStatus = ku8MBResponseTimedOut; + } + } + + // verify response is large enough to inspect further + if (!u8MBStatus && u8ModbusADUSize >= 5) { + // calculate CRC + u16CRC = 0xFFFF; + + for (i = 0; i < (u8ModbusADUSize - 2); i++) { + u16CRC = _crc16_update(u16CRC, u8ModbusADU[i]); + } + + // verify CRC + if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] || + highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1])) { + u8MBStatus = ku8MBInvalidCRC; + } + } + + // disassemble ADU into words + if (!u8MBStatus) { + + // evaluate returned Modbus function code + switch(u8ModbusADU[1]) + { + case ku8MBReadCoils: + case ku8MBReadDiscreteInputs: + + // load bytes into word; response bytes are ordered L, H, L, H, ... + for (i = 0; i < (u8ModbusADU[2] >> 1); i++) { + if (i < ku8MaxBufferSize) { + _u16ResponseBuffer[i] = makeWord(u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]); + } + + _u8ResponseBufferLength = i; + } + + // in the event of an odd number of bytes, load last byte into zero-padded word + if (u8ModbusADU[2] % 2) + { + if (i < ku8MaxBufferSize) { + _u16ResponseBuffer[i] = makeWord(0, u8ModbusADU[2 * i + 3]); + } + + _u8ResponseBufferLength = i + 1; + } + + break; + + case ku8MBReadInputRegisters: + case ku8MBReadHoldingRegisters: + case ku8MBReadWriteMultipleRegisters: + // load bytes into word; response bytes are ordered H, L, H, L, ... + for (i = 0; i < (u8ModbusADU[2] >> 1); i++) { + if (i < ku8MaxBufferSize) { + _u16ResponseBuffer[i] = makeWord(u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]); + } + + _u8ResponseBufferLength = i; + } + + break; + } + } + + + _u8TransmitBufferIndex = 0; + u16TransmitBufferLength = 0; + _u8ResponseBufferIndex = 0; + + return u8MBStatus; +} + +/*********************************************************************** +* Modbus makeWord from unsigned int +* @param unsigned int w +* @return unsigned int w +***********************************************************************/ +unsigned int ModbusMaster::makeWord(unsigned int w) +{ + return w; +} + + +/*********************************************************************** +* Modbus makeWord from two bytes +* @param uint8_t h: high byte +* @param uint8_t l: low byte +* @return unsigned int w +***********************************************************************/ +unsigned int ModbusMaster::makeWord(uint8_t h, uint8_t l) +{ + return (h << 8) | l; +} + + +/*********************************************************************** +* Modbus set slave address +* @param uint8_t u8MBSlave: slave of the device +* @return void +***********************************************************************/ +void ModbusMaster::setSlaveAddress(uint8_t u8MBSlave){ + + _u8MBSlave = u8MBSlave; +} + + +/*********************************************************************** +* Modbus bytes availbale to read +* @param void +* @return uint8_t : bytes available for reading +***********************************************************************/ +uint8_t ModbusMaster::available(void) +{ + return _u8ResponseBufferLength - _u8ResponseBufferIndex; +} + + + + + + + + diff --git a/libraries/ModbusMaster/ModbusMaster.h b/libraries/ModbusMaster/ModbusMaster.h new file mode 100755 index 0000000..bf0ce8b --- /dev/null +++ b/libraries/ModbusMaster/ModbusMaster.h @@ -0,0 +1,307 @@ +/* + ModbusMaster232.h - Waspmote library for communicating with Modbus slaves + over RS-232/485 (via RTU protocol). + + This file is part of ModbusMaster. + + ModbusMaster is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ModbusMaster is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ModbusMaster. If not, see . + + Written by Doc Walker (Rx) + Copyright © 2009-2013 Doc Walker <4-20ma at wvfans dot net> + Modified for Waspmote by Libelium, 2016 + + Version: 3.0 + +*/ + + +#ifndef _MODBUSMASTER_H_INCLUDED +#define _MODBUSMASTER_H_INCLUDED + + +/*********************************************************************** +@def __MODBUSMASTER_DEBUG__ (1). +Set to 1 to enable debugging features within class: + - pin 4 cycles for each byte read in the Modbus response + - pin 5 cycles for each millisecond timeout during the Modbus response +***********************************************************************/ +#define __MODBUSMASTER_DEBUG__ (1) + +//********************************************************************** +// STANDARD INCLUDES +//********************************************************************** + +// Include types & constants of Wiring core API + +#ifndef inttypes_h + #include +#endif + +//********************************************************************** +// UTILITY MACROS +//********************************************************************** +/** +@def lowWord(ww) ((uint16_t) ((ww) & 0xFFFF)) +Macro to return low word of a 32-bit integer. +*/ +#define lowWord(ww) ((uint16_t) ((ww) & 0xFFFF)) + + +/** +@def highWord(ww) ((uint16_t) ((ww) >> 16)) +Macro to return high word of a 32-bit integer. +*/ +#define highWord(ww) ((uint16_t) ((ww) >> 16)) + + +/** +@def LONG(hi, lo) ((uint32_t) ((hi) << 16 | (lo))) +Macro to generate 32-bit integer from (2) 16-bit words. +*/ +#define LONG(hi, lo) ((uint32_t) ((hi) << 16 | (lo))) +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +#define RS485_COM 0x01 +#define RS232_COM 0x02 + +//********************************************************************** +// PROJECT INCLUDES +//********************************************************************** +// Functions to calculate Modbus Application Data Unit CRC +#include +#include "Wasp485.h" + +//************************************************************************************************** +// MODBUS MASTER CLASS DEFINITIONS +//************************************************************************************************** +/*********************************************************************** +* Waspmote class library for communicating with Modbus slaves over +* RS-232/485 (via RTU protocol). +***********************************************************************/ +class ModbusMaster +{ + public: + + ModbusMaster(); + ModbusMaster(uint8_t); + ModbusMaster(uint8_t, uint8_t); + + void begin(); + void begin(unsigned long); + void begin(unsigned long, uint8_t); + + void idle(void (*)()); + + //********************************************************************** + // Modbus exception codes + //********************************************************************** + /** + Modbus protocol illegal function exception. + + The function code received in the query is not an allowable action for + the server (or slave). This may be because the function code is only + applicable to newer devices, and was not implemented in the unit + selected. It could also indicate that the server (or slave) is in the + wrong state to process a request of this type, for example because it is + unconfigured and is being asked to return register values. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalFunction = 0x01; + + /** + Modbus protocol illegal data address exception. + + The data address received in the query is not an allowable address for + the server (or slave). More specifically, the combination of reference + number and transfer length is invalid. For a controller with 100 + registers, the ADU addresses the first register as 0, and the last one + as 99. If a request is submitted with a starting register address of 96 + and a quantity of registers of 4, then this request will successfully + operate (address-wise at least) on registers 96, 97, 98, 99. If a + request is submitted with a starting register address of 96 and a + quantity of registers of 5, then this request will fail with Exception + Code 0x02 "Illegal Data Address" since it attempts to operate on + registers 96, 97, 98, 99 and 100, and there is no register with address + 100. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalDataAddress = 0x02; + + /** + Modbus protocol illegal data value exception. + + A value contained in the query data field is not an allowable value for + server (or slave). This indicates a fault in the structure of the + remainder of a complex request, such as that the implied length is + incorrect. It specifically does NOT mean that a data item submitted for + storage in a register has a value outside the expectation of the + application program, since the MODBUS protocol is unaware of the + significance of any particular value of any particular register. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalDataValue = 0x03; + + /** + Modbus protocol slave device failure exception. + + An unrecoverable error occurred while the server (or slave) was + attempting to perform the requested action. + + @ingroup constant + */ + static const uint8_t ku8MBSlaveDeviceFailure = 0x04; + + //********************************************************************** + // Class-defined success/exception codes + //********************************************************************** + /** + ModbusMaster success. + + Modbus transaction was successful; the following checks were valid: + - slave ID + - function code + - response code + - data + - CRC + + @ingroup constant + */ + static const uint8_t ku8MBSuccess = 0x00; + + /** + ModbusMaster invalid response slave ID exception. + The slave ID in the response does not match that of the request. + @ingroup constant + */ + static const uint8_t ku8MBInvalidSlaveID = 0xE0; + + /** + ModbusMaster invalid response function exception. + The function code in the response does not match that of the request. + @ingroup constant + */ + static const uint8_t ku8MBInvalidFunction = 0xE1; + + /** + ModbusMaster response timed out exception. + The entire response was not received within the timeout period, + ModbusMaster::ku8MBResponseTimeout. + + @ingroup constant + */ + static const uint8_t ku8MBResponseTimedOut = 0xE2; + + /** + ModbusMaster invalid response CRC exception. + The CRC in the response does not match the one calculated. + @ingroup constant + */ + static const uint8_t ku8MBInvalidCRC = 0xE3; + + //********************************************************************** + // Public functions + //********************************************************************** + + uint16_t getResponseBuffer(uint8_t); + void clearResponseBuffer(); + uint8_t setTransmitBuffer(uint8_t, uint16_t); + void clearTransmitBuffer(); + + void beginTransmission(uint16_t); + uint8_t requestFrom(uint16_t, uint16_t); + void sendBit(bool); + void send(uint8_t); + void send(uint16_t); + void send(uint32_t); + void setSlaveAddress(uint8_t); + + uint8_t available(void); + uint16_t receive(void); + + + uint8_t readCoils(uint16_t, uint16_t); + uint8_t readDiscreteInputs(uint16_t, uint16_t); + uint8_t readHoldingRegisters(uint16_t, uint16_t); + uint8_t readInputRegisters(uint16_t, uint8_t); + uint8_t writeSingleCoil(uint16_t, uint8_t); + uint8_t writeSingleRegister(uint16_t, uint16_t); + uint8_t writeMultipleCoils(uint16_t, uint16_t); + uint8_t writeMultipleCoils(); + uint8_t writeMultipleRegisters(uint16_t, uint16_t); + uint8_t writeMultipleRegisters(); + uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t); + uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t); + uint8_t readWriteMultipleRegisters(uint16_t, uint16_t); + uint8_t readRegiters(uint16_t, uint16_t, uint8_t); + + //********************************************************************** + // Protected functions + //********************************************************************** + + protected: + + uint8_t _protocol; + uint8_t _u8SerialPort; ///< serial port (0..3) initialized in constructor + uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in constructor + uint16_t _u16BaudRate; ///< baud rate (300..115200) initialized in begin() + static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers + uint16_t _u16ReadAddress; ///< slave register from which to read + uint16_t _u16ReadQty; ///< quantity of words to read + uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() + uint16_t _u16WriteAddress; ///< slave register to which to write + uint16_t _u16WriteQty; ///< quantity of words to write + uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer() + uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx + uint8_t _u8TransmitBufferIndex; + uint16_t u16TransmitBufferLength; + uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx + uint8_t _u8ResponseBufferIndex; + uint8_t _u8ResponseBufferLength; + + // Modbus function codes for bit access + static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils + static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs + static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil + static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils + + // Modbus function codes for 16 bit access + static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers + static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers + static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register + static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers + static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register + static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers + + // Modbus timeout [milliseconds] + static const uint8_t ku8MBResponseTimeout = 200; ///< Modbus timeout [milliseconds] + + // master function that conducts Modbus transactions + uint8_t ModbusMasterTransaction(uint8_t u8MBFunction); + + // idle callback function; gets called during idle time between TX and RX + void (*_idle)(); + + uint16_t makeWord(uint16_t w); + uint16_t makeWord(uint8_t h, uint8_t l); +}; +#endif + diff --git a/libraries/ModbusMaster/keywords.txt b/libraries/ModbusMaster/keywords.txt new file mode 100644 index 0000000..6888b0f --- /dev/null +++ b/libraries/ModbusMaster/keywords.txt @@ -0,0 +1,26 @@ +# ModbusMaster keywords # + + +ModbusMaster KEYWORD2 +begin KEYWORD2 + +readCoils KEYWORD2 +readDiscreteInputs KEYWORD2 +readHoldingRegisters KEYWORD2 +readInputRegisters KEYWORD2 +writeSingleCoil KEYWORD2 +writeSingleRegister KEYWORD2 +writeMultipleCoils KEYWORD2 +writeMultipleCoils KEYWORD2 +writeMultipleRegisters KEYWORD2 +writeMultipleRegisters KEYWORD2 +maskWriteRegister KEYWORD2 +getResponseBuffer KEYWORD2 +clearResponseBuffer KEYWORD2 +readWriteMultipleRegisters KEYWORD2 +readWriteMultipleRegisters KEYWORD2 +readRegiters KEYWORD2 + +RS232_COM LITERAL1 +RS485_COM LITERAL1 + diff --git a/libraries/ModbusSlave/ModbusSlave.cpp b/libraries/ModbusSlave/ModbusSlave.cpp new file mode 100755 index 0000000..130f3f5 --- /dev/null +++ b/libraries/ModbusSlave/ModbusSlave.cpp @@ -0,0 +1,686 @@ +/* + file ModbusSlave.cpp + + Modbus over serial line - RTU Slave Waspmote Sketch + + This library of functions are designed to enable a program send and + receive data from a device that communicates using the Modbus protocol. + + Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD. + Modified for Waspmote by Libelium, 2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The functions included here have been derived from the + Modicon Modbus Protocol Reference Guide + which can be obtained from Schneider at www.schneiderautomation.com. + + This code has its origins with + paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk) + who wrote a small program to read 100 registers from a modbus slave. + + Version: 3.0 + +*/ + +#ifndef __WPROGRAM_H__ + #include "WaspClasses.h" +#endif + +#include "ModbusSlave.h" + + +/**************************************************************************** + * BEGIN MODBUS RTU SLAVE FUNCTIONS + ****************************************************************************/ +/* constants */ +enum +{ + MAX_READ_REGS = 0x7D, + MAX_WRITE_REGS = 0x7B, + MAX_MESSAGE_LENGTH = 256 +}; + + +enum +{ + RESPONSE_SIZE = 6, + EXCEPTION_SIZE = 3, + CHECKSUM_SIZE = 2 +}; + +/* exceptions code */ +enum +{ + NO_REPLY = -1, + EXC_FUNC_CODE = 1, + EXC_ADDR_RANGE = 2, + EXC_REGS_QUANT = 3, + EXC_EXECUTE = 4 +}; + +/* positions inside the query/response array */ +enum +{ + SLAVE = 0, + FUNC, + START_H, + START_L, + REGS_H, + REGS_L, + BYTE_CNT +}; + + +/* enum of supported modbus function codes. If you implement a new one, put its function code here ! */ +enum { + FC_READ_REGS = 0x03, //Read contiguous block of holding register + FC_WRITE_REG = 0x06, //Write single holding register + FC_WRITE_REGS = 0x10 //Write block of contiguous registers +}; + +/* supported functions. If you implement a new one, put its function code into this array! */ +const unsigned char fsupported[] = { FC_READ_REGS, FC_WRITE_REG, FC_WRITE_REGS }; + + + /*! + * @brief Class contructor + * @param void + * @return void + */ +ModbusSlave::ModbusSlave() +{ + Nowdt = 0; + _protocol = RS485_COM; + _socket = 0; +} + + + /*! + * @brief Class contructor + * @param uint8_t protocol: RS232 or RS485 + * @return void + */ +ModbusSlave::ModbusSlave(uint8_t protocol) +{ + Nowdt = 0; + _protocol = protocol; + _socket = 0; +} + + + /*! + * @brief Class contructor + * @param uint8_t protocol: RS-232 or RS-485 + * @param uint8_t socket: SOCKET_1 or SOCKET_0 (for RS-232) + * @return void + */ +ModbusSlave::ModbusSlave(uint8_t protocol, uint8_t socket) +{ + Nowdt = 0; + _protocol = protocol; + _socket = socket; +} + + + /*! + * @brief Class contructor + * @param unsigned char * buf: Array containing message to be sent to controller + * @param unsigned char start: Start of loop in crc counter, usually 0 + * @param unsigned char cnt: Amount of bytes in message being sent to controller + * @return unsigned int temp: Returns crc byte for message + */ +unsigned int ModbusSlave::crc(unsigned char *buf, unsigned char start, unsigned char cnt) +{ + unsigned char i, j; + unsigned temp, temp2, flag; + + temp = 0xFFFF; + + for (i = start; i < cnt; i++) + { + temp = temp ^ buf[i]; + + for (j = 1; j <= 8; j++) + { + flag = temp & 0x0001; + temp = temp >> 1; + + if (flag) + { + temp = temp ^ 0xA001; + } + } + } + + // Reverse byte order + temp2 = temp >> 8; + temp = (temp << 8) | temp2; + temp &= 0xFFFF; + + return (temp); +} + + + + /*! + * @brief Start of the packet of a read_holding_register response + * @param unsigned char function: the modbus function + * @param unsigned char count: specifies the quantity of complete bytes of data + * @param unsigned char *packet: pointer to the packet buffer + * @return void + */ +void ModbusSlave::build_read_packet(unsigned char function, unsigned char count, unsigned char *packet) +{ + packet[SLAVE] = slave; + packet[FUNC] = function; + packet[2] = count * 2; +} + + + /*! + * @brief Start of the packet of a preset_multiple_register response + * @param unsigned char function: the modbus function + * @param unsigned int start_addr: start address where reading + * @param unsigned char count: specifies the quantity of complete bytes of data + * @param unsigned char *packet: pointer to the packet buffer + * @return void + */ +void ModbusSlave::build_write_packet(unsigned char function, unsigned int start_addr, unsigned char count, unsigned char *packet) +{ + packet[SLAVE] = slave; + packet[FUNC] = function; + packet[START_H] = start_addr >> 8; + packet[START_L] = start_addr & 0x00FF; + packet[REGS_H] = 0x00; + packet[REGS_L] = count; +} + + + /*! + * @brief Start of the packet of a write_single_register response + * @param unsigned char function: the modbus function + * @param unsigned int write_addr: start address where write + * @param unsigned int reg_val: value to write + * @param unsigned char *packet: pointer to the packet buffer + * @return void + */ +void ModbusSlave::build_write_single_packet(unsigned char function, unsigned int write_addr, unsigned int reg_val, unsigned char* packet) +{ + packet[SLAVE] = slave; + packet[FUNC] = function; + packet[START_H] = write_addr >> 8; + packet[START_L] = write_addr & 0x00FF; + packet[REGS_H] = reg_val >> 8; + packet[REGS_L] = reg_val & 0x00FF; +} + + + /*! + * @brief Start of the packet of an exception response + * @param unsigned char function: the modbus function + * @param unsigned char exception: exception code + * @param unsigned char *packet: pointer to the packet buffer + * @return void + */ +void ModbusSlave::build_error_packet( unsigned char function, unsigned char exception, unsigned char *packet) +{ + packet[SLAVE] = slave; + packet[FUNC] = function + 0x80; + packet[2] = exception; +} + + + /*! + * @brief Function to add a checksum to the end of a packet. + * Please note that the packet array must be at least 2 fields longer than + * string_length. + * + * @param unsigned char *packet: pointer to the packet + * @param unsigned char string_length: length of the packet + * @return void + */ +void ModbusSlave::modbus_reply(unsigned char *packet, unsigned char string_length) +{ + int temp_crc; + + temp_crc = crc(packet, 0, string_length); + packet[string_length] = temp_crc >> 8; + string_length++; + packet[string_length] = temp_crc & 0x00FF; +} + + + /*! + * @brief Function to send a reply to a modbus master + * @param unsigned char *query: packet to be sent + * @param unsigned char string_length: length of the packet + * @return int: number of bytes sent + */ +int ModbusSlave::send_reply(unsigned char *query, unsigned char string_length) +{ + unsigned char i; + + modbus_reply(query, string_length); + string_length += 2; + + if (_protocol == RS232_COM) + { + for (i = 0; i < string_length; i++) + { + printByte(query[i], _socket); + } + } + else + { + for (i = 0; i < string_length; i++) + { + W485.send(query[i], BYTE); + } + } + + // It does not mean that the write was succesful + return i; +} + + + /*! + * @brief Function to monitor for a request from the modbus master + * @param unsigned char *received_string: received string + * @return int: bytes received + */ +int ModbusSlave::receive_request(unsigned char *received_string) +{ + int bytes_received = 0; + + if (_protocol == RS232_COM) + { + // FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? + while (serialAvailable(_socket)) + { + received_string[bytes_received] = serialRead(_socket); + bytes_received++; + + if (bytes_received >= MAX_MESSAGE_LENGTH) + { + // Port error + return NO_REPLY; + } + } + } + else + { + // FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? + while (W485.available()) + { + received_string[bytes_received] = W485.read(); + bytes_received++; + + if (bytes_received >= MAX_MESSAGE_LENGTH) + { + // Port error + return NO_REPLY; + } + } + } + + return (bytes_received); +} + + + /*! + * @brief Function to the correct request is returned and that the checksum is correct. + * @param unsigned char *data: data to be sent + * @return int: response length. 0 if failed + */ +int ModbusSlave::modbus_request(unsigned char *data) +{ + int response_length; + unsigned int crc_calc = 0; + unsigned int crc_received = 0; + unsigned char recv_crc_hi; + unsigned char recv_crc_lo; + + response_length = receive_request(data); + + if (response_length > 0) + { + crc_calc = crc(data, 0, response_length - 2); + recv_crc_hi = (unsigned) data[response_length - 2]; + recv_crc_lo = (unsigned) data[response_length - 1]; + crc_received = data[response_length - 2]; + crc_received = (unsigned) crc_received << 8; + crc_received = crc_received | (unsigned) data[response_length - 1]; + + /*********** check CRC of response ************/ + if (crc_calc != crc_received) + { + return NO_REPLY; + } + + // check for slave id + if (slave != data[SLAVE]) + { + return NO_REPLY; + } + } + + return (response_length); +} + + + /*! + * @brief Function to check that the request can be processed by the slave + * @param unsigned char *data: data to validate + * @param unsigned char length: length of the request + * @param unsigned int regs_size: size of register + * @return int: 0 if OK. + */ +int ModbusSlave::validate_request(unsigned char *data, unsigned char length, unsigned int regs_size) +{ + int i, fcnt = 0; + unsigned int regs_num = 0; + unsigned int start_addr = 0; + unsigned char max_regs_num; + + // check function code + for (i = 0; i < sizeof(fsupported); i++) + { + if (fsupported[i] == data[FUNC]) + { + fcnt = 1; + break; + } + } + + if (0 == fcnt) + return EXC_FUNC_CODE; + + if (FC_WRITE_REG == data[FUNC]) + { + /* For function write single reg, this is the target reg.*/ + regs_num = ((int) data[START_H] << 8) + (int) data[START_L]; + if (regs_num >= regs_size) + return EXC_ADDR_RANGE; + + return 0; + } + + // For functions read/write regs, this is the range + regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L]; + + // Check quantity of registers + if (FC_READ_REGS == data[FUNC]) + { + max_regs_num = MAX_READ_REGS; + } + else if (FC_WRITE_REGS == data[FUNC]) + { + max_regs_num = MAX_WRITE_REGS; + } + + if ((regs_num < 1) || (regs_num > max_regs_num)) + { + return EXC_REGS_QUANT; + } + + // Check registers range, start address is 0 + start_addr = ((int) data[START_H] << 8) + (int) data[START_L]; + + if ((start_addr + regs_num) > regs_size) + { + return EXC_ADDR_RANGE; + } + + // OK, no exception + return 0; +} + + + /*! + * @brief Writes into the slave's holding registers the data in query + * @param unsigned int start_addr: start address + * @param unsigned char *query: query to write + * @param int *regs: registers to be writed + * @return int: bytes sent + */ +int ModbusSlave::write_regs(unsigned int start_addr, unsigned char *query, int *regs) +{ + int temp; + unsigned int i; + + for (i = 0; i < query[REGS_L]; i++) { + // Shift reg hi_byte to temp + temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8; + + // OR with lo_byte + temp = temp | (int) query[(BYTE_CNT + 2) + i * 2]; + regs[start_addr + i] = temp; + } + + return i; +} + + + /*! + * @brief Write the data from an array into the holding registers of the slave + * @param unsigned int start_addr: start address + * @param unsigned char count: number of bytes + * @param unsigned char *query: query to be writed + * @param int *regs: registers to be writed + * @return int: status + */ +int ModbusSlave::preset_multiple_registers(unsigned int start_addr, unsigned char count, unsigned char *query, int *regs) +{ + unsigned char function = FC_WRITE_REGS; /* Preset Multiple Registers */ + int status = 0; + unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; + + build_write_packet(function, start_addr, count, packet); + + if (write_regs(start_addr, query, regs)) + { + status = send_reply(packet, RESPONSE_SIZE); + } + + return (status); +} + + + /*! + * @brief Write a single int val into a single holding register of the slave + * @param unsigned int write_addr: write address + * @param unsigned char *query: query to be writed + * @param int *regs: registers to write + * @return int: status + */ +int ModbusSlave::write_single_register(unsigned int write_addr, unsigned char *query, int *regs) +{ + // Function: Write Single Register + unsigned char function = FC_WRITE_REG; + int status = 0; + unsigned int reg_val; + unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; + + reg_val = query[REGS_H] << 8 | query[REGS_L]; + build_write_single_packet(function, write_addr, reg_val, packet); + regs[write_addr] = (int) reg_val; + + /* + written.start_addr=write_addr; + written.num_regs=1; + */ + + status = send_reply(packet, RESPONSE_SIZE); + + return (status); +} + + /*! + * @brief Read the slave's holdings registers and sends them to the Modbus master + * @param unsigned int start_addr: start address + * @param unsigned char reg_count: number of bytes + * @param int *regs: registers to be read + * @return int: status + */ +int ModbusSlave::read_holding_registers(unsigned int start_addr, unsigned char reg_count, int *regs) +{ + /* Read Holding Registers */ + unsigned char function = FC_READ_REGS; + int packet_size = 3; + int status; + unsigned int i; + unsigned char packet[MAX_MESSAGE_LENGTH]; + + build_read_packet(function, reg_count, packet); + + for (i = start_addr; i < (start_addr + (unsigned int) reg_count); i++) + { + packet[packet_size] = regs[i] >> 8; + packet_size++; + packet[packet_size] = regs[i] & 0x00FF; + packet_size++; + } + + status = send_reply(packet, packet_size); + + return (status); +} + + + /*! + * @brief Sets the communication parameters for of the serial line. + * @param uint8_t _slave: identification number of the slave in the Modbus network (1 to 127) + * @param long baud: baudrate in bps (typical values 9600, 19200... 115200) + * @param uint8_t socket: SOCKET_0 or SOCKET_1 for RS-232 protocol + * @return void + */ +void ModbusSlave::configure(uint8_t _slave, long baud, uint8_t socket) +{ + slave = _slave; + + if (_protocol == RS232_COM) + { + //W232.ON(socket); + delay(10); + beginSerial(baud, socket); + } + else + { + W485.ON(); + delay(100); + + // Configure the baud rate of the module + W485.baudRateConfig(baud); + // Configure the parity bit as disabled + W485.parityBit(DISABLE); + // Use one stop bit configuration + W485.stopBitConfig(1); + } + + return; +} + + + /*! + * @brief Sets the communication parameters for of the serial line SOCKET_0 by default + * @param uint8_t _slave: identification number of the slave in the Modbus network (1 to 127) + * @param long baud: baudrate in bps (typical values 9600, 19200... 115200) + * @return void + */ +void ModbusSlave::configure(uint8_t _slave, long baud) +{ + configure(_slave, baud, 0); +} + + + /*! + * @brief checks if there is any valid request from the modbus master. If there is performs the requested action. + * @param int *regs: an array with the holding registers. They start at address 1 (master point of view) + * @param unsigned int regs_size: total number of holding registers. + * @return int: returns: + * - 0 if no request from master + * - (-1) if no reply is sent to the master + */ +int ModbusSlave::update(int *regs, unsigned int regs_size) +{ + unsigned char query[MAX_MESSAGE_LENGTH]; + unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE]; + unsigned int start_addr; + int exception; + int length; + unsigned long now = millis(); + + if (_protocol == RS232_COM) + { + length = serialAvailable(_socket); + } + else + { + length = W485.available(); + } + + if (length == 0) + { + lastBytesReceived = 0; + return 0; + } + + if (lastBytesReceived != length) + { + lastBytesReceived = length; + Nowdt = now + T35; + return 0; + } + + if (now < Nowdt) + return 0; + + lastBytesReceived = 0; + + length = modbus_request(query); + + if (length < 1) + return length; + + exception = validate_request(query, length, regs_size); + + if (exception) + { + build_error_packet( query[FUNC], exception, errpacket); + send_reply(errpacket, EXCEPTION_SIZE); + + return (exception); + } + + start_addr = ((int) query[START_H] << 8) + (int) query[START_L]; + + switch (query[FUNC]) + { + case FC_READ_REGS: + return read_holding_registers(start_addr, query[REGS_L], regs); + break; + + case FC_WRITE_REGS: + return preset_multiple_registers(start_addr, query[REGS_L], query, regs); + break; + + case FC_WRITE_REG: + write_single_register(start_addr, query, regs); + break; + } +} + + diff --git a/libraries/ModbusSlave/ModbusSlave.h b/libraries/ModbusSlave/ModbusSlave.h new file mode 100755 index 0000000..87dbc6b --- /dev/null +++ b/libraries/ModbusSlave/ModbusSlave.h @@ -0,0 +1,99 @@ +/* file ModbusSlave.cpp + * + * ModbusSlave library implementing a Modbus RTU Slave for Waspmote + * Based on the work published by jpmzometa at + * http://sites.google.com/site/jpmzometa/arduino-mbrt + * + * These library of functions are designed to enable a program send and + * receive data from a device that communicates using the Modbus protocol. + * + * Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD. + * Modified for Waspmote by Libelium, 2016 + * + * This file is part of ModbusSlave. + * + * ModbusSlave is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * The functions included here have been derived from the + * Modbus Specifications and Implementation Guides + * + * http://www.modbus.org/docs/Modbus_over_serial_line_V1_02.pdf + * http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf + * http://www.modbus.org/docs/PI_MBUS_300.pdf + * + * + * Version: 3.0 + * + ****************************************************************************/ + +#define RS485_COM 0x01 +#define RS232_COM 0x02 + +/**************************************************************************** + * BEGIN MODBUS RTU SLAVE FUNCTIONS + ****************************************************************************/ + +#ifndef MODBUS_SLAVE_H +#define MODBUS_SLAVE_H + +#include +#include "Wasp232.h" +#include "Wasp485.h" + + +class ModbusSlave +{ + public: + + // Empty constructor + ModbusSlave(); + ModbusSlave(uint8_t); + ModbusSlave(uint8_t, uint8_t); + + // Configure the communication parameters + void configure(uint8_t, long); + void configure(uint8_t, long, uint8_t ); + // Update the registers + int update(int *regs, unsigned int regs_size); + + protected: + + unsigned char slave; + unsigned long Nowdt; + unsigned int lastBytesReceived; + const unsigned long T35 = 5; + uint8_t _protocol; + uint8_t _socket; + + + void modbus_reply(unsigned char *packet, unsigned char string_length); + int preset_multiple_registers(unsigned int start_addr,unsigned char count,unsigned char *query,int *regs); + int write_single_register(unsigned int write_addr, unsigned char *query, int *regs); + int read_holding_registers(unsigned int start_addr, unsigned char reg_count, int *regs); + void build_error_packet(unsigned char function,unsigned char exception, unsigned char *packet); + unsigned int crc(unsigned char *buf, unsigned char start, unsigned char cnt); + void build_read_packet(unsigned char function, unsigned char count, unsigned char *packet); + void build_write_packet(unsigned char function, unsigned int start_addr, unsigned char count, unsigned char *packet); + void build_write_single_packet(unsigned char function, unsigned int write_addr, unsigned int reg_val, unsigned char* packet); + int send_reply(unsigned char *query, unsigned char string_length); + int receive_request(unsigned char *received_string); + int modbus_request(unsigned char *data); + int validate_request(unsigned char *data, unsigned char length, unsigned int regs_size); + int write_regs(unsigned int start_addr, unsigned char *query, int *regs); +}; + +#endif + diff --git a/libraries/ModbusSlave/keywords.txt b/libraries/ModbusSlave/keywords.txt new file mode 100644 index 0000000..3bf9a8d --- /dev/null +++ b/libraries/ModbusSlave/keywords.txt @@ -0,0 +1,8 @@ +# ModbusSlave keywords # + +configure KEYWORD2 +update KEYWORD2 +ModbusSlave KEYWORD2 + +RS232_COM LITERAL1 +RS485_COM LITERAL1 diff --git a/libraries/OPC_N2/WaspOPC_N2.cpp b/libraries/OPC_N2/WaspOPC_N2.cpp index 809e4a4..e34dfdc 100755 --- a/libraries/OPC_N2/WaspOPC_N2.cpp +++ b/libraries/OPC_N2/WaspOPC_N2.cpp @@ -41,7 +41,7 @@ WaspOPC_N2::WaspOPC_N2() { // update Waspmote Control Register - WaspRegister |= REG_DUST_GASES_PRO; + WaspRegisterSensor |= REG_DUST_GASES_PRO; pinMode(DUST_SENSOR_CS,OUTPUT); digitalWrite(DUST_SENSOR_CS,HIGH); @@ -95,37 +95,63 @@ uint8_t WaspOPC_N2::checkStatus() USB.print(F("OPC-N2: Check status...")); #endif - SPI.setSPISlave(ALL_DESELECTED); - SPI.setSPISlave(DUST_SENSOR_SELECT); - delayMicroseconds(2); - while((val != CHECK_STATUS_READY)&&(times<100)) - { - val = SPI.transfer(CHECK_STATUS); - times++; - delay(50); - } - if (times<99) + if(_mode == OPC_N2_SPI_MODE) { - - error = 1; + SPI.setSPISlave(ALL_DESELECTED); + SPI.setSPISlave(DUST_SENSOR_SELECT); + delayMicroseconds(2); + while((val != CHECK_STATUS_READY)&&(times<100)) + { + val = SPI.transfer(CHECK_STATUS); + times++; + delay(50); + } + if (times<99) + { + + error = 1; #if OPC_N2_DEBUG>0 - USB.println(F("ready")); - #endif + USB.println(F("ready")); + #endif + } + else + { + error = 0; + #if OPC_N2_DEBUG>0 + USB.println(F("not ready")); + #endif + + } + + SPI.setSPISlave(ALL_DESELECTED); } else - { - error = 0; - #if OPC_N2_DEBUG>0 - USB.println(F("not ready")); - #endif - + { + times = 5; + do{ + error = sendCommand("AT\r", "OK",3000); + times--; + }while((times > 0) && (error != 1)); + + if (error == 1) + { + #if OPC_N2_DEBUG>0 + USB.println(F("ready")); + #endif + } + else + { + #if OPC_N2_DEBUG>0 + USB.println(F("not ready")); + #endif + + } } - - SPI.setSPISlave(ALL_DESELECTED); - + return error; } + /* Function: This function inits the SPI bus to use with OPC-N2 module * * Returns nothing @@ -146,42 +172,74 @@ void WaspOPC_N2::configSPI() * PUBLIC FUNCTIONS ******************************************************************************/ +uint8_t WaspOPC_N2::ON() +{ + return ON(OPC_N2_UART_MODE); +} /* Function: This function opens SPI port and powers the sensor * * Returns 0 if the sensor doesn't init correctly * 1 if init OK */ -uint8_t WaspOPC_N2::ON() +uint8_t WaspOPC_N2::ON(bool com_mode) { uint8_t error = 0; - pinMode(DUST_SENSOR_CS,OUTPUT); - digitalWrite(DUST_SENSOR_CS,HIGH); - delay(1000); - - - pinMode(DUST_SENSOR_POWER,OUTPUT); - digitalWrite(DUST_SENSOR_POWER,LOW); - delay(1000); - - digitalWrite(DUST_SENSOR_POWER,HIGH); - delay(1000); - - // update SPI flag - SPI.isDustSensor = true; + _mode = com_mode; + #if OPC_N2_DEBUG>0 + if(_mode == OPC_N2_SPI_MODE) + { + USB.println(F("OPC-N2.SPI Mode")); + } + else + { + USB.println(F("OPC-N2.UART Mode")); + } + #endif - configSPI(); + if (_mode == OPC_N2_SPI_MODE) + { - delay(1000); - if ((WaspRegister & REG_3V3) == 0) + pinMode(DUST_SENSOR_CS,OUTPUT); + digitalWrite(DUST_SENSOR_CS,HIGH); + delay(1000); + + + pinMode(DUST_SENSOR_POWER,OUTPUT); + digitalWrite(DUST_SENSOR_POWER,LOW); + delay(1000); + + digitalWrite(DUST_SENSOR_POWER,HIGH); + delay(1000); + + // update SPI flag + SPI.isDustSensor = true; + + configSPI(); + + delay(1000); + if ((WaspRegister & REG_3V3) == 0) + { + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.3V3 to ON")); + #endif + PWR.setSensorPower(SENS_3V3, SENS_ON); + } + delay(1000); + } + else { - #if OPC_N2_DEBUG>0 - USB.println(F("OPC-N2.3V3 to ON")); - #endif - PWR.setSensorPower(SENS_3V3, SENS_ON); + pinMode(DUST_SENSOR_POWER,OUTPUT); + + digitalWrite(DUST_SENSOR_POWER,HIGH); +// delay(15000); + delay(5000); + _baudrate = 9600; + _uart = 1; + beginUART(); + Utils.setMuxAux2(); } - delay(1000); error = checkStatus(); @@ -211,38 +269,56 @@ uint8_t WaspOPC_N2::OFF() { uint8_t error = 0; - #if OPC_N2_DEBUG>0 - USB.print(F("OPC-N2.Turning off sensor,")); - #endif - // Stopping SPI port - SPI.isDustSensor = false; - SPI.setSPISlave(ALL_DESELECTED); - pinMode(DUST_SENSOR_CS,INPUT); - SPI.close(); - - digitalWrite(DUST_SENSOR_POWER,LOW); - if (( pwrGasPRORegister == 0x01) || ( pwrGasPRORegister == 0x0)) - { - #if OPC_N2_DEBUG>0 - USB.println(F("3V3 off")); + if (_mode == OPC_N2_SPI_MODE) + { + #if OPC_N2_DEBUG>0 + USB.print(F("OPC-N2.Turning off sensor,")); + #endif + // Stopping SPI port + SPI.isDustSensor = false; + SPI.setSPISlave(ALL_DESELECTED); + pinMode(DUST_SENSOR_CS,INPUT); + SPI.close(); + + digitalWrite(DUST_SENSOR_POWER,LOW); + + if (( pwrGasPRORegister == 0x01) || ( pwrGasPRORegister == 0x0)) + { + #if OPC_N2_DEBUG>0 + USB.println(F("3V3 off")); + #endif + PWR.setSensorPower(SENS_3V3, SENS_OFF); + } + #if OPC_N2_DEBUG>0 + else + { + USB.println(F("3V3 NOT off")); + } #endif - PWR.setSensorPower(SENS_3V3, SENS_OFF); + + + if((digitalRead(DUST_SENSOR_CS) == HIGH) && (digitalRead(DUST_SENSOR_POWER) == LOW)) + { + error = 1; + pwrGasPRORegister &= 0xFE; + } + isON = 0; } - #if OPC_N2_DEBUG>0 else { - USB.println(F("3V3 NOT off")); - } - #endif - + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.Turning off sensor")); + #endif + + closeSerial(1); - if((digitalRead(DUST_SENSOR_CS) == HIGH) && (digitalRead(DUST_SENSOR_POWER) == LOW)) - { - error = 1; + digitalWrite(DUST_SENSOR_POWER,LOW); + + error = 1; pwrGasPRORegister &= 0xFE; + isON = 0; } - isON = 0; return error; @@ -265,46 +341,87 @@ int8_t WaspOPC_N2::getInfoString(char* buffer) #if OPC_N2_DEBUG>0 USB.println(F("OPC-N2.Reading information string")); #endif + + if (_mode == OPC_N2_SPI_MODE) + { - SPI.setSPISlave(DUST_SENSOR_SELECT); - delayMicroseconds(100); - while((val != CHECK_STATUS_READY) && (times<100)) - { - val = SPI.transfer(READ_INFO_STRING); - times++; - delay(30); + SPI.setSPISlave(DUST_SENSOR_SELECT); + delayMicroseconds(100); + while((val != CHECK_STATUS_READY) && (times<100)) + { + val = SPI.transfer(READ_INFO_STRING); + times++; + delay(30); + } + + if (times >= 100) + { + return -1; + } + + // At least 1.7 ms between command byte and following byte + delay(2); + + for(int i = 0; i < 58; i++) + { + buffer[i] = SPI.transfer(READ_INFO_STRING); + delayMicroseconds(8); + + } + + buffer[58] = '\0'; + + error = 1; + + #if OPC_N2_DEBUG>0 + for(int i = 0; i < 58; i++) + { + USB.print(buffer[i],HEX); + USB.print(" "); + } + USB.println(""); + #endif + + // Release the bus + SPI.setSPISlave(ALL_DESELECTED); } - - if (times >= 100) - { - return -1; - } - - // At least 1.7 ms between command byte and following byte - delay(2); - - for(int i = 0; i < 58; i++) + else { - buffer[i] = SPI.transfer(READ_INFO_STRING); - delayMicroseconds(8); + char command[10]; + uint32_t waitTime; - } - - buffer[58] = '\0'; - - error = 1; - - #if OPC_N2_DEBUG>0 - for(int i = 0; i < 58; i++) + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.Getting PM with fan on")); + #endif + + memset(command, '\0', sizeof(command)); + snprintf( command, sizeof(command), "AT$101\r"); + + beginSerial(9600, 1); + Utils.setMuxAux2(); + delay(100); + + error = sendCommand(command, "$101", "ERROR", 2000); + if( error != 1) { - USB.print(buffer[i],HEX); - USB.print(" "); + return -11; } - USB.println(""); - #endif - // Release the bus - SPI.setSPISlave(ALL_DESELECTED); + error = waitFor("OK", 2000); + if( error != 1) + { + return -12; + } + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.String received: ")); + USB.println((char*) _buffer); + #endif + + memset(buffer, '\0', 60); + strncpy(buffer, (char*)_buffer+1, 60); + + } + return error; } @@ -324,6 +441,14 @@ int8_t WaspOPC_N2::setDigitalPot(uint8_t mode) USB.print(F("OPC-N2.Setting digital pot")); #endif + if(_mode == OPC_N2_UART_MODE) + { + #if OPC_N2_DEBUG>0 + USB.println(F("... not supported in UART_MODE")); + #endif + return -3; + } + uint8_t command[2]; uint8_t command_answer[2]; @@ -399,88 +524,154 @@ int8_t WaspOPC_N2::getHistogramData() #if OPC_N2_DEBUG>0 USB.print(F("OPC-N2.Getting histogram data")); #endif - error = 1; - delay(100); + + if (_mode == OPC_N2_SPI_MODE) + { + + error = 1; + delay(100); - SPI.setSPISlave(DUST_SENSOR_SELECT); - // Read histogram data - while((val != CHECK_STATUS_READY) && (times < 100)) - { - val = SPI.transfer(READ_HISTOGRAM); - delay(10); - times++; - if (val != CHECK_STATUS_READY) + SPI.setSPISlave(DUST_SENSOR_SELECT); + // Read histogram data + while((val != CHECK_STATUS_READY) && (times < 100)) + { + val = SPI.transfer(READ_HISTOGRAM); + delay(10); + times++; + if (val != CHECK_STATUS_READY) + { + SPI.setSPISlave(ALL_DESELECTED); + delay(100); + SPI.setSPISlave(DUST_SENSOR_SELECT); + + } + + } + + if (times >= 100) { - SPI.setSPISlave(ALL_DESELECTED); - delay(100); - SPI.setSPISlave(DUST_SENSOR_SELECT); + #if OPC_N2_DEBUG>0 + USB.println(F("...failed. Communication error.")); + #endif + error = -1; + } + + + for(int i = 0; i < 62; i++) + { + delayMicroseconds(8); + histogramString[i] = SPI.transfer(0x30); + } + + SPI.setSPISlave(ALL_DESELECTED); + + crc = (histogramString[49] * 256) + histogramString[48]; + crc_bin=0; + for (int i = 0; i<16; i++) + { + _bin[i] = 0; + _bin[i] = (_bin[i] << 8) | histogramString[2*i+1]; + _bin[i] = (_bin[i] << 8) | histogramString[2*i]; + crc_bin += _bin[i]; + } + + + if (crc_bin != crc) + { + #if OPC_N2_DEBUG>0 + USB.println(F("...CRC NOK")); + USB.print(F("CRC bin: ")); + USB.print(crc_bin, DEC); + USB.print(F(" || CRC : ")); + USB.println(crc, DEC); + #endif + + error = -2; } - } - - if (times >= 100) - { #if OPC_N2_DEBUG>0 - USB.println(F("...failed. Communication error.")); + USB.println(F("...Done")); #endif - error = -1; - } - - for(int i = 0; i < 62; i++) - { - delayMicroseconds(8); - histogramString[i] = SPI.transfer(0x30); + _bin1_MToF = histogramString[32]; + _bin3_MToF = histogramString[33]; + _bin5_MToF = histogramString[34]; + _bin7_MToF = histogramString[35]; + + aux_val = *(uint32_t *)&histogramString[36]; + _temp = aux_val / 10.0; + aux_val = *(uint32_t *)&histogramString[40]; + _pressure = aux_val; + _periodCount = *(uint32_t *)&histogramString[44]; + + + _PM1 = *(float *)&histogramString[50]; + _PM2_5 = *(float *)&histogramString[54]; + _PM10 = *(float *)&histogramString[58]; } - - SPI.setSPISlave(ALL_DESELECTED); - - crc = (histogramString[49] * 256) + histogramString[48]; - crc_bin=0; - for (int i = 0; i<16; i++) + else { - _bin[i] = 0; - _bin[i] = (_bin[i] << 8) | histogramString[2*i+1]; - _bin[i] = (_bin[i] << 8) | histogramString[2*i]; - crc_bin += _bin[i]; - } - - - if (crc_bin != crc) - { + char command[10]; + uint32_t waitTime; + #if OPC_N2_DEBUG>0 - USB.println(F("...CRC NOK")); - USB.print(F("CRC bin: ")); - USB.print(crc_bin, DEC); - USB.print(F(" || CRC : ")); - USB.println(crc, DEC); + USB.println(F("OPC-N2.Getting PM with fan on")); #endif - - error = -2; + + for (int i = 0; i < 15; i++) + { + _bin[i] = 0; + } + + _temp = 0.0; + _pressure = 0.0; + _periodCount = 0; + _PM1 = 0.0; + _PM2_5 = 0.0; + _PM10 = 0.0; + + memset(command, '\0', sizeof(command)); + snprintf( command, sizeof(command), "AT$201\r"); + + beginSerial(9600, 1); + Utils.setMuxAux2(); + delay(100); + + error = sendCommand(command, "$201", "ERROR", 2000); + if( error != 1) + { + return -11; + } + + error = waitFor("OK", 2000); + if( error != 1) + { + return -12; + } + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.String received: ")); + USB.println((char*) _buffer); + #endif + _PM1 = strtod(strtok((char*)_buffer+1, ","), NULL); + _PM2_5 = strtod(strtok(NULL, ","), NULL); + _PM10 = strtod(strtok(NULL, ","), NULL); + + for (uint8_t i = 0; i < 16; i++) + { + _bin[i] = atoi(strtok(NULL, ",")); + } + + _bin1_MToF = atoi(strtok(NULL, ",")); + _bin3_MToF = atoi(strtok(NULL, ",")); + _bin5_MToF = atoi(strtok(NULL, ",")); + _bin7_MToF = atoi(strtok(NULL, ",")); + + _temp = strtod(strtok(NULL, ","), NULL); + _pressure = strtod(strtok(NULL, ","), NULL); + _periodCount = atol(strtok(NULL, "\r")); } - - #if OPC_N2_DEBUG>0 - USB.println(F("...Done")); - #endif - - - _bin1_MToF = histogramString[32]; - _bin3_MToF = histogramString[33]; - _bin5_MToF = histogramString[34]; - _bin7_MToF = histogramString[35]; - - aux_val = *(uint32_t *)&histogramString[36]; - _temp = aux_val / 10.0; - aux_val = *(uint32_t *)&histogramString[40]; - _pressure = aux_val; - _periodCount = *(uint32_t *)&histogramString[44]; - - - _PM1 = *(float *)&histogramString[50]; - _PM2_5 = *(float *)&histogramString[54]; - _PM10 = *(float *)&histogramString[58]; return error; } @@ -514,6 +705,14 @@ int8_t WaspOPC_N2::getConfigVar() USB.print(F("OPC-N2.Getting config variables")); #endif + if(_mode == OPC_N2_UART_MODE) + { + #if OPC_N2_DEBUG>0 + USB.println(F("... not supported in UART_MODE")); + #endif + return -3; + } + delay(100); SPI.setSPISlave(DUST_SENSOR_SELECT); @@ -664,10 +863,7 @@ int8_t WaspOPC_N2::getConfigVar() */ int8_t WaspOPC_N2::getPM(uint32_t timeSample) { - - - return getPM(0, timeSample); - + return getPM(0, timeSample); } /* Function: This function gets PM values (PM1, PM2_5 and PM10) @@ -698,48 +894,86 @@ int8_t WaspOPC_N2::getPM(uint32_t timeSample) int8_t WaspOPC_N2::getPM(uint32_t waitSample, uint32_t timeSample) { uint8_t error = 0; + char* pointer1; + char* pointer2; - #if OPC_N2_DEBUG>0 - USB.println(F("OPC-N2.Getting PM with fan on")); - #endif - - for (int i = 0; i < 15; i++) + if (_mode == OPC_N2_SPI_MODE) { - _bin[i] = 0; - } - - _temp = 0.0; - _pressure = 0.0; - _periodCount = 0; - _PM1 = 0.0; - _PM2_5 = 0.0; - _PM10 = 0.0; - configSPI(); - error = checkStatus(); - // Set digital pot ON - delay(100); - error = setDigitalPot(DIGITAL_POT_ON); - if (error != 1) - { - return error; - } + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.Getting PM with fan on")); + #endif + + for (int i = 0; i < 15; i++) + { + _bin[i] = 0; + } + + _temp = 0.0; + _pressure = 0.0; + _periodCount = 0; + _PM1 = 0.0; + _PM2_5 = 0.0; + _PM10 = 0.0; + configSPI(); + error = checkStatus(); + + // Set digital pot ON + delay(100); + error = setDigitalPot(DIGITAL_POT_ON); + if (error != 1) + { + return error; + } + + // Reset the histogram + delay(waitSample + 500); + error = getHistogramData(); + if (error != 1) + { + return error - 2; + } + + // Desired delay + delay(timeSample); + + // Read the histogram + error = getHistogramData(); + if (error != 1) + { + for (int i = 0; i < 15; i++) + { + _bin[i] = 0; + } + + _temp = 0.0; + _pressure = 0.0; + _periodCount = 0; + _PM1 = 0.0; + _PM2_5 = 0.0; + _PM10 = 0.0; + + return error - 4; + } + + // Set digital pot OFF + delay(100); + error = setDigitalPot(DIGITAL_POT_OFF); + if (error != 1) + { + return error - 6; + } - // Reset the histogram - delay(waitSample + 500); - error = getHistogramData(); - if (error != 1) - { - return error - 2; } - - // Desired delay - delay(timeSample); - - // Read the histogram - error = getHistogramData(); - if (error != 1) - { + else + { + char command[23]; + uint32_t waitTime; + + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.Getting PM with fan on")); + #endif + for (int i = 0; i < 15; i++) { _bin[i] = 0; @@ -752,19 +986,55 @@ int8_t WaspOPC_N2::getPM(uint32_t waitSample, uint32_t timeSample) _PM2_5 = 0.0; _PM10 = 0.0; - return error - 4; + memset(command, '\0', sizeof(command)); + snprintf( command, sizeof(command), "AT$200=%lu,%lu,2\r", + waitSample, timeSample); + waitTime = waitSample + timeSample + 5000; + + beginSerial(9600, 1); + Utils.setMuxAux2(); + delay(100); + + error = sendCommand(command, "$200", "ERROR", waitTime); + if( error != 1) + { + return -11; + } + + error = waitFor("OK", 2000); + if( error != 1) + { + return -12; + } + #if OPC_N2_DEBUG>0 + USB.println(F("OPC-N2.String received: ")); + USB.println((char*) _buffer); + #endif + _PM1 = strtod(strtok((char*)_buffer+1, ","), NULL); + _PM2_5 = strtod(strtok(NULL, ","), NULL); + _PM10 = strtod(strtok(NULL, ","), NULL); + + for (uint8_t i = 0; i < 16; i++) + { + _bin[i] = atoi(strtok(NULL, ",")); + } + + _bin1_MToF = atoi(strtok(NULL, ",")); + _bin3_MToF = atoi(strtok(NULL, ",")); + _bin5_MToF = atoi(strtok(NULL, ",")); + _bin7_MToF = atoi(strtok(NULL, ",")); + + _temp = strtod(strtok(NULL, ","), NULL); + _pressure = strtod(strtok(NULL, ","), NULL); + _periodCount = atol(strtok(NULL, "\r")); } - // Set digital pot OFF - delay(100); - error = setDigitalPot(DIGITAL_POT_OFF); - if (error != 1) - { - return error - 6; - } + return error; } + + /// Preinstantiate Objects ///////////////////////////////////////////////////// WaspOPC_N2 OPC_N2 = WaspOPC_N2(); diff --git a/libraries/OPC_N2/WaspOPC_N2.h b/libraries/OPC_N2/WaspOPC_N2.h index 3ed8e6e..645f308 100755 --- a/libraries/OPC_N2/WaspOPC_N2.h +++ b/libraries/OPC_N2/WaspOPC_N2.h @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Marcos Yarza, Alejandro Gállego @@ -46,6 +46,10 @@ #define DUST_SENSOR_POWER DIGITAL1 #define OPC_N2_DEBUG 0 +// #define OPC_N2_DEBUG 1 + +#define OPC_N2_SPI_MODE 0 +#define OPC_N2_UART_MODE 1 /// Sensor commands ///////////////////////////////////////////////////////////////// // COMMAND: Set digital pot @@ -68,10 +72,10 @@ const uint8_t READ_CONFIG_VAR PROGMEM = 0x3C; const uint8_t WRITE_CONFIG_VAR PROGMEM = 0x3A; // COMMAND: Read histogram -const uint8_t READ_HISTOGRAM PROGMEM = 0X30; // It will reset the histogram too +const uint8_t READ_HISTOGRAM PROGMEM = 0x30; // It will reset the histogram too // UNUSED COMMAND -const uint8_t SAVE_CONFIG PROGMEM = 0X43; +const uint8_t SAVE_CONFIG PROGMEM = 0x43; // COMMAND: Read sensor status const uint8_t CHECK_STATUS PROGMEM = 0xCF; @@ -89,7 +93,7 @@ extern volatile uint8_t pwrGasPRORegister; /*! WaspOPC_N2 Class defines all the variables and functions used to manage OPC N2 particle sensosr */ -class WaspOPC_N2 +class WaspOPC_N2 : public WaspUART { /// private methods ////////////////////////// @@ -101,12 +105,19 @@ class WaspOPC_N2 */ uint8_t isON; + //! Variable : working mode + /*! + * 0 if the sensor uses SPI, 1 if uses UART + */ + bool _mode; + //! This function checks if the OPC-N2 sensor is ready /*! \return 0 if not ready 1 if ready */ uint8_t checkStatus(); + //! This function inits the SPI bus to use with OPC-N2 module /*! @@ -239,13 +250,22 @@ class WaspOPC_N2 WaspOPC_N2(); /// Funtions /////////////////////////////////////////////////////////////// - //! This function opens SPI port and powers the sensor + //! This function opens UART port and powers the sensor /*! \return 0 if the sensor doesn't init correctly 1 if init OK */ uint8_t ON(); + //! This function opens desired communication port and powers the sensor + /*! + * + \param bool com_mode: 0 if the sensor uses SPI, 1 if uses UART + \return 0 if the sensor doesn't init correctly + 1 if init OK + */ + uint8_t ON(bool com_mode); + //! This function closes SPI port and powers OFF the sensor /*! \return 0 if the sensor doesn't power off correctly @@ -253,6 +273,13 @@ class WaspOPC_N2 */ uint8_t OFF(); + //! This function closes SPI port and powers OFF the sensor + /*! + \return 0 if the sensor doesn't power off correctly + 1 if powers off correctly + */ + uint8_t OFF_UART(); + //! This function reads the information string from OPC-N2 sensor /*! \param char* buffer: string pointer to store the information data diff --git a/libraries/OPC_N2/keywords.txt b/libraries/OPC_N2/keywords.txt index e4c6581..f77d69b 100644 --- a/libraries/OPC_N2/keywords.txt +++ b/libraries/OPC_N2/keywords.txt @@ -42,3 +42,4 @@ setDigitalPot KEYWORD2 getHistogramData KEYWORD2 getConfigVar KEYWORD2 getPM KEYWORD2 +OPC_N2 KEYWORD1 diff --git a/libraries/RFID1356/WaspRFID13.cpp b/libraries/RFID1356/WaspRFID13.cpp index 3ba3b54..3d35023 100644 --- a/libraries/RFID1356/WaspRFID13.cpp +++ b/libraries/RFID1356/WaspRFID13.cpp @@ -1,7 +1,7 @@ /*! \file WaspRFID.cpp - * \brief Library for managing WIFI modules + * \brief Library for managing RFID modules * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascn * Implementation: Ahmad Saad, Javier Solobera */ @@ -41,37 +41,23 @@ \param uint8_t socket: The uart por used */ void WaspRFID::ON(uint8_t socket) -{ - if (socket == SOCKET1) - { - // select uart - _uart = SOCKET1; - - // set uart baudrate - Utils.setMuxSocket1(); - beginSerial(RFID_RATE, _uart); - - // power supply - pinMode(DIGITAL6, OUTPUT); - digitalWrite(DIGITAL6, HIGH); - } - else - { - // select uart - _uart = SOCKET0; - - // set uart baudrate - Utils.setMuxSocket0(); - beginSerial(RFID_RATE, _uart); - - // power supply - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - } - - // update Waspmote Register - if(_uart == SOCKET0) WaspRegister |= REG_SOCKET0; - if(_uart == SOCKET1) WaspRegister |= REG_SOCKET1; +{ + // set uart + _uart = socket; + + // select multiplexer + if (_uart == SOCKET0) Utils.setMuxSocket0(); + if (_uart == SOCKET1) Utils.setMuxSocket1(); + + // open uart + beginSerial(RFID_RATE, _uart); + + // power on the socket + PWR.powerSocket(_uart, HIGH); + + // update Waspmote Register + if (_uart == SOCKET0) WaspRegister |= REG_SOCKET0; + if (_uart == SOCKET1) WaspRegister |= REG_SOCKET1; serialFlush(_uart); delay(100); @@ -87,19 +73,17 @@ void WaspRFID::OFF(void) // close UART closeSerial(_uart); - // update Waspmote Register - if(_uart == SOCKET0) WaspRegister &= ~(REG_SOCKET0); - if(_uart == SOCKET1) WaspRegister &= ~(REG_SOCKET1); + // unselect multiplexer + if (_uart == SOCKET0) Utils.setMuxUSB(); + if (_uart == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uart, LOW); - // power off depending on the socket - if (_uart == 1) - { - digitalWrite(DIGITAL6, LOW); - } - else - { - digitalWrite(XBEE_PW,LOW); - } + // update Waspmote Register + if (_uart == SOCKET0) WaspRegister &= ~(REG_SOCKET0); + if (_uart == SOCKET1) WaspRegister &= ~(REG_SOCKET1); + } diff --git a/libraries/RFID1356/WaspRFID13.h b/libraries/RFID1356/WaspRFID13.h index 3ed00cc..9e9bca7 100644 --- a/libraries/RFID1356/WaspRFID13.h +++ b/libraries/RFID1356/WaspRFID13.h @@ -1,7 +1,7 @@ -/*! \file WaspRFDI.h +/*! \file WaspRFID.h - \brief Library for managing the accelerometer LIS3LV02DL - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + \brief Library for managing the RFID module + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascn Implementation: Ahmad Saad, Javier Solobera */ diff --git a/libraries/RFID1356/keywords.txt b/libraries/RFID1356/keywords.txt index c19098d..cbf4bdf 100755 --- a/libraries/RFID1356/keywords.txt +++ b/libraries/RFID1356/keywords.txt @@ -23,6 +23,69 @@ searchUID KEYWORD2 string2vector KEYWORD2 vector2int KEYWORD2 setKeys KEYWORD2 -WaspRFID13 KEYWORD2 +WaspRFID13 KEYWORD1 +PREAMBLE KEYWORD1 +STARTCODE1 KEYWORD1 +STARTCODE2 KEYWORD1 +POSTAMBLE KEYWORD1 +HOSTTOPN532 KEYWORD1 +FIRMWAREVERSION KEYWORD1 +GETGENERALSTATUS KEYWORD1 +SAMCONFIGURATION KEYWORD1 +INLISTPASSIVETARGET KEYWORD1 +INDATAEXCHANGE KEYWORD1 +MIFARE_READ KEYWORD1 +MIFARE_WRITE KEYWORD1 +AUTH_WITH_KEYA KEYWORD1 +GETFIRMWAREVERSION KEYWORD1 +READREGISTER KEYWORD1 +WRITEREGISTER KEYWORD1 +READGPIO KEYWORD1 +WRITEGPIO KEYWORD1 +SETSERIALBAUDRATE KEYWORD1 +SETPARAMETERS KEYWORD1 +POWERDOWN KEYWORD1 +RFCONFIGURATION KEYWORD1 +RFREGULATIONTEST KEYWORD1 +INATR KEYWORD1 +INPSL KEYWORD1 +INCOMMUNICATETHRU KEYWORD1 +INDESELECT KEYWORD1 +INRELEASE KEYWORD1 +INSELECT KEYWORD1 +INAUTOPOLL KEYWORD1 +TGINITASTARGET KEYWORD1 +TGSETGENERALBYTES KEYWORD1 +PN532_WAKEUP KEYWORD1 +PN532_MIFARE_ISO14443A KEYWORD1 +MIFARE_CMD_AUTH_A KEYWORD1 +MIFARE_CMD_AUTH_B KEYWORD1 +MIFARE_CMD_READ KEYWORD1 +MIFARE_CMD_WRITE KEYWORD1 +MIFARE_CMD_TRANSFER KEYWORD1 +MIFARE_CMD_DECREMENT KEYWORD1 +MIFARE_CMD_INCREMENT KEYWORD1 +MIFARE_CMD_STORE KEYWORD1 +RFID_RATE +_delay 1 KEYWORD2 +timeOut KEYWORD2 +keyOld KEYWORD2 +keyA KEYWORD2 +keyB KEYWORD2 +config KEYWORD2 +add KEYWORD2 +dataRX KEYWORD2 +dataTX KEYWORD2 +keyAccess KEYWORD2 +_uart KEYWORD2 +_UID KEYWORD2 +_ATQ KEYWORD2 +configureSAM KEYWORD2 +sendTX KEYWORD2 +getACK KEYWORD2 +waitResponse KEYWORD2 +getData KEYWORD2 +checkSum KEYWORD2 +lengthCheckSum KEYWORD2 diff --git a/libraries/RS232/Wasp232.cpp b/libraries/RS232/Wasp232.cpp index 740246c..95568a6 100644 --- a/libraries/RS232/Wasp232.cpp +++ b/libraries/RS232/Wasp232.cpp @@ -1,7 +1,7 @@ /*! \file Wasp232.cpp \brief Library for managing RS-232 module - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 - Design: David Gascn + Version: 3.0 + Design: David Gascon Implementation: Ahmad Saad */ @@ -48,36 +48,20 @@ //!************************************************************* void Wasp232::ON(char socket) { - if (socket == SOCKET0) - { - // set Mux - Utils.setMuxSocket0(); - - // power on - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - - // update attribute - _uart = SOCKET0; - } - else if (socket == SOCKET1) - { - // set Mux - Utils.setMuxSocket1(); - - // power on - pinMode(DIGITAL6, OUTPUT); - digitalWrite(DIGITAL6, HIGH); - - // update attribute - _uart = SOCKET1; - } + // set uart + _uart = socket; - // update Waspmote Register - if(_uart == SOCKET0) WaspRegister |= REG_SOCKET0; - if(_uart == SOCKET1) WaspRegister |= REG_SOCKET1; + // select multiplexer + if (_uart == SOCKET0) Utils.setMuxSocket0(); + if (_uart == SOCKET1) Utils.setMuxSocket1(); - // wait stabilization time + // Open UART + beginUART(); + + // power on the socket + PWR.powerSocket(_uart, HIGH); + + // wait stabilization time delay(100); } @@ -91,17 +75,15 @@ void Wasp232::ON(char socket) //!************************************************************* void Wasp232::OFF(void) { - closeSerial(_uart); + // close uart + closeUART(); - // update Waspmote Register - if(_uart == SOCKET0) WaspRegister &= ~(REG_SOCKET0); - if(_uart == SOCKET1) WaspRegister &= ~(REG_SOCKET1); - - if (_uart == 1) { - digitalWrite(DIGITAL6, LOW); - } else { - digitalWrite(XBEE_PW,LOW); - } + // unselect multiplexer + if (_uart == SOCKET0) Utils.setMuxUSB(); + if (_uart == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uart, LOW); } diff --git a/libraries/RS232/Wasp232.h b/libraries/RS232/Wasp232.h index bb71746..0260c03 100644 --- a/libraries/RS232/Wasp232.h +++ b/libraries/RS232/Wasp232.h @@ -1,7 +1,7 @@ /*! \file Wasp232.h \brief Library for managing RS-232 module - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascn Implementation: Ahmad Saad diff --git a/libraries/RS232/keywords.txt b/libraries/RS232/keywords.txt index 070ecb8..edcd30d 100644 --- a/libraries/RS232/keywords.txt +++ b/libraries/RS232/keywords.txt @@ -19,4 +19,4 @@ flush KEYWORD2 parityBit KEYWORD2 stopBitConfig KEYWORD2 -W232 KEYWORD3 +W232 KEYWORD1 diff --git a/libraries/RS485/Wasp485.cpp b/libraries/RS485/Wasp485.cpp index 9308f9a..7995596 100644 --- a/libraries/RS485/Wasp485.cpp +++ b/libraries/RS485/Wasp485.cpp @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascn Implementation: Ahmad Saad */ @@ -53,30 +53,34 @@ Wasp485::Wasp485() //!************************************************************* uint8_t Wasp485::ON() { + // Switch ON the module in Socket0 + PWR.powerSocket(SOCKET0, HIGH); + // Configure the SS pin and the switch as outputs - pinMode(XBEE_PW, OUTPUT); - pinMode(MAX_SS, OUTPUT); - SPI.isRS485 = true; + pinMode(SOCKET0_SS, OUTPUT); + SPI.isSocket0 = true; // Deselect the MAX chip - digitalWrite(MAX_SS, HIGH); - delay(100); - // Switch ON the module in the XBee socket - digitalWrite(XBEE_PW,HIGH); - delay(100); + digitalWrite(SOCKET0_SS, HIGH); + delay(200); + //Configure the MISO, MOSI, CS, SPCR. SPI.secureBegin(); SPI.begin(); - + //Set Most significant bit first SPI.setBitOrder(MSBFIRST); + //Divide the clock frequency SPI.setClockDivider(SPI_CLOCK_DIV2); //Set data mode + SPI.setDataMode(SPI_MODE0); - delay(100); + + //Configure 8-bits comunnication mode maxWrite(LCR_REG , 0x03); + //Disables clock pre dividier. maxWrite(PLLCFG_REG , 0x01); @@ -96,9 +100,10 @@ uint8_t Wasp485::ON() //!************************************************************* void Wasp485::OFF(void) { - digitalWrite(XBEE_PW,LOW); - SPI.isSX = false; - SPI.secureEnd(); + PWR.powerSocket(SOCKET0, LOW); + + SPI.isSocket0 = false; + SPI.close(); } @@ -319,7 +324,7 @@ uint8_t Wasp485::baudRateConfig(unsigned long speed) maxWrite(BRGDIVLSB_REG, 0xC0); maxWrite(BRGDIVMSB_REG, 0x00); } - + //!Return 0 if all success. Else return 1. if (maxRead(CLKSRC_REG) == 0x1A) return 0; @@ -455,10 +460,12 @@ void Wasp485::maxWrite(char address, char data) { // Disable all SPI slaves SPI.setSPISlave(ALL_DESELECTED); + delay(1); // Select SX slave SPI.setSPISlave(SOCKET0_SELECT); SPI.transfer(0x80 | address); + SPI.transfer(data); // Disable all SPI slaves @@ -476,6 +483,7 @@ uint8_t Wasp485::maxRead(char address) { // Disable all SPI slaves SPI.setSPISlave(ALL_DESELECTED); + delay(1); // Select SX slave SPI.setSPISlave(SOCKET0_SELECT); @@ -484,6 +492,7 @@ uint8_t Wasp485::maxRead(char address) // Disable all SPI slaves SPI.setSPISlave(ALL_DESELECTED); + return data; } diff --git a/libraries/RS485/Wasp485.h b/libraries/RS485/Wasp485.h index af0eb05..61ded24 100644 --- a/libraries/RS485/Wasp485.h +++ b/libraries/RS485/Wasp485.h @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascn Implementation: Ahmad Saad @@ -73,7 +73,7 @@ #define DISABLE 0 #define ONE_STOP_BIT 1 #define TWO_STOP_BITS 2 -#define MAX_SS 34 + /****************************************************************************** * Includes diff --git a/libraries/SX1272/WaspSX1272.cpp b/libraries/SX1272/WaspSX1272.cpp index aa3a98c..fb09964 100644 --- a/libraries/SX1272/WaspSX1272.cpp +++ b/libraries/SX1272/WaspSX1272.cpp @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.0 * Design: David Gascón * Implementation: Covadonga Albiñana, Yuri Carmona */ @@ -69,9 +69,10 @@ uint8_t WaspSX1272::ON() #endif // Powering the module - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - SPI.isSX = true; + PWR.powerSocket(SOCKET0, HIGH); + + // update SPI flag + SPI.isSocket0 = true; //Configure the MISO, MOSI, CS, SPCR. SPI.begin(); @@ -114,16 +115,15 @@ void WaspSX1272::OFF() USB.println(F("Starting 'OFF'")); #endif - // disable Semtech SPI flag - SPI.isSX = false; + // disable SPI flag + SPI.isSocket0 = false; // close SPI bus if it is posible SPI.close(); - // Power off - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,LOW); - - #if (SX1272_debug_mode > 1) + // Powering the module + PWR.powerSocket(SOCKET0, LOW); + + #if (SX1272_debug_mode > 1) USB.println(F("## Setting OFF ##")); USB.println(); #endif @@ -139,17 +139,18 @@ byte WaspSX1272::readRegister(byte address) { byte value = 0x00; - // Disable all SPI slaves - SPI.setSPISlave(ALL_DESELECTED); // Select SX slave SPI.setSPISlave(SOCKET0_SELECT); - //PRUEBA SPI + // read from module delay(1); bitClear(address, 7); // Bit 7 cleared to write in registers SPI.transfer(address); value = SPI.transfer(0x00); + // Disable all SPI slaves + SPI.setSPISlave(ALL_DESELECTED); + #if (SX1272_debug_mode > 1) USB.print(F("## Reading: ##\t")); USB.print(F("Register ")); @@ -171,16 +172,16 @@ byte WaspSX1272::readRegister(byte address) */ void WaspSX1272::writeRegister(byte address, byte data) { - // Disable all SPI slaves - SPI.setSPISlave(ALL_DESELECTED); // Select SX slave SPI.setSPISlave(SOCKET0_SELECT); - - //PRUEBA SPI + + // write to module delay(1); bitSet(address, 7); // Bit 7 set to read from registers SPI.transfer(address); SPI.transfer(data); + + // Disable all SPI slaves SPI.setSPISlave(ALL_DESELECTED); #if (SX1272_debug_mode > 1) @@ -666,7 +667,7 @@ uint8_t WaspSX1272::getHeader() #endif // take out bit 2 from REG_MODEM_CONFIG1 indicates ImplicitHeaderModeOn - if( bitRead(REG_MODEM_CONFIG1, 2) == 0 ) + if( bitRead(readRegister(REG_MODEM_CONFIG1), 2) == 0 ) { // explicit header mode (ON) _header = HEADER_ON; state = 1; diff --git a/libraries/SX1272/WaspSX1272.h b/libraries/SX1272/WaspSX1272.h index 9b92621..075ab1c 100644 --- a/libraries/SX1272/WaspSX1272.h +++ b/libraries/SX1272/WaspSX1272.h @@ -1,7 +1,7 @@ /*! \file WaspSX1272.h \brief Library for managing Semtech modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Covadonga Albiñana, Yuri Carmona diff --git a/libraries/SX1272/keywords.txt b/libraries/SX1272/keywords.txt index bbddef4..17bbed1 100644 --- a/libraries/SX1272/keywords.txt +++ b/libraries/SX1272/keywords.txt @@ -171,6 +171,16 @@ t MESH_TIMEOUT LITERAL1 MAX_RETRIES LITERAL1 CORRECT_PACKET LITERAL1 INCORRECT_PACKET LITERAL1 +REG_FIFO_RX_CURRENT_ADDR LITERAL1 +REG_RX_HEADER_CNT_VALUE_MSB LITERAL1 +REG_RX_HEADER_CNT_VALUE_LSB LITERAL1 +REG_RX_PACKET_CNT_VALUE_MSB LITERAL1 +REG_RX_PACKET_CNT_VALUE_LSB LITERAL1 +FSK_STANDBY_MODE LITERAL1 +MAX_TIMEOUT LITERAL1 +MAX_WAIT LITERAL1 +MESH_TIMEOUT LITERAL1 + WaspSX1272 KEYWORD2 ON KEYWORD2 @@ -272,5 +282,9 @@ packet_received KEYWORD2 ACK KEYWORD2 _temp KEYWORD2 _sendTime KEYWORD2 +getCR KEYWORD2 +setACK KEYWORD2 +getACK KEYWORD2 +sendPacketMAXTimeoutACKRetries KEYWORD2 -sx1272 KEYWORD3 +sx1272 KEYWORD1 diff --git a/libraries/SensorAgr_v20/WaspSensorAgr_v20.cpp b/libraries/SensorAgr_v20/WaspSensorAgr_v20.cpp index caafb2a..286549b 100755 --- a/libraries/SensorAgr_v20/WaspSensorAgr_v20.cpp +++ b/libraries/SensorAgr_v20/WaspSensorAgr_v20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.6 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Manuel Calahorra, Yuri Carmona */ @@ -63,7 +63,7 @@ WaspSensorAgr_v20::WaspSensorAgr_v20() memset( plv_array, 0x00, sizeof(plv_array) ); // update Waspmote Control Register - WaspRegister |= REG_AGRICULTURE; + WaspRegisterSensor |= REG_AGRICULTURE; } // Public Methods ////////////////////////////////////////////////////////////// @@ -506,7 +506,10 @@ float WaspSensorAgr_v20::readDendrometer(void) byte data_dendro[3] = {0,0,0}; float value_dendro = 0; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(300); Wire.beginTransmission(I2C_ADDRESS_AGR_DENDROMETER); @@ -519,13 +522,14 @@ float WaspSensorAgr_v20::readDendrometer(void) Wire.requestFrom(I2C_ADDRESS_AGR_DENDROMETER, 3); int i=0; - while(Wire.available()) + while (Wire.available()) { data_dendro[i]=Wire.receive(); i++; } - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -604,7 +608,10 @@ float WaspSensorAgr_v20::readPT1000(void) byte data_pt1000[3] = {0,0,0}; float value_pt1000 = 0; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(300); Wire.beginTransmission(I2C_ADDRESS_AGR_PT1000); @@ -617,13 +624,14 @@ float WaspSensorAgr_v20::readPT1000(void) Wire.requestFrom(I2C_ADDRESS_AGR_PT1000, 3); int k=0; - while(Wire.available()) + while (Wire.available()) { data_pt1000[k]=Wire.receive(); k++; } - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -643,20 +651,24 @@ float WaspSensorAgr_v20::readRadiation(void) long val = 0; float val_def = 0; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(150); Wire.requestFrom(I2C_ADDRESS_AGR_RADIATION, 2); int i = 0; - while(Wire.available()) + while (Wire.available()) { data_apogee[i] = Wire.receive(); i++; } - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } diff --git a/libraries/SensorAgr_v20/WaspSensorAgr_v20.h b/libraries/SensorAgr_v20/WaspSensorAgr_v20.h index b6629b1..d4b0d33 100755 --- a/libraries/SensorAgr_v20/WaspSensorAgr_v20.h +++ b/libraries/SensorAgr_v20/WaspSensorAgr_v20.h @@ -1,7 +1,7 @@ /*! \file WaspSensorAgr_v20.h \brief Library for managing the Agriculture Sensor Board v2.0 - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra, Yuri Carmona diff --git a/libraries/SensorAgr_v20/keywords.txt b/libraries/SensorAgr_v20/keywords.txt index f672c05..c8276fc 100644 --- a/libraries/SensorAgr_v20/keywords.txt +++ b/libraries/SensorAgr_v20/keywords.txt @@ -45,6 +45,7 @@ SENS_AGR_VANE_S LITERAL1 SENS_AGR_VANE_SSE LITERAL1 SENS_AGR_VANE_SE LITERAL1 SENS_AGR_VANE_ESE LITERAL1 +SENS_AGR_PLUVIOMETER LITERAL1 vaneDirection KEYWORD2 gustWind KEYWORD2 @@ -64,4 +65,4 @@ readPluviometerHour KEYWORD2 readPluviometerCurrent KEYWORD2 readPluviometerDay KEYWORD2 readPluviometer KEYWORD2 -SensorAgrv20 KEYWORD3 +SensorAgrv20 KEYWORD1 diff --git a/libraries/SensorAgr_v30/WaspSensorAgr_v30.cpp b/libraries/SensorAgr_v30/WaspSensorAgr_v30.cpp new file mode 100755 index 0000000..044e6ae --- /dev/null +++ b/libraries/SensorAgr_v30/WaspSensorAgr_v30.cpp @@ -0,0 +1,1282 @@ +/* + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.1 + * Design: David Gascón + * Implementation: Carlos Bello + */ +#ifndef __WPROGRAM_H__ + #include +#endif + +// BME280 library for reading temperature, humidity and pressure values +#include "BME280.h" +#include "Wire.h" +#include "WaspConstants.h" +#include "WaspSensorAgr_v30.h" +#include "UltrasoundSensor.h" +#include + +//********************************************************************** +// AGRICULTURE SENSOR BOARD CLASS +//********************************************************************** +//!********************************************************************* +//! Name: WaspSensorAgr_v30() +//! Description: Class contructor +//! Param : void +//! Returns: void +//!********************************************************************* +WaspSensorAgr_v30::WaspSensorAgr_v30() +{ + // init power supply to OFF state + PWR.setSensorPower(SENS_3V3, SENS_OFF); + // clear array + //memset( plv_array, 0x00, sizeof(plv_array) ); +} + +//!********************************************************************* +//! Name: ON() +//! Description: Switch ON the power supply and configure the I/O pins +//! Param : void +//! Returns: void +//!********************************************************************* +void WaspSensorAgr_v30::ON() { + // Configure pins + pinMode(DIGITAL0,OUTPUT); //E4 PWM2 RESERVED + pinMode(DIGITAL1,OUTPUT); //WATERMARK POWER ON + pinMode(DIGITAL2,INPUT); //ANEMOMETER SIGNAL INPUT + pinMode(DIGITAL3,OUTPUT); //I2C MAIN PIN + pinMode(DIGITAL5,OUTPUT); //DENTROMETER AND PT1000 POWER ON + pinMode(DIGITAL6,OUTPUT); //ADDRESS B WATERMARK + pinMode(DIGITAL7,OUTPUT); //RADIATION POWER ON + pinMode(DIGITAL8,OUTPUT); //ADDRESS A WATERMARK + + pinMode(ANA0,OUTPUT); //WEATHER STATION POWER ON + pinMode(ANA1,OUTPUT); //NO USE + pinMode(ANA3,INPUT); //PLUVIOMETER DATA + pinMode(ANA5,INPUT); //WATERMARK DATA + pinMode(ANA6,OUTPUT); //LEAF WETNESS POWER ON + delay(10); + //I2C ISOLATOR PIN ENABLE + pinMode(I2C_PIN_OE, OUTPUT); + digitalWrite(I2C_PIN_OE, LOW); + // Switch ON 3V3 for supplying the board + PWR.setSensorPower(SENS_3V3, SENS_ON); + + if (_boot_version < 'H') + { + USB.println(F("\n*************** WARNING *******************")); + USB.println(F("This example is valid only for Waspmote v15.")); + USB.println(F("Your Waspmote version is v12.")); + USB.println(F("*******************************************")); + return (void)0; + } +} + +//!********************************************************************* +//! Name: OFF() +//! Description: Switch OFF the power supply +//! Param : void +//! Returns: void +//!********************************************************************* +void WaspSensorAgr_v30::OFF(){ + digitalWrite(DIGITAL0,LOW); + digitalWrite(DIGITAL4,LOW); + digitalWrite(DIGITAL7,LOW); + digitalWrite(ANA0,LOW); + digitalWrite(ANA1,LOW); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + // Switch OFF 3V3 + PWR.setSensorPower(SENS_3V3, SENS_OFF); + delay(100); +} +/* conversion: converts the value read from the PT1000 and dendrometer ADC into + * the units of the sensor + * Parameters: byte data_input[3] : three bytes from the ADC conversion + * uint8_t type : 1 for PT1000 reading, 0 for dendrometer reading + * Return: float value : temperature (ºC) or diameter (mm) in function of the sensor + * + */ +float WaspSensorAgr_v30::conversion(byte data_input[3], uint8_t type) +{ + long val = 0; + float val_def = 0; + int signo = 0; + int overflow = 0; + float Vcc = 3.3; + float R1 = 1005.0; + float R2 = 1005.0; + float R3 = 1005.0; + float Rx = 0.0; + float tempPt = 0.0; + float equis = 0.0; + + signo = int(data_input[0] >> 7); + overflow = int((data_input[0] >> 6)&B00000001); + + val = long((data_input[2] >> 6)&B00000011) + long(data_input[1])*4 + + long((data_input[0])&B00111111)*1024; + + if (signo == 1) + { + if (overflow == 1) + { + //OVERFLOW High + val_def = 2; + } + else + { + val_def = val*1.5; + val_def = val_def/65535; + } + } + else + { + if (overflow == 0) + { + //OVERFLOW LOW + val_def = -2; + } + else + { + val_def = -(65535 - val)*1.5; + val_def = val_def/65535; + } + } + + if( type==1 ){ + Rx = (Vcc*R2*R3 + val_def*R3*(R1+R2)) / (Vcc*R1 - val_def*(R1+R2)); + equis = (Rx - 1001.52) / 1351.99; + Rx = equis * 1494.46 + 996.04; + tempPt = (Rx-1000)/3.9083; + return(tempPt); + } + else if( type==0) return ( (val_def * 11000)/1000.0 ); + + return 0; +} +/* sleepAgr: Calls the sleepAgr without agriculture interruptions + * Parameters: const char* time2wake + * uint8_t offset + * uint8_t mode + * uint8_t option + * + * See deepSleep function in PWR library + * + * Return: void + * + */ + +void WaspSensorAgr_v30::sleepAgr(const char* time2wake, + uint8_t offset, + uint8_t mode, + uint8_t option) +{ + #if DEBUG_AGR > 0 + PRINT_AGR(F("sleepAgr function:\r\n")); + #endif + sleepAgr(time2wake, offset, mode, option, 0); +} + +/* sleepAgr: sleep function to turn off the sensors without disabling the board + * Parameters: const char* time2wake + * uint8_t offset + * uint8_t mode + * uint8_t option + * + * See deepSleep function in PWR library + * + * Return: void + * + */ + +void WaspSensorAgr_v30::sleepAgr(const char* time2wake, + uint8_t offset, + uint8_t mode, + uint8_t option, + uint8_t agr_interrupt) +{ + #if DEBUG_AGR > 0 + PRINT_AGR(F("sleepAgr interrupt function:\r\n")); + #endif + // Set RTC alarme to wake up from Sleep Power Down Mode + uint8_t retries=0; + // Switch off both multiplexers in UART_0 and UART_1 + Utils.muxOFF(); + + // mandatory delay to wait for MUX_RX stabilization + delay(100); + + // set the XBee monitorization pin to zero + pinMode(XBEE_MON,OUTPUT); + digitalWrite(XBEE_MON,LOW); + + // set RTC alarm to wake up at specified time + RTC.ON(); + RTC.setAlarm1(time2wake,offset,mode); + RTC.OFF(); + + // switch off sensors power supply + digitalWrite(DIGITAL0,LOW); + digitalWrite(DIGITAL2,LOW); + digitalWrite(DIGITAL3,LOW); + digitalWrite(DIGITAL4,LOW); + digitalWrite(DIGITAL6,LOW); + digitalWrite(DIGITAL7,LOW); + digitalWrite(ANA0,LOW); + digitalWrite(ANA1,LOW); + digitalWrite(ANA2,LOW); + digitalWrite(ANA3,LOW); + digitalWrite(ANA4,LOW); + digitalWrite(ANA5,LOW); + + // switches off depending on the option selected + PWR.switchesOFF(option); + + // enable PLV interruption if selected + if (agr_interrupt & SENS_AGR_PLUVIOMETER) + { + enableInterrupts(PLV_INT); + } + + // make sure interruption pin is LOW before entering a low power state + // if not the interruption will never come + while(digitalRead(MUX_RX)==HIGH) + { + // clear all detected interruption signals + delay(1); + PWR.clearInterruptionPin(); + retries++; + if(retries>10) + { + return (void)0; + } + } + + // set sleep mode + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_enable(); + sleep_mode(); + sleep_disable(); + + // in the case SENS_OFF was an option is mandatory to turn on the + // sensor boards before setting up the I2C bus + PWR.switchesON(option); + + // Switch on the RTC and clear the alarm signals + // Disable RTC interruption after waking up + // Except if the pluviometer interruption has woken-up the device. Then it + // is supposed to enter sleep mode in a few seconds + if( !(intFlag & PLV_INT) ) + { + RTC.ON(); + RTC.disableAlarm1(); + RTC.clearAlarmFlag(); + RTC.OFF(); + } + + // Keep sensor supply powered down if selected + if( option & SENS_OFF ) + { + // switch off the power supplies + PWR.setSensorPower(SENS_3V3, SENS_OFF); + PWR.setSensorPower(SENS_5V, SENS_OFF); + } +} + +//!********************************************************************* +//! Name: getTemperature() +//! Description: Gets the temperature from the BME280 sensor +//! Param : void +//! Returns: float: temperature value read +//!********************************************************************* +float WaspSensorAgr_v30::getTemperature() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + value = BME.getTemperature(BME280_OVERSAMP_1X, 0); + #if DEBUG_AGR==1 + PRINT_AGR(F("getTemperature:")); + USB.println(value); + #endif + + #if DEBUG_AGR==2 + PRINT_AGR(F("getTemperature:")); + USB.println(value); + PRINT_AGR(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + + // Read the temperature from the BME280 Sensor + return value; +} + +//!********************************************************************* +//! Name: getHumidity() +//! Description: Gets the Humidity from the BME280 sensor +//! Param : void +//! Returns: float: humidity value read +//!********************************************************************* +float WaspSensorAgr_v30::getHumidity() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + // Read the humidity from the BME280 Sensor + value = BME.getHumidity(BME280_OVERSAMP_1X); + #if DEBUG_AGR==1 + PRINT_AGR(F("getHumidity:")); + USB.println(value); + #endif + + #if DEBUG_AGR==2 + PRINT_AGR(F("getHumidity:")); + USB.println(value); + PRINT_AGR(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + // Read the temperature from the BME280 Sensor + return value; +} + +//!********************************************************************* +//! Name: getPressure() +//! Description: Gets the Pressure from the BME280 sensor +//! Param : void +//! Returns: float: pressure value read +//!********************************************************************* +float WaspSensorAgr_v30::getPressure() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + // Read the pressure from the BME280 Sensor + value = BME.getPressure(BME280_OVERSAMP_1X, 0); + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + #if DEBUG_AGR==1 + PRINT_AGR(F("getPressure:")); + USB.println(value); + #endif + + #if DEBUG_AGR==2 + PRINT_AGR(F("getPressure:")); + USB.println(value); + PRINT_AGR(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + // Read the temperature from the BME280 Sensor + return value; +} + +//!********************************************************************* +//! Name: getDistance() +//! Description: Gets distance from Ultrasound Sensor +//! Param : void +//! Returns: float: distance value read +//!********************************************************************* +uint16_t WaspSensorAgr_v30::getDistance(){ + uint16_t value; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + value = Ultrasound.getDistance(); + delay(100); + + #if DEBUG_AGR > 0 + PRINT_AGR(F("getDistance function: ")); + USB.println(value); + #endif + + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + return value; +} + +//!********************************************************************* +//! Name: getLuxes() +//! Description: Gets luxes from TSL2561 +//! Param : gain ( OUTDOOR OR INDOOR) +//! Returns: float: luxes value read +//!********************************************************************* +uint32_t WaspSensorAgr_v30::getLuxes(uint8_t gain){ + uint32_t value; + TSL.ON(); + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + switch (gain) + { + case OUTDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_1); + break; + + case INDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_16); + break; + } + #if DEBUG_AGR >= 1 + PRINT_AGR(F("getLuxes function: ")); + USB.println(value); + #endif + value = TSL.lux; + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + return value; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// +WaspSensorAgr_v30 Agriculture = WaspSensorAgr_v30(); + + + +/* + * Class constructor + * + */ +watermarkClass::watermarkClass(uint8_t socket) +{ + _watermarkSocket = socket; +} + +/* readWatermark: reads the frequency of the adaptation circuit of the Watermark + * sensor indicated in sens + * Return: float value : watermark circuit frequency + * -1 if wrong sensor selected + * + */ +float watermarkClass::readWatermark() +{ + int value = 0; + int previous_value = 0; + int counter = 0; + float freq = 0; + + // switch on + digitalWrite(WATERMARK_ON,HIGH); + + switch (_watermarkSocket) + { + case SOCKET_1: + case SOCKET_B: + digitalWrite(WATERMARK_DIR_A,LOW); + digitalWrite(WATERMARK_DIR_B,LOW); + break; + case SOCKET_2: + case SOCKET_E: + digitalWrite(WATERMARK_DIR_A,HIGH); + digitalWrite(WATERMARK_DIR_B,LOW); + break; + case SOCKET_3: + case SOCKET_C: + digitalWrite(WATERMARK_DIR_A,LOW); + digitalWrite(WATERMARK_DIR_B,HIGH); + break; + } + + #if DEBUG_AGR==2 + PRINT_AGR(F("readWatermark Select:")); + USB.println(_watermarkSocket); + #endif + + const uint32_t total_timeout = 10000; + const uint32_t total_counts = 500; + uint32_t current_millis; + uint32_t previous = millis(); + + // init counter + counter = 0; + + while (counter < total_counts) + { + previous_value = value; + value = digitalRead(ANA5); + if ((previous_value == 1) && (value == 0)) + { + counter++; + } + + // get current 'millis' time + current_millis = millis(); + + if (current_millis-previous > total_timeout) + { + break; + } + else if (current_millis < previous) + { + previous = millis(); + } + } + + // switch off + digitalWrite(WATERMARK_ON,LOW); + + if (counter >= total_counts) + { + return freq = ((float)total_counts*1000.0) / float((millis() - previous)); + } + + // check no counts (bad behaviour) + if (counter == 0) + { + return 0; + } + + return freq = (float)counter*1000.0 / float(total_timeout); +} + + +/* + * Class constructor + * + */ +leafWetnessClass::leafWetnessClass() +{ +}; + +/* getLeafWetness: converts the value read at the analog to digital converter + * input corresponding to the leaf wetness sensor into a percentage + * Parameters: + * Return: float value : wetness measured by the sensor in %RH + * + */ +float leafWetnessClass::getLeafWetness() { + float aux = 0; + float value = 0; + analogReference(DEFAULT); + digitalWrite(ANA6,HIGH); + delay(100); + aux = analogRead(ANALOG3); + delay(100); + //Convert analog value to %RH + //This sensor has a range between 1-3.3 V + //So that the ADC reads values between 310-1023 + //The next formula can be extracted by linearizing with two points + // (x1 , y1) = (310, 100 %) + // (x2 , y2) = (1023, 0 %) + // (y-y1)/(y2-y1) = (x-x1)/(x2-x1) + #if DEBUG_AGR > 0 + PRINT_AGR(F("getLeafWetness value Analog Read:")); + USB.println(aux); + #endif + + if(aux > 310.0){ + value = (1023.0*100.0/713.0)-(100.0/713.0)*aux; + #if DEBUG_AGR==2 + PRINT_AGR(F("getLeafWetness value aux>310:")); + USB.println(value); + #endif + } + else{ + value=100.0; + #if DEBUG_AGR==2 + PRINT_AGR(F("getLeafWetness value < 310:")); + USB.println(value); + #endif + } + digitalWrite(ANA6,LOW); + return value; +} + + +/* + * Class constructor + * + */ +ds18b20Class::ds18b20Class() +{ +} + +/* readDS18b20: reads the analog to digital converter input to which is connected + * the PT1000 sensor through the I2C and converts its value into + * temperature (ºC) + * Parameters: void + * Return: float value : temperature in Celsius (ºC) + * + */ +float ds18b20Class::readDS18b20(void) +{ + float value_ds18b20 = 0; + digitalWrite(DEN_PT1000_ON,HIGH); + delay(100); + value_ds18b20 = Utils.readTempDS1820(15,true); + delay(100); + digitalWrite(DEN_PT1000_ON,LOW); + #if DEBUG_AGR > 0 + PRINT_AGR(F("readDS18b20:")); + USB.println(value_ds18b20); + #endif + return value_ds18b20; +} + + +/* + * Class constructor + * + */ +pt1000Class::pt1000Class() +{ +} + + +/* readPT1000: reads the analog to digital converter input to which is connected + * the PT1000 sensor through the I2C and converts its value into + * temperature (ºC) + * Parameters: void + * Return: float value : temperature in Celsius (ºC) + * + */ +float pt1000Class::readPT1000(void) +{ + const byte pt1000_channel = B10100000; + byte data_pt1000[3] = {0,0,0}; + float value_pt1000 = 0; + digitalWrite(DEN_PT1000_ON,HIGH); + delay(100); + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + + Wire.beginTransmission(I2C_ADDRESS_AGR_PT1000); + Wire.send(pt1000_channel); + Wire.send(B01010101); + Wire.endTransmission(); + + delay(300); + + Wire.requestFrom(I2C_ADDRESS_AGR_PT1000, 3); + + int k=0; + while (Wire.available()) + { + data_pt1000[k]=Wire.receive(); + k++; + } + value_pt1000 = conversion(data_pt1000,1); + delay(1000); + #if DEBUG_AGR > 0 + PRINT_AGR(F("readPT1000 value conversion:")); + USB.println(value_pt1000); + #endif + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + digitalWrite(DEN_PT1000_ON,LOW); + return value_pt1000; +} + +/* + * Class constructor + * + */ +dendrometerClass::dendrometerClass() +{ +} + +/* readDendrometer: reads the analog to digital converter input to which is + * connected the dendrometer through the I2C and converts its + * value into mm + * Parameters: void + * Return: float value : trunk diameter read by the dendrometer in mm + * + */ +float dendrometerClass::readDendrometer(void) +{ + const byte dendro_channel = B10100001; + byte data_dendro[3] = {0,0,0}; + float value_dendro = 0; + digitalWrite(DEN_PT1000_ON,HIGH); + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + + delay(300); + + Wire.beginTransmission(I2C_ADDRESS_AGR_DENDROMETER); + Wire.send(dendro_channel); + Wire.send(B01010101); + Wire.endTransmission(); + + delay(300); + + Wire.requestFrom(I2C_ADDRESS_AGR_DENDROMETER, 3); + + int i=0; + while (Wire.available()) + { + data_dendro[i]=Wire.receive(); + i++; + } + /* + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { + PWR.closeI2C(); + RTC.setMode(RTC_OFF, RTC_I2C_MODE); + } + */ + digitalWrite(DEN_PT1000_ON,LOW); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + #if DEBUG_AGR==1 + PRINT_AGR(F("readDendrometer value without conversion:")); + USB.println(value_dendro); + #endif + #if DEBUG_AGR==2 + PRINT_AGR(F("readDendrometer value without conversion:")); + USB.println(value_dendro); + PRINT_AGR(F("readDendrometer value conversion:")); + USB.println(value_dendro = conversion(data_dendro,0)); + #endif + return value_dendro = conversion(data_dendro,0); +} + + +/* + * Class constructor + * + */ +radiationClass::radiationClass() +{ +} + +/* readRadiation: reads the analog to digital converter to which is connected the + * solar radiation sensor through the I2C and converts its value + * into voltage + * Parameters: void + * Return: float value : solar radiation in volts + * + */ +float radiationClass::readRadiation(void) +{ + byte data_apogee[2] = {0,0}; + long val = 0; + float val_def = 0; + digitalWrite(RADIATION_ON,HIGH); + delay(100); + //Switch ON I2C + pinMode(I2C_PIN_OE, OUTPUT); + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + + // Init I2C bus + if( !Wire.isON ) Wire.begin(); + Wire.requestFrom(I2C_ADDRESS_AGR_RADIATION, 2); + while (Wire.available()) + { + Wire.receive(); + } + delay(50); + Wire.requestFrom(I2C_ADDRESS_AGR_RADIATION, 2); + int i = 0; + while (Wire.available()) + { + data_apogee[i] = Wire.receive(); + i++; + } + val = long(data_apogee[1]) + long(data_apogee[0])*256; + val_def = (val - 32769)*9; + digitalWrite(RADIATION_ON,LOW); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + #if DEBUG_AGR==1 + PRINT_AGR(F("readRadiation without conversion:")); + USB.println(val_def); + #endif + #if DEBUG_AGR==2 + PRINT_AGR(F("readRadiation without conversion:")); + USB.println(val_def); + PRINT_AGR(F("readRadiation with conversion:")); + USB.println(val_def/65535); + #endif + return val_def = val_def/65535; +} + + +/* + * Class constructor + * + */ +weatherStationClass::weatherStationClass() +{ +} + +/* readAnemometer: reads the number of anemometer pulses during three seconds + * and turns the value into speed (km/h) + * Parameters: void + * Return: float value : wind speed (km/h) + * + */ +float weatherStationClass::readAnemometer(void) +{ + int reading_anemometer = 0; + int previous_reading_anemometer = 0; + int value_anemometer = 0; + float wind_speed = 0; + unsigned long start_anemometer=0; + unsigned long previous_pulse=0; + unsigned long pulse_duration=1000000; // set to large value + unsigned long new_pulse_duration=0; + const unsigned long MEAS_TIME = 3000; // ms + + value_anemometer = 0; + start_anemometer = millis(); + previous_pulse = millis(); + digitalWrite(WEATHER_STATION_ON,HIGH); + while( (millis()-start_anemometer) <= MEAS_TIME ) + { + previous_reading_anemometer = reading_anemometer; + reading_anemometer = digitalRead(ANEMOMETER_DATA); + // check falling edge + if((previous_reading_anemometer == 1)&&(reading_anemometer == 0)) + { + // increment pulse counter + value_anemometer++; + // get new pulse elapsed time + new_pulse_duration = millis()-previous_pulse; + // update pulse instant time + previous_pulse = millis(); + // update pulse duration in the case is the lowest + if( new_pulse_duration < pulse_duration ) + { + pulse_duration = new_pulse_duration; + } + } + //avoid millis overflow problem + if( millis() < start_anemometer ) start_anemometer=millis(); + } + delay(100); + // calculate average wind speed + wind_speed = value_anemometer * 2.4 / (MEAS_TIME/1000); + #if DEBUG_AGR > 0 + PRINT_AGR(F("readAnemometer windSpeed:")); + USB.println(wind_speed); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("readAnemometer windSpeed:")); + USB.println(wind_speed); + #endif + // calculate gust of wind 2.4Km/h per second + gustWind = 2.4 / ((float)pulse_duration/1000); + #if DEBUG_AGR > 0 + PRINT_AGR(F("readAnemometer windSpeed:")); + USB.println(gustWind); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("readAnemometer windSpeed:")); + USB.println(gustWind); + #endif + digitalWrite(WEATHER_STATION_ON,LOW); + return wind_speed; +} + + +/* + * readVaneDirection + * + */ +uint8_t weatherStationClass::readVaneDirection() +{ + float aux2=0; + float aux=0; + uint8_t aux3; + digitalWrite(WEATHER_STATION_ON,HIGH); + delay(100); + aux=analogRead(ANALOG5); + aux2 = (aux*3.3)/1023; // Volts, k + if( aux2<0.25 ) aux3=SENS_AGR_VANE_ESE; + else if( aux2>=0.25 && aux2<0.28 ) aux3=SENS_AGR_VANE_ENE; + else if( aux2>=0.28 && aux2<0.35 ) aux3=SENS_AGR_VANE_E; + else if( aux2>=0.35 && aux2<0.5 ) aux3=SENS_AGR_VANE_SSE; + else if( aux2>=0.5 && aux2<0.65 ) aux3=SENS_AGR_VANE_SE; + else if( aux2>=0.65 && aux2<0.85 ) aux3=SENS_AGR_VANE_SSW; + else if( aux2>=0.85 && aux2<1.1 ) aux3=SENS_AGR_VANE_S; + else if( aux2>=1.1 && aux2<1.38 ) aux3=SENS_AGR_VANE_NNE; + else if( aux2>=1.38 && aux2<1.6 ) aux3=SENS_AGR_VANE_NE; + else if( aux2>=1.6 && aux2<1.96 ) aux3=SENS_AGR_VANE_WSW; + else if( aux2>=1.96 && aux2<2.15 ) aux3=SENS_AGR_VANE_SW; + else if( aux2>=2.15 && aux2<2.35 ) aux3=SENS_AGR_VANE_NNW; + else if( aux2>=2.35 && aux2<2.6 ) aux3=SENS_AGR_VANE_N; + else if( aux2>=2.6 && aux2<2.75 ) aux3=SENS_AGR_VANE_WNW; + else if( aux2>=2.75 && aux2<2.95 ) aux3=SENS_AGR_VANE_NW; + else if( aux2>=2.95 ) aux3=SENS_AGR_VANE_W; + digitalWrite(WEATHER_STATION_ON,LOW); + #if DEBUG_AGR > 0 + PRINT_AGR(F("readVaneDirection:")); + USB.println(aux3); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("readVaneDirection:")); + USB.println(aux3); + #endif + return aux3; +} + +/* getVaneDirection: stores in the vaneDirection variable the orientation of the + * vane calculated from the voltage read at its output + * Parameters: + * Return: uint8_t value: Returns Direction + * + */ +void weatherStationClass::getVaneDirection(float vane) +{ + if( vane<0.25 ) vaneDirection=SENS_AGR_VANE_ESE; + else if( vane>=0.25 && vane<0.28 ) vaneDirection=SENS_AGR_VANE_ENE; + else if( vane>=0.28 && vane<0.35 ) vaneDirection=SENS_AGR_VANE_E; + else if( vane>=0.35 && vane<0.5 ) vaneDirection=SENS_AGR_VANE_SSE; + else if( vane>=0.5 && vane<0.65 ) vaneDirection=SENS_AGR_VANE_SE; + else if( vane>=0.65 && vane<0.85 ) vaneDirection=SENS_AGR_VANE_SSW; + else if( vane>=0.85 && vane<1.1 ) vaneDirection=SENS_AGR_VANE_S; + else if( vane>=1.1 && vane<1.38 ) vaneDirection=SENS_AGR_VANE_NNE; + else if( vane>=1.38 && vane<1.6 ) vaneDirection=SENS_AGR_VANE_NE; + else if( vane>=1.6 && vane<1.96 ) vaneDirection=SENS_AGR_VANE_WSW; + else if( vane>=1.96 && vane<2.15 ) vaneDirection=SENS_AGR_VANE_SW; + else if( vane>=2.15 && vane<2.35 ) vaneDirection=SENS_AGR_VANE_NNW; + else if( vane>=2.35 && vane<2.6 ) vaneDirection=SENS_AGR_VANE_N; + else if( vane>=2.6 && vane<2.75 ) vaneDirection=SENS_AGR_VANE_WNW; + else if( vane>=2.75 && vane<2.95 ) vaneDirection=SENS_AGR_VANE_NW; + else if( vane>=2.95 ) vaneDirection=SENS_AGR_VANE_W; + #if DEBUG_AGR > 0 + PRINT_AGR(F("getVaneDirection:")); + USB.println(vaneDirection); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("getVaneDirection:")); + USB.println(vaneDirection); + #endif +} + +/* getVaneFiltred: stores in the vaneDirection variable the orientation of the + * vane calculated from the voltage read at its output. The + * measurement is performed doing the mean of several values. + * + * Return: void + * Remarks: http://en.wikipedia.org/wiki/Mean_of_circular_quantities + * + */ +void weatherStationClass::getVaneFiltered() +{ + int NUM_SAMPLES=20; + int SAMPLING_TIME=100; // ms + int aux; + float sample[NUM_SAMPLES]; + float vanes[NUM_SAMPLES]; + digitalWrite(ANA0,HIGH); + for( int i=0 ; i 0 + PRINT_AGR(F("getVaneFiltered sample n:")); + USB.print(i); + USB.print(F(" ")); + USB.println(sample[i]); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("getVaneFiltered sample n:")); + USB.print(i); + USB.print(F(" ")); + USB.println(sample[i]); + #endif + } + // Mean filter + float mean=0; + int conversion=0; + float senos=0.0; + float cosenos=0.0; + + // translate to radians + for( int i=0 ; i 0 + PRINT_AGR(F("getVaneFiltered conversion:")); + USB.println(vaneDirection); + #endif + #if DEBUG_AGR > 1 + PRINT_AGR(F("getVaneFiltered conversion:")); + USB.println(vaneDirection); + #endif + digitalWrite(WEATHER_STATION_ON,LOW); +} + +/* attacPluvioInt: It attaches the pluviometer interruptions + * Parameters: void + * Return: void + * + */ +void weatherStationClass::attachPluvioInt(void) +{ + #if DEBUG_AGR > 1 + PRINT_AGR(F("attachPluvioInt function:\r\n")); + #endif + enableInterrupts(PLV_INT); +} + + +/* detachPluvioInt: It detaches the pluviometer interruptions + * Parameters: void + * Return: void + * + */ +void weatherStationClass::detachPluvioInt(void) +{ + #if DEBUG_AGR > 1 + PRINT_AGR(F("detachPluvioInt function:\r\n")); + #endif + disableInterrupts(PLV_INT); +} +/* readPluviometerHour + * + * It calculates the rain fall during the previous hour before actual slot. + * + * For example: It is 13.30 pm. Then this function calculates the rain fall for + * the whole previous slot. It is said to be the rainfall from 12pm to 13pm + * + */ +float weatherStationClass::readPluviometerHour() +{ + // Introduce one hour time as '1' hour and '1' hour-offset + return readPluviometer(1, 1); +} + + +/* readPluviometerCurrent + * + * It calculates the rain fall during the current hour slot. + * + * For example: It is 13.30 pm. Then this function calculates the rain fall for + * this hour slot. It is said to be the rainfall from 13pm to 13.30pm + * + */ +float weatherStationClass::readPluviometerCurrent() +{ + // Introduce one hour time as '1' hour and '0' hour-offset + return readPluviometer(1, 0); +} + +/* readPluviometerDay + * + * It calculates the rain fall during the last day + * + */ +float weatherStationClass::readPluviometerDay() +{ + // Introduce one day time as '24' hour + return readPluviometer(24, 1); +} + + +/* readPluviometer: reads the number of pluviometer pulses during the indicated + * time and turns the value into mm of rain per indicated time + * Parameters: 'time' indicates the amount of time (in seconds) to calculate + * the rain fall. For example, one hour would be 3600 seconds. + * Return: float value : precipitations (mm) + * + */ +float weatherStationClass::readPluviometer( uint8_t numHours, int offset) +{ + // Variable to store the precipitations value + float precipitations = 0.0; // mm + float pluviometerCounter = 0.0; // number of pulses + int counter = (int)numHours; + + // switch on RTC and get Date + RTC.ON(); + RTC.getTime(); + + // calculate rain fall: + + // firstly, from RTC.hour down to 24h + for(int i = (int)RTC.hour-offset; i>=0 ; i--) + { + // decrease counter variable + counter--; + + // check hours counter + if( counter < 0 ) break; + + // check correct Date + if( (plv_array[i].day == RTC.date) && + (plv_array[i].month == RTC.month) ) + { + // add number of pulses for each valid slot + pluviometerCounter += plv_array[i].pulses; + } + } + + // secondly, from 24h down to RTC.hour + for(int i = 23; i>=RTC.hour ; i--) + { + // decrease counter variable + counter--; + + // check hours counter + if( counter < 0 ) break; + + // get epoch reference to actual Date + unsigned long epoch = RTC.getEpochTime(RTC.year,RTC.month,RTC.date,0,0,0); + // substract one day + epoch -= SECS_PER_DAY; + timestamp_t tm; + RTC.breakTimeAbsolute( epoch, &tm); + + // check correct Date + if( (plv_array[i].day == tm.date) && + (plv_array[i].month == tm.month) ) + { + // add number of pulses for each valid slot + pluviometerCounter += plv_array[i].pulses; + } + + } + + // calculate precipitation (mm) for indicated time period + precipitations = pluviometerCounter * 0.2794; + #if DEBUG_AGR>1 + PRINT_AGR(F("readPluviometer (float):")); + USB.println(precipitations); + #endif + return precipitations; +} + + +/* readPluviometer: reads the number of anemometer pulses during three seconds + * and turns the value into mm of rain + * Parameters: void + * Return: float value : precipitations (mm) + * + */ +uint16_t weatherStationClass::readPluviometer() +{ + int reading_pluviometer = 0; + int previous_reading_pluviometer = 0; + int value_pluviometer = 0; + unsigned long start_pluviometer=0; + + value_pluviometer = 0; + start_pluviometer = millis(); + digitalWrite(WEATHER_STATION_ON,HIGH); + while((millis()-start_pluviometer)<=3000) + { + previous_reading_pluviometer = reading_pluviometer; + reading_pluviometer = digitalRead(PLUVIO_DATA); + + if((previous_reading_pluviometer == 1)&&(reading_pluviometer == 0)) + { + value_pluviometer++; + } + //avoid millis overflow problem + if( millis() < start_pluviometer) start_pluviometer=millis(); + } + delay(100); + #if DEBUG_AGR==1 + PRINT_AGR(F("readPluviometer (uint16_t):")); + USB.println(value_pluviometer); + #endif + #if DEBUG_AGR==2 + PRINT_AGR(F("readPluviometer (uint16_t):")); + USB.println(value_pluviometer); + #endif + digitalWrite(WEATHER_STATION_ON,LOW); + return value_pluviometer; +} + + +/* storePulse: + * + * This function increments the number of pulses inside the pluviometer array + * in the corresponding index of 'plv_array' + * + */ +void weatherStationClass::storePulse() +{ + // switch on RTC and get actual time + RTC.ON(); + RTC.getTime(); + uint16_t MAX_NUMBER_PULSES = 65535; + + // check if array slot must be initialized or not + if( (plv_array[RTC.hour].day == RTC.date) && + (plv_array[RTC.hour].month == RTC.month) ) + { + // increment number of pulses + if( plv_array[RTC.hour].pulses < MAX_NUMBER_PULSES ) + { + plv_array[RTC.hour].pulses++; + } + } + else + { + // store new date for this slot + plv_array[RTC.hour].day = RTC.date; + plv_array[RTC.hour].month = RTC.month; + plv_array[RTC.hour].pulses = 0; + // increment number of pulses + if( plv_array[RTC.hour].pulses < MAX_NUMBER_PULSES ) + { + plv_array[RTC.hour].pulses++; + } + } +} diff --git a/libraries/SensorAgr_v30/WaspSensorAgr_v30.h b/libraries/SensorAgr_v30/WaspSensorAgr_v30.h new file mode 100755 index 0000000..772f582 --- /dev/null +++ b/libraries/SensorAgr_v30/WaspSensorAgr_v30.h @@ -0,0 +1,325 @@ +/*! \file WaspSensorAgr_v30.h + \brief Library for managing the Agriculture Sensor Board v2.0 + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: Carlos Bello + + */ + + /*! \def WaspSensorAgr_v30_h + \brief The library flag + */ +#ifndef WaspSensorAgr_v30_h +#define WaspSensorAgr_v30_h +/****************************************************************************** + * Includes + ******************************************************************************/ +#include +#include +#include +#include "UltrasoundSensor.h" +#include "TSL2561.h" +//********************************************************************** +// DEBUG MODES +//********************************************************************** + +/*! Possible values: + * 0: No debug mode enabled + * 1: debug 1 + * 2: debug 2 + */ +#define DEBUG_AGR 0 + +// define print message +#define PRINT_AGR(str) USB.print(F("[AGR] ")); USB.print(str); + + +//********************************************************************** +// DEFINES INPUTS INPUTS +//********************************************************************** +#define WATERMARK_DIR_A DIGITAL8 +#define RADIATION_ON DIGITAL7 +#define WATERMARK_DIR_B DIGITAL6 +#define DEN_PT1000_ON DIGITAL5 +#define I2C_PIN_OE DIGITAL3 +#define ANEMOMETER_DATA DIGITAL2 +#define WATERMARK_ON DIGITAL1 +#define LEAF_WETNESS_ON ANA6 +#define WATERMARK_DATA ANA5 +#define WIND_VANE_DATA ANA4 +#define PLUVIO_DATA ANA3 +#define LEAF_WETNESS_DATA ANA2 +#define WEATHER_STATION_ON ANA0 +#define SENS_AGR_PLUVIOMETER 16 +/* +#define SENS_AGR_ANEMOMETER 1 +#define SENS_AGR_WATERMARK_1 2 +#define SENS_AGR_WATERMARK_2 4 +#define SENS_AGR_WATERMARK_3 8 +#define SENS_AGR_VANE 0 +#define SENS_AGR_DENDROMETER 32 +#define SENS_AGR_PT1000 64 +#define SENS_AGR_LEAF_WETNESS 128 +#define SENS_AGR_TEMPERATURE 256 +#define SENS_AGR_HUMIDITY 512 +#define SENS_AGR_RADIATION 1024 +#define SENS_AGR_SENSIRION 2048 +#define SENS_AGR_PRESSURE 4096 +#define SENS_AGR_LDR 8192 +#define SENS_AGR_TEMP_DS18B20 16384 +* / + +//********************************************************************** +// DEFINES WIND VANE DIRECTIONS +//********************************************************************** +/*! \def SENS_AGR_VANE_N + \brief Vane : North Direction + */ +/*! \def SENS_AGR_VANE_NNE + \brief Vane : North-NorthEast Direction + */ +/*! \def SENS_AGR_VANE_NE + \brief Vane : NorthEast Direction + */ +/*! \def SENS_AGR_VANE_ENE + \brief Vane : East-NorthEast Direction + */ +/*! \def SENS_AGR_VANE_E + \brief Vane : East Direction + */ +/*! \def SENS_AGR_VANE_ESE + \brief Vane : East-SouthEast Direction + */ +/*! \def SENS_AGR_VANE_SE + \brief Vane : SouthEast Direction + */ +/*! \def SENS_AGR_VANE_SSE + \brief Vane : South-SouthEast Direction + */ +/*! \def SENS_AGR_VANE_S + \brief Vane : South Direction + */ +/*! \def SENS_AGR_VANE_SSW + \brief Vane : South-SouthWest Direction + */ +/*! \def SENS_AGR_VANE_SW + \brief Vane : SouthWest Direction + */ +/*! \def SENS_AGR_VANE_WSW + \brief Vane : West-SouthWest Direction + */ +/*! \def SENS_AGR_VANE_W + \brief Vane : West Direction + */ +/*! \def SENS_AGR_VANE_WNW + \brief Vane : West-Northwest Direction + */ +/*! \def SENS_AGR_VANE_NW + \brief Vane : NorthWest Direction + */ +/*! \def SENS_AGR_VANE_NNW + \brief Vane : North-NorthWest Direction + */ +#define SENS_AGR_VANE_E 0 +#define SENS_AGR_VANE_ENE 1 +#define SENS_AGR_VANE_NE 2 +#define SENS_AGR_VANE_NNE 3 +#define SENS_AGR_VANE_N 4 +#define SENS_AGR_VANE_NNW 5 +#define SENS_AGR_VANE_NW 6 +#define SENS_AGR_VANE_WNW 7 +#define SENS_AGR_VANE_W 8 +#define SENS_AGR_VANE_WSW 9 +#define SENS_AGR_VANE_SW 10 +#define SENS_AGR_VANE_SSW 11 +#define SENS_AGR_VANE_S 12 +#define SENS_AGR_VANE_SSE 13 +#define SENS_AGR_VANE_SE 14 +#define SENS_AGR_VANE_ESE 15 + +//********************************************************************** +// DEFINES INPUTS INPUTS +//********************************************************************** +#define SENS_SA_WATERMARK 17 +#define SENS_SA_PT1000 18 +#define SENS_SA_DENDROMETER 19 +#define SENS_SA_LW 20 +#define SENS_SA_APG 21 +#define SENS_SA_DENDROMETER 22 +#define SENS_SA_LW 23 +#define SENS_SA_APG 24 +#define SENS_SA_WDV 25 +#define SENS_SA_ANE 26 +#define SENS_SA_PLV 27 +//********************************************************************** +//DECLARE VARS +//********************************************************************** + struct pluviometer_st + { + uint8_t month; + uint8_t day; + uint16_t pulses; + }; +//************************************************************************************************** +// Smart Agriculture Board Class +//************************************************************************************************** +class WaspSensorAgr_v30 +{ + public: + //! Class constructor + WaspSensorAgr_v30(); + //! Turns ON the board + void ON(void); + //! Turns OFF the board + void OFF(void); + float getTemperature(); + float getHumidity(); + float getPressure(); + uint16_t getDistance(); + uint32_t getLuxes(uint8_t); + uint16_t readUltrasoundSensor(); + void sleepAgr(const char*, uint8_t, uint8_t, uint8_t); + void sleepAgr(const char*, uint8_t, uint8_t, uint8_t, uint8_t); + friend class watermarkClass; + friend class leafWetnessClass; + friend class ds18b20Class; + friend class pt1000Class; + friend class dendrometerClass; + friend class radiationClass; + friend class weatherStationClass; + private: + + protected: + float conversion(byte[], uint8_t); +}; +extern WaspSensorAgr_v30 Agriculture; +#endif + +//************************************************************************************************** +// watermark class +//************************************************************************************************** +#ifndef watermarkClass_h +#define watermarkClass_h + +class watermarkClass +{ + public: + watermarkClass(uint8_t); + float readWatermark(); + private: + uint8_t _watermarkSocket; +}; +#endif + +//************************************************************************************************** +// Leaf Wetness class +//************************************************************************************************** +#ifndef leafWetnessClass_h +#define leafWetnessClass_h + +class leafWetnessClass +{ + public: + leafWetnessClass(); + float getLeafWetness(); +}; + +#endif + +//************************************************************************************************** +// DS18B20 class +//************************************************************************************************** +#ifndef ds18b20Class_h +#define ds18b20Class_h + +class ds18b20Class +{ + public: + ds18b20Class(); + float readDS18b20(); +}; +#endif + +//************************************************************************************************** +// PT1000 class +//************************************************************************************************** +#ifndef pt1000Class_h +#define pt1000Class_h + +class pt1000Class : public WaspSensorAgr_v30 +{ + public: + pt1000Class(); + float readPT1000(); +}; +#endif +//************************************************************************************************** +// Dendrometer sensor class +//************************************************************************************************** +#ifndef dendrometerClass_h +#define dendrometerClass_h + +class dendrometerClass : public WaspSensorAgr_v30 +{ + public: + dendrometerClass(); + float readDendrometer(); +}; +#endif +//************************************************************************************************** +// Radiation class +//************************************************************************************************** +#ifndef radiationClass_h +#define radiationClass_h + +class radiationClass +{ + public: + radiationClass(); + float readRadiation(); +}; +#endif +//************************************************************************************************** +// Weather Station class +//************************************************************************************************** +#ifndef weatherStationClass_h +#define weatherStationClass_h + +class weatherStationClass : public WaspSensorAgr_v30 +{ + public: + weatherStationClass(); + float readAnemometer(); + void getVaneFiltered(void); + uint8_t readVaneDirection(); + float readPluviometerHour(); + float readPluviometerCurrent(); + float readPluviometerDay(); + uint16_t readPluviometer(void); + float readPluviometer(uint8_t, int); + uint8_t vaneDirection; + void attachPluvioInt(void); + void detachPluvioInt(void); + void storePulse(); + float gustWind; + pluviometer_st plv_array[24]; + void getVaneDirection(float); +}; +#endif diff --git a/libraries/SensorAgr_v30/keywords.txt b/libraries/SensorAgr_v30/keywords.txt new file mode 100644 index 0000000..c6afa6b --- /dev/null +++ b/libraries/SensorAgr_v30/keywords.txt @@ -0,0 +1,59 @@ +# Agr_v30 Keywords # + +ON KEYWORD2 +OFF KEYWORD2 +getDistance KEYWORD2 +getLuxes KEYWORD2 +getPressure KEYWORD2 +getTemperature KEYWORD2 +getHumidity KEYWORD2 +sleepAgr KEYWORD2 + +readDendrometer KEYWORD2 +readDS18b20 KEYWORD2 +getLeafWetness KEYWORD2 +readPT1000 KEYWORD2 +readRadiation KEYWORD2 +readWatermark KEYWORK2 + +attachPluvioInt KEYWORD2 +detachPluvioInt KEYWORD2 +getVaneDirection KEYWORD2 +getVaneFiltered KEYWORD2 +readAnemometer KEYWORD2 +readPluviometer KEYWORD2 +readPluviometerCurrent KEYWORD2 +readPluviometerDay KEYWORD2 +readPluviometerHour KEYWORD2 +gustWind KEYWORD2 +WaspSensorAgr_v30 KEYWORD2 +storePulse KEYWORD2 +readVaneDirection KEYWORD2 + +SENS_AGR_VANE_ENE LITERAL1 +SENS_AGR_VANE_NE LITERAL1 +SENS_AGR_VANE_NNE LITERAL1 +SENS_AGR_VANE_N LITERAL1 +SENS_AGR_VANE_NNW LITERAL1 +SENS_AGR_VANE_NW LITERAL1 +SENS_AGR_VANE_WNW LITERAL1 +SENS_AGR_VANE_W LITERAL1 +SENS_AGR_VANE_WSW LITERAL1 +SENS_AGR_VANE_SW LITERAL1 +SENS_AGR_VANE_SSW LITERAL1 +SENS_AGR_VANE_S LITERAL1 +SENS_AGR_VANE_SSE LITERAL1 +SENS_AGR_VANE_SE LITERAL1 +SENS_AGR_VANE_ESE LITERAL1 +OUTDOOR LITERAL1 +INDOOR LITERAL1 + +WaspSensorAgr_v30 KEYWORD2 +Agriculture KEYWORD1 +dendrometerClass KEYWORD2 +ds18b20Class KEYWORD2 +leafWetnessClass KEYWORD2 +pt1000Class KEYWORD2 +radiationClass KEYWORD2 +watermarkClass KEYWORD2 +weatherStationClass KEYWORD2 diff --git a/libraries/SensorAmbient/WaspSensorAmbient.cpp b/libraries/SensorAmbient/WaspSensorAmbient.cpp index 48c46e3..896b067 100755 --- a/libraries/SensorAmbient/WaspSensorAmbient.cpp +++ b/libraries/SensorAmbient/WaspSensorAmbient.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.1 * Design: David Gascón * Implementation: Alberto Bielsa, Manuel Calahorra, Yuri Carmona, Jorge Casanova, Javier Siscart * @@ -50,128 +50,11 @@ WaspSensorAmbient::WaspSensorAmbient() digitalWrite(SENS_AMBIENT_SENSIRION_DATA,LOW); digitalWrite(SENS_AMBIENT_LDR_GND,LOW); - TSL2561(TSL2561_ADDR_FLOAT); } // Private Methods ////////////////////////////////////////////////////////////// -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::TSL2561(uint8_t addr) -{ - _addr = addr; - _initialized = false; - _integration = TSL2561_INTEGRATIONTIME_13MS; - _gain = TSL2561_GAIN_16X; - - // we cant do wire initialization till later, because we havent loaded Wire yet -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -boolean WaspSensorAmbient::begin(void) -{ - if( !Wire.I2C_ON ) Wire.begin(); - delay(100); - - // Initialise I2C - Wire.beginTransmission(_addr); - - Wire.send(TSL2561_REGISTER_ID); - - Wire.endTransmission(); - Wire.requestFrom(_addr, 1); - - int x = Wire.receive(); - - if (x & 0x0A ) - {} - else - { - return false; - } - _initialized = true; - - // Set default integration time and gain - setTiming(_integration); - setGain(_gain); - - // Note: by default, the device is in power down mode on bootup - disable(); - - return true; -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::enable(void) -{ - if (!_initialized) begin(); - - // Enable the device by setting the control bit to 0x03 - write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); - delay(100); -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::disable(void) -{ - if (!_initialized) begin(); - - // Disable the device by setting the control bit to 0x03 - write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::setGain(tsl2561Gain_t gain) -{ - if (!_initialized) begin(); - - enable(); - _gain = gain; - write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); - disable(); -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::setTiming(tsl2561IntegrationTime_t integration) -{ - if (!_initialized) begin(); - - enable(); - _integration = integration; - write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); - disable(); -} - /* Function: Read the sensirion temperature @@ -434,216 +317,6 @@ float WaspSensorAmbient::humidityConversion(int readValue, int precision) } -/* - Function: - Returns: - Parameters: - Values: -*/ -uint32_t WaspSensorAmbient::calculateLux(uint16_t ch0, uint16_t ch1) -{ - unsigned long chScale; - unsigned long channel1; - unsigned long channel0; - - switch (_integration) - { - case TSL2561_INTEGRATIONTIME_13MS: - chScale = TSL2561_LUX_CHSCALE_TINT0; - break; - case TSL2561_INTEGRATIONTIME_101MS: - chScale = TSL2561_LUX_CHSCALE_TINT1; - break; - default: // No scaling ... integration time = 402ms - chScale = (1 << TSL2561_LUX_CHSCALE); - break; - } - - // Scale for gain (1x or 16x) - if (!_gain) chScale = chScale << 4; - - // scale the channel values - channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE; - channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE; - - // find the ratio of the channel values (Channel1/Channel0) - unsigned long ratio1 = 0; - if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; - - // round the ratio value - unsigned long ratio = (ratio1 + 1) >> 1; - - unsigned int b, m; - -#ifdef TSL2561_PACKAGE_CS - if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) - {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;} - else if (ratio <= TSL2561_LUX_K2C) - {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;} - else if (ratio <= TSL2561_LUX_K3C) - {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;} - else if (ratio <= TSL2561_LUX_K4C) - {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;} - else if (ratio <= TSL2561_LUX_K5C) - {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;} - else if (ratio <= TSL2561_LUX_K6C) - {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;} - else if (ratio <= TSL2561_LUX_K7C) - {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;} - else if (ratio > TSL2561_LUX_K8C) - {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;} -#else - if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) - {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} - else if (ratio <= TSL2561_LUX_K2T) - {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} - else if (ratio <= TSL2561_LUX_K3T) - {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} - else if (ratio <= TSL2561_LUX_K4T) - {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} - else if (ratio <= TSL2561_LUX_K5T) - {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} - else if (ratio <= TSL2561_LUX_K6T) - {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} - else if (ratio <= TSL2561_LUX_K7T) - {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} - else if (ratio > TSL2561_LUX_K8T) - {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} -#endif - - unsigned long temp; - temp = ((channel0 * b) - (channel1 * m)); - - // do not allow negative lux value - if (temp < 0) temp = 0; - - // round lsb (2^(LUX_SCALE-1)) - temp += (1 << (TSL2561_LUX_LUXSCALE-1)); - - // strip off fractional portion - uint32_t lux = temp >> TSL2561_LUX_LUXSCALE; - - // Signal I2C had no errors - return (float)lux; -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -uint32_t WaspSensorAmbient::getFullLuminosity (void) -{ - if (!_initialized) begin(); - - // Enable the device by setting the control bit to 0x03 - enable(); - - // Wait x ms for ADC to complete - switch (_integration) - { - case TSL2561_INTEGRATIONTIME_13MS: - delay(14); - break; - case TSL2561_INTEGRATIONTIME_101MS: - delay(102); - break; - default: - delay(400); - break; - } - - uint32_t x; - x = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); - x <<= 16; - x |= read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); - - disable(); - - return x; -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -uint16_t WaspSensorAmbient::getLuminosity (uint8_t channel) -{ - - uint32_t x = getFullLuminosity(); - - if (channel == 0) - { - // Reads two byte value from channel 0 (visible + infrared) - return (x & 0xFFFF); - } else if (channel == 1) - { - // Reads two byte value from channel 1 (infrared) - return (x >> 16); - } else if (channel == 2) - { - // Reads all and subtracts out just the visible! - return ( (x & 0xFFFF) - (x >> 16)); - } - - // unknown channel! - return 0; -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -uint16_t WaspSensorAmbient::read16(uint8_t reg) -{ - uint16_t x; uint16_t t; - - Wire.beginTransmission(_addr); -#if ARDUINO >= 100 - Wire.write(reg); -#else - Wire.send(reg); -#endif - Wire.endTransmission(); - - Wire.requestFrom(_addr, 2); -#if ARDUINO >= 100 - t = Wire.read(); - x = Wire.read(); -#else - t = Wire.receive(); - x = Wire.receive(); -#endif - x <<= 8; - x |= t; - return x; -} - -/* - Function: - Returns: - Parameters: - Values: -*/ -void WaspSensorAmbient::write8 (uint8_t reg, uint8_t value) -{ - Wire.beginTransmission(_addr); -#if ARDUINO >= 100 - Wire.write(reg); - Wire.write(value); -#else - Wire.send(reg); - Wire.send(value); -#endif - Wire.endTransmission(); -} - - // Public Methods ////////////////////////////////////////////////////////////// @@ -727,7 +400,7 @@ float WaspSensorAmbient::readValue(uint8_t sensor) case SENS_AMBIENT_LDR : aux = readLDR(); break; - case SENS_AMBIENT_LUX : aux = readLUXbright(); // bright environments by default + case SENS_AMBIENT_LUX : aux = TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_1); break; default : return -1.0; @@ -736,164 +409,182 @@ float WaspSensorAmbient::readValue(uint8_t sensor) return aux; } -/* - Function: - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUXbright() + + + + +/* getTemperature: + * + */ +float WaspSensorAmbient::getTemperature() { - // set no gain (for bright situations) - setGain(TSL2561_GAIN_0X); + float value = 0; - // shortest integration time (bright light) - setTiming(TSL2561_INTEGRATIONTIME_13MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; + setSensorMode(SENS_ON, SENS_AMBIENT_TEMPERATURE); + delay(100); + value = readValue(SENS_AMBIENT_TEMPERATURE); + setSensorMode(SENS_OFF, SENS_AMBIENT_TEMPERATURE); - return calculateLux(full, ir); + return value; } -/* - Function: - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUXmedium() -{ - // set gain to medium light situations - setGain(TSL2561_GAIN_16X); - - // Set integration time - setTiming(TSL2561_INTEGRATIONTIME_101MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; - - return calculateLux(full, ir); + + +/* getHumidity: + * + */ +float WaspSensorAmbient::getHumidity() +{ + float value = 0; + + setSensorMode(SENS_ON, SENS_AMBIENT_HUMIDITY); + delay(100); + value = readValue(SENS_AMBIENT_HUMIDITY); + setSensorMode(SENS_OFF, SENS_AMBIENT_HUMIDITY); + + return value; } -/* - Function: - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUXdim() + +/* getLuminosity: + * + */ +float WaspSensorAmbient::getLuminosity() { - // set gain to medium light situations - setGain(TSL2561_GAIN_16X); + float value = 0; - // longest integration time - setTiming(TSL2561_INTEGRATIONTIME_402MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; + setSensorMode(SENS_ON, SENS_AMBIENT_LDR); + // dummy reading + readValue(SENS_AMBIENT_LDR); + value = readValue(SENS_AMBIENT_LDR); + setSensorMode(SENS_OFF, SENS_AMBIENT_LDR); - return calculateLux(full, ir); + return value; } -/* - Function: More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum - That way you can do whatever math and comparions you want! - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUMINOSITYbright() + +/* getLuxes: + * + */ +float WaspSensorAmbient::getLuxes(uint8_t gain) +{ + // update I2C flag + Wire.isBoard = true; + // switch on the power supplies + PWR.setSensorPower(SENS_3V3, SENS_ON); + TSL.ON(); + + switch (gain) + { + case INDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_16); + break; + + case OUTDOOR: + default: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_1); + break; + } + + // update I2C flag + Wire.isBoard = false; + // switch off the power supplies + PWR.setSensorPower(SENS_3V3, SENS_OFF); + return TSL.lux; +} + + + +/* getTemperatureBME: get temperature from BME280 sensor + * + */ +float WaspSensorAmbient::getTemperatureBME() { - float value; - - // set no gain (for bright situtations) - setGain(TSL2561_GAIN_0X); - - // shortest integration time (bright light) - setTiming(TSL2561_INTEGRATIONTIME_13MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; - value = calculateLux(full, ir); - - // Print calculated values - #ifdef SENS_AMBIENT_DEBUG - USB.print(F("IR: ")); USB.print(ir); USB.print(F("\t")); - USB.print(F("Full: ")); USB.print(full); USB.print(F("\t")); - USB.print(F("Visible: ")); USB.print(full - ir); USB.print(F("\t")); - USB.print(F("Lux: ")); USB.println(value); - #endif - - return value; + float value = 0; + + // update I2C flag + Wire.isBoard = true; + // switch on the power supplies + PWR.setSensorPower(SENS_3V3, SENS_ON); + + // Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + + value = BME.getTemperature(BME280_OVERSAMP_1X, 0); + delay(100); + + // update I2C flag + Wire.isBoard = false; + // switch off the power supplies + PWR.setSensorPower(SENS_3V3, SENS_OFF); + + // Read the temperature from the BME280 Sensor + return value; } -/* - Function: - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUMINOSITYmedium() + + +/* getPressureBME: get pressure from BME280 sensor + * + */ +float WaspSensorAmbient::getPressureBME() { - float value; - - // set gain to medium light situations - setGain(TSL2561_GAIN_16X); - - // set integration time - setTiming(TSL2561_INTEGRATIONTIME_101MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; - value = calculateLux(full, ir); - - // Print calculated values - #ifdef SENS_AMBIENT_DEBUG - USB.print(F("IR: ")); USB.print(ir); USB.print(F("\t")); - USB.print(F("Full: ")); USB.print(full); USB.print(F("\t")); - USB.print(F("Visible: ")); USB.print(full - ir); USB.print(F("\t")); - USB.print(F("Lux: ")); USB.println(value); - #endif + float value = 0; + + // update I2C flag + Wire.isBoard = true; + // switch on the power supplies + PWR.setSensorPower(SENS_3V3, SENS_ON); + + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + + // Read the pressure from the BME280 Sensor + value = BME.getPressure(BME280_OVERSAMP_1X, 0); + delay(100); + // update I2C flag + Wire.isBoard = false; + // switch off the power supplies + PWR.setSensorPower(SENS_3V3, SENS_OFF); + + // Read the temperature from the BME280 Sensor return value; } -/* - Function: - Returns: - Parameters: - Values: -*/ -float WaspSensorAmbient::readLUMINOSITYdim() + + +/* getHumidityBME: get humidity from BME280 sensor + * + */ +float WaspSensorAmbient::getHumidityBME() { - float value; - - // set gain to medium light situations - setGain(TSL2561_GAIN_16X); - - // longest integration time - setTiming(TSL2561_INTEGRATIONTIME_402MS); - uint32_t lum = getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; - value = calculateLux(full, ir); - - // Print calculated values - #ifdef SENS_AMBIENT_DEBUG - USB.print(F("IR: ")); USB.print(ir); USB.print(F("\t")); - USB.print(F("Full: ")); USB.print(full); USB.print(F("\t")); - USB.print(F("Visible: ")); USB.print(full - ir); USB.print(F("\t")); - USB.print(F("Lux: ")); USB.println(value); - #endif + float value = 0; + + // update I2C flag + Wire.isBoard = true; + // switch on the power supplies + PWR.setSensorPower(SENS_3V3, SENS_ON); + + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + + // Read the humidity from the BME280 Sensor + value = BME.getHumidity(BME280_OVERSAMP_1X); + delay(100); + + // update I2C flag + Wire.isBoard = false; + // switch off the power supplies + PWR.setSensorPower(SENS_3V3, SENS_OFF); + + // Read the temperature from the BME280 Sensor return value; } + WaspSensorAmbient SensorAmbient=WaspSensorAmbient(); diff --git a/libraries/SensorAmbient/WaspSensorAmbient.h b/libraries/SensorAmbient/WaspSensorAmbient.h index 94ce407..20bfaad 100755 --- a/libraries/SensorAmbient/WaspSensorAmbient.h +++ b/libraries/SensorAmbient/WaspSensorAmbient.h @@ -1,7 +1,7 @@ /*! \file WaspSensorAmbient.h \brief Library for environmental Sensors - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.3 + Version: 3.1 Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra, Yuri Carmona, Jorge Casanova, Javier Siscart @@ -38,6 +38,10 @@ #include #include +// TSL2561 Sensor for reading luxes value +#include "TSL2561.h" +#include "BME280.h" + /****************************************************************************** * Definitions & Declarations @@ -83,90 +87,6 @@ #define SENS_PREC_HIGH 1 #define SENS_PREC_LOW 0 -// LUX auxiliary definitions -#ifndef _TSL2561_H_ -#define _TSL2561_H_ -#define TSL2561_VISIBLE 2 // channel 0 - channel 1 -#define TSL2561_INFRARED 1 // channel 1 -#define TSL2561_FULLSPECTRUM 0 // channel 0 -//i2c address -#define TSL2561_ADDR_FLOAT 0x39 -// Lux calculations -#define TSL2561_PACKAGE_T_FN_CL -#define TSL2561_READBIT (0x01) -#define TSL2561_COMMAND_BIT (0x80) // Must be 1 -#define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) -#define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) -#define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write -#define TSL2561_CONTROL_POWERON (0x03) -#define TSL2561_CONTROL_POWEROFF (0x00) -#define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 -#define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 -#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 -#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE -#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE -//Values -#define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE -#define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE -#define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE -#define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE -#define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE -#define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE -#define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE -#define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE -#define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE -#define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE -#define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE -#define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE -#define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE -#define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE -#define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE -#define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE -#define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE -#define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE -#define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE -#define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE -#define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE -#define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE -#define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE -#define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE - -// Lux auxiliary data -enum -{ - TSL2561_REGISTER_CONTROL = 0x00, - TSL2561_REGISTER_TIMING = 0x01, - TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, - TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, - TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, - TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, - TSL2561_REGISTER_INTERRUPT = 0x06, - TSL2561_REGISTER_CRC = 0x08, - TSL2561_REGISTER_ID = 0x0A, - TSL2561_REGISTER_CHAN0_LOW = 0x0C, - TSL2561_REGISTER_CHAN0_HIGH = 0x0D, - TSL2561_REGISTER_CHAN1_LOW = 0x0E, - TSL2561_REGISTER_CHAN1_HIGH = 0x0F -}; - -// Lux auxiliary data -typedef enum -{ - TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms - TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms - TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms -} -tsl2561IntegrationTime_t; - -// Lux auxiliary data -typedef enum -{ - TSL2561_GAIN_0X = 0x00, // No gain - TSL2561_GAIN_16X = 0x10, // 16x gain -} -tsl2561Gain_t; - -#endif // end of lux definitions /****************************************************************************** * Class @@ -181,26 +101,6 @@ class WaspSensorAmbient { private: - //! Variable : Lux sensor address - /*! - */ - int8_t _addr; - - //! Variable : aux variable for Lux sensor - /*! - */ - tsl2561IntegrationTime_t _integration; - - //! Variable : Gain for the Lux sensor - /*! - */ - tsl2561Gain_t _gain; - - //! Variable : stores lux sensor state - /*! - */ - boolean _initialized; - //! It reads from the sensirion /*! \param uint8_t parameter : TEMPERATURE or HUMIDITY @@ -243,92 +143,7 @@ class WaspSensorAmbient */ float readLDR(void); - //! It reads the Lux Sensor - /*! - \return the value returned by the sensor - */ - boolean begin(void); - - //! Enables lux sensor - /*! - \param void - - \return void - */ - void enable(void); - - //! Disables lux sensor - /*! - \param void - - \return void - */ - void disable(void); - - //! Write a register of Lux sensor - /*! - \param r: register to write - \param v: value to write - - \return void - */ - void write8(uint8_t r, uint8_t v); - - //! REad a lux sensor reguster - /*! - \param reg: register to be read - - \return register value - */ - uint16_t read16(uint8_t reg); - - //! Calculate luxes measured by lux sensor - /*! - \param ch0: channel 0 - \param ch1: channel 1 - \return luxes - */ - uint32_t calculateLux(uint16_t ch0, uint16_t ch1); - - //! Configures luxes sensor - /*! - \param integration: - - \return void - */ - void setTiming(tsl2561IntegrationTime_t integration); - - //! Sets Lux sensor gain - /*! - \param gain: gain to be set - - \return - */ - void setGain(tsl2561Gain_t gain); - - //! Reads the lux sensor - /*! - \param channel: sellects lux ssensor channel - - \return lux - */ - uint16_t getLuminosity (uint8_t channel); - - //! Reads lux sensor - /*! - \param - \return lux - */ - uint32_t getFullLuminosity (); - - //! Initialize aux variables of Lux sensor - /*! - \param addr: lux sensor address - - \return void - */ - void TSL2561(uint8_t addr); public: @@ -356,54 +171,25 @@ class WaspSensorAmbient \return error */ float readValue(uint8_t sensor); - - //! Read Luxes in bright environments (outdoors) - /*! - \param void - - \return luxes - */ - float readLUXbright(void); - - //! Read Luxes in medium light environments - /*! - \param void - \return luxes - */ - float readLUXmedium(void); - - //! Read Luxes in low light environments - /*! - \param void - - \return luxes - */ - float readLUXdim(void); - - //! Read Luxes and calculate other parameters in bright environments - /*! - \param void - - \return lux - */ - float readLUMINOSITYbright(void); - - //! Read Luxes and calculate other parameters in medium light environments - /*! - \param void - - \return luxes - */ - float readLUMINOSITYmedium(void); - - //! Read Luxes and calculate other parameters in low light environments - /*! - \param void + //! Read temperature sensor + float getTemperature(); + + //! Read humidity sensor + float getHumidity(); + + //! Read LDR sensor (luminosity) + float getLuminosity(); + + //! Read Luxes sensor + float getLuxes(uint8_t gain); - \return luxes - */ - float readLUMINOSITYdim(void); + //! Read BME Temperature + float getTemperatureBME(); + //! Read BME Humidity + float getHumidityBME(); + //! Read BME Pressure + float getPressureBME(); }; diff --git a/libraries/SensorAmbient/keywords.txt b/libraries/SensorAmbient/keywords.txt index 991c973..87b2feb 100644 --- a/libraries/SensorAmbient/keywords.txt +++ b/libraries/SensorAmbient/keywords.txt @@ -74,6 +74,7 @@ TSL2561_INTEGRATIONTIME_101MS LITERAL1 TSL2561_INTEGRATIONTIME_402MS LITERAL1 TSL2561_GAIN_0X LITERAL1 TSL2561_GAIN_16X LITERAL1 +TSL2561_LUX_CHSCALE_TINT1 LITERAL1 WaspSensorAmbient KEYWORD2 setSensorMode KEYWORD2 @@ -84,5 +85,8 @@ readLUXdim KEYWORD2 readLUMINOSITYbright KEYWORD2 readLUMINOSITYmedium KEYWORD2 readLUMINOSITYdim KEYWORD2 +getTemperatureBME KEYWORD2 +getHumidityBME KEYWORD2 +getPressureBME KEYWORD2 -SensorAmbient KEYWORD3 +SensorAmbient KEYWORD1 diff --git a/libraries/SensorCities/WaspSensorCities.cpp b/libraries/SensorCities/WaspSensorCities.cpp index 0c16532..78b9c85 100755 --- a/libraries/SensorCities/WaspSensorCities.cpp +++ b/libraries/SensorCities/WaspSensorCities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.0 * Design: David Gascón * Implementation: Manuel Calahorra */ @@ -64,7 +64,7 @@ WaspSensorCities::WaspSensorCities() PWR.setSensorPower(SENS_5V, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_CITIES_V15; + WaspRegisterSensor |= REG_CITIES_V15; } // Public Methods ////////////////////////////////////////////////////////////// @@ -146,7 +146,10 @@ void WaspSensorCities::setAudioGain(uint8_t value1, float value2) value1--; ampli=(uint8_t) 128-(128/100)*value1; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(I2C_ADDRESS_CITIES_AUDIO_GAIN); Wire.send(B00000000); @@ -168,7 +171,8 @@ void WaspSensorCities::setAudioGain(uint8_t value1, float value2) Wire.send(ampli); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -371,7 +375,7 @@ float WaspSensorCities::readValue(uint16_t sensor, uint8_t type) delay(1); } value = value / 1000; - value = audioConversion(value); + //value = audioConversion(value); break; case SENS_CITIES_HUMIDITY : aux = analogRead(ANALOG3); value = humidityConversion(aux); @@ -536,13 +540,18 @@ void WaspSensorCities::setDigipot1(uint8_t address, float value) thres *=128; thres /=3.3; threshold = (uint8_t) thres; - if( !Wire.I2C_ON ) Wire.begin(); + + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00010000); Wire.send(threshold); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -564,13 +573,19 @@ void WaspSensorCities::setDigipot0(uint8_t address, float value) thres *=128; thres /=3.3; threshold = (uint8_t) thres; - if( !Wire.I2C_ON ) Wire.begin(); + + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00000000); Wire.send(threshold); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -669,11 +684,9 @@ float WaspSensorCities::ldrConversion(int readValue) */ float WaspSensorCities::temperatureConversion(int readValue) { - float temperature = 0; - + float temperature = 0.0; temperature = float(readValue) * 3300 / 1023; - - temperature = (temperature - 500) / 10; + temperature = (temperature - 500) / 10; return(temperature); } diff --git a/libraries/SensorCities/WaspSensorCities.h b/libraries/SensorCities/WaspSensorCities.h index 3091d5b..6468cdf 100755 --- a/libraries/SensorCities/WaspSensorCities.h +++ b/libraries/SensorCities/WaspSensorCities.h @@ -1,7 +1,7 @@ /*! \file WaspSensorCities.h \brief Library for managing the Smart Cities Sensor Board - Copyright (C) 2013 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 - Design: David Gascón + Version: 3.0 + Design: David Gascón Implementation: Manuel Calahorra */ diff --git a/libraries/SensorCities/keywords.txt b/libraries/SensorCities/keywords.txt index 9f8df33..1bdbe20 100644 --- a/libraries/SensorCities/keywords.txt +++ b/libraries/SensorCities/keywords.txt @@ -31,4 +31,4 @@ attachInt KEYWORD2 detachInt KEYWORD2 loadInt KEYWORD2 -SensorCities KEYWORD3 +SensorCities KEYWORD1 diff --git a/libraries/SensorCities_PRO/WaspSensorCities_PRO.cpp b/libraries/SensorCities_PRO/WaspSensorCities_PRO.cpp new file mode 100755 index 0000000..4bee703 --- /dev/null +++ b/libraries/SensorCities_PRO/WaspSensorCities_PRO.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.1 + * Design: David Gascón + * Implementation: Alejandro Gállego, Ahmad Saad + */ + + +#ifndef __WPROGRAM_H__ + #include +#endif + +#include "WaspSensorCities_PRO.h" + +// Constructors /////////////////////////////////////////////////////////// + +/* Constructor: Sets the mode of the digital pins and initializes them + * + */ +WaspSensorCitiesPRO::WaspSensorCitiesPRO() +{ + pinMode(SCP_I2C_MAIN_EN, OUTPUT); // I2C main pin + + pinMode(SCP_PWR_SOCKET_1, OUTPUT); // PWR pin socket 1 + pinMode(SCP_PWR_SOCKET_2, OUTPUT); // PWR pin socket 2 + pinMode(SCP_PWR_SOCKET_3, OUTPUT); // PWR pin socket 3 + pinMode(SCP_PWR_SOCKET_4, OUTPUT); // PWR pin socket 4 + pinMode(SCP_PWR_SOCKET_5, OUTPUT); // PWR pin socket 5 + + + digitalWrite(SCP_I2C_MAIN_EN, LOW); // I2C main pin + + digitalWrite(SCP_PWR_SOCKET_1, LOW); // PWR pin socket 1 + digitalWrite(SCP_PWR_SOCKET_2, LOW); // PWR pin socket 2 + digitalWrite(SCP_PWR_SOCKET_3, LOW); // PWR pin socket 3 + digitalWrite(SCP_PWR_SOCKET_4, LOW); // PWR pin socket 4 + digitalWrite(SCP_PWR_SOCKET_5, LOW); // PWR pin socket 5 + + // update Waspmote Control Register + WaspRegisterSensor |= REG_CITIES_PRO; + pwrCitiesPRORegister = 0; + pwrGasPRORegister = 0; +} + +// Private Methods //////////////////////////////////////////////////////// + + +// Public Methods ////////////////////////////////////////////////////////////// + +/* Turns ON the sensor/socket + * Parameters: socket_sensor: SOCKET_1 + * SOCKET_2 + * SOCKET_3 + * SOCKET_4 + * SOCKET_5 + * SOCKET_A + * SOCKET_B + * SOCKET_C + * SOCKET_E + * SOCKET_F + * Return: void + */ +void WaspSensorCitiesPRO::ON(uint8_t socket_sensor) +{ + + // Power on 3V3 and/or 5V if necessary + if ((WaspRegister & REG_3V3) == 0) + { + #if CITIES_PRO_DEBUG>0 + USB.println(F("SCP.3V3 to ON")); + #endif + PWR.setSensorPower(SENS_3V3, SENS_ON); + digitalWrite(SCP_I2C_MAIN_EN, HIGH); // I2C main pin + } + + switch(socket_sensor) + { + case SOCKET_1: + case SOCKET_C: + digitalWrite(SCP_PWR_SOCKET_1, HIGH); + + // Set the flags + pwrCitiesPRORegister |= 0x01; + break; + + case SOCKET_2: + case SOCKET_E: + digitalWrite(SCP_PWR_SOCKET_2, HIGH); + + // Set the flags + pwrCitiesPRORegister |= 0x02; + break; + + case SOCKET_3: + case SOCKET_F: + digitalWrite(SCP_PWR_SOCKET_3, HIGH); + + // Set the flags + pwrCitiesPRORegister |= 0x04; + break; + + case SOCKET_4: + case SOCKET_A: + digitalWrite(SCP_PWR_SOCKET_4, HIGH); + + // Set the flags + pwrCitiesPRORegister |= 0x08; + break; + + case SOCKET_5: + case SOCKET_B: + digitalWrite(SCP_PWR_SOCKET_5, HIGH); + + // Set the flags + pwrCitiesPRORegister |= 0x10; + break; + + } + + #if CITIES_PRO_DEBUG>1 + USB.print(F("SCP.pwrCitiesPRORegister=")); + USB.println(pwrCitiesPRORegister, BIN); + USB.print(F("SCP.pwrGasPRORegister=")); + USB.println(pwrGasPRORegister, BIN); + #endif + +} + +/* Turns OFF the sensor/socket + * Parameters: socket_sensor: SOCKET_1 + * SOCKET_2 + * SOCKET_3 + * SOCKET_4 + * SOCKET_5 + * SOCKET_A + * SOCKET_B + * SOCKET_C + * SOCKET_E + * SOCKET_F + * Return: void + */ +void WaspSensorCitiesPRO::OFF(uint8_t socket_sensor) +{ + uint8_t mask; + + switch(socket_sensor) + { + + case SOCKET_1: + case SOCKET_C: + digitalWrite(SCP_PWR_SOCKET_1, LOW); + + // Set the flags + pwrCitiesPRORegister &= 0xFE; + break; + + case SOCKET_2: + case SOCKET_E: + digitalWrite(SCP_PWR_SOCKET_2, LOW); + + // Set the flags + pwrCitiesPRORegister &= 0xFD; + break; + + case SOCKET_3: + case SOCKET_F: + digitalWrite(SCP_PWR_SOCKET_3, LOW); + + // Set the flags + pwrCitiesPRORegister &= 0xFB; + break; + + case SOCKET_4: + case SOCKET_A: + digitalWrite(SCP_PWR_SOCKET_4, LOW); + + // Set the flags + pwrCitiesPRORegister &= 0xF7; + break; + + case SOCKET_5: + case SOCKET_B: + digitalWrite(SCP_PWR_SOCKET_5, LOW); + + // Set the flags + pwrCitiesPRORegister &= 0xEF; + break; + + } + #if CITIES_PRO_DEBUG>1 + USB.print(F("SCP.pwrCitiesPRORegister=")); + USB.println(pwrCitiesPRORegister, BIN); + USB.print(F("SCP.pwrGasPRORegister=")); + USB.println(pwrGasPRORegister, BIN); + #endif + + // Check I2C isolator + if ((pwrCitiesPRORegister == 0) && ((pwrGasPRORegister & 0xFE) == 0)) + { + // Disable I2C isolator + digitalWrite(SCP_I2C_MAIN_EN, LOW); + } + + if ((pwrGasPRORegister == 0x00) && + (pwrCitiesPRORegister == 0x00) && + ((WaspRegister & REG_3V3) != 0)) + { + #if CITIES_PRO_DEBUG>0 + USB.println(F("SCP.3V3 to OFF")); + #endif + PWR.setSensorPower(SENS_3V3, SENS_OFF); + } +} + +WaspSensorCitiesPRO SensorCitiesPRO=WaspSensorCitiesPRO(); + + +//************************************************************************************ +// Noise Sensor Class functions +//************************************************************************************ + +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +noiseSensor::noiseSensor() +{ + // store the UART to be used + _uart = 0x01; + _baudrate = 115200; + _def_delay = 50; +} + + +/*! + * @brief Get a new measure of SPLA + * @param + * @return uint8_t: Status of the last communication + */ +uint8_t noiseSensor::getSPLA(void) +{ + getSPLA(FAST_MODE); +} + + +/*! + * @brief Get a new measure of SPLA + * @param + * @return uint8_t: Status of the last communication + */ +uint8_t noiseSensor::getSPLA(uint8_t mode) +{ + uint8_t status; + + if (mode == SLOW_MODE) + { + // Send command for getting a new measure + status = sendCommand("ATSLOW", "OK", 5000); + } + else + { + // Send command for getting a new measure + status = sendCommand("ATFAST", "OK", 5000); + } + + // Request 8 bytes from the UART buffer + readBuffer(7, 1); + + if (status == 0) + { + #if DEBUG_CITIES_PRO > 0 + PRINTLN_CITIES_PRO(F("Timeout: No response from the Noise Sensor")); + #endif + + return -1; + } + else + { + status = parseFloat(&SPLA, "\r\n"); + + if (status == 0) + { + #if DEBUG_CITIES_PRO > 1 + PRINTLN_CITIES_PRO(F("Successful communication. Value stored in SPLA variable.")); + PRINTLN_CITIES_PRO(F("Value Stored in SPLA: ")); + PRINTLN_CITIES_PRO_VAL(SPLA); + #endif + + return status; + } + else + { + #if DEBUG_CITIES_PRO > 0 + PRINTLN_CITIES_PRO(F("Wrong response. Can't read data.")); + #endif + } + + return status; + } +} + + +/*! + * @brief Configure the UART for communicating with the sensor + * @param void + * @return void + */ +void noiseSensor::configure() +{ + // open mcu uart + beginUART(); + // set Auxiliar1 socket + Utils.setMuxAux1(); + // flush uart + serialFlush(_uart); +} + +// Instance of the class +noiseSensor noise = noiseSensor(); + + + diff --git a/libraries/SensorCities_PRO/WaspSensorCities_PRO.h b/libraries/SensorCities_PRO/WaspSensorCities_PRO.h new file mode 100755 index 0000000..772fc7c --- /dev/null +++ b/libraries/SensorCities_PRO/WaspSensorCities_PRO.h @@ -0,0 +1,151 @@ +/*! \file WaspSensorCitiesPRO.h + \brief Library for managing the Smart Cities PRO Sensor Board + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.1 + Design: David Gascón + Implementation: Alejandro Gállego, Ahmad Saad + + */ + + + /*! \def WaspSensorCitiesPRO_h + \brief The library flag + + */ +#ifndef WaspSensorCitiesPRO_h +#define WaspSensorCitiesPRO_h + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include +#include + + +/****************************************************************************** + * Definitions & Declarations + ******************************************************************************/ +#define SCP_PWR_SOCKET_1 ANA2 +#define SCP_PWR_SOCKET_2 DIGITAL5 +#define SCP_PWR_SOCKET_3 ANA5 +#define SCP_PWR_SOCKET_4 ANA6 +#define SCP_PWR_SOCKET_5 ANA1 +#define SCP_I2C_MAIN_EN ANA0 + + +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_CITIES_PRO 1 + +#define PRINT_CITIES_PRO(str) USB.print(F("[CITIES_PRO] ")); USB.print(str); +#define PRINT_CITIES_PRO_VAL(val) USB.print(float(val)); +#define PRINTLN_CITIES_PRO(str) USB.print(F("[CITIES_PRO] ")); USB.println(str); +#define PRINTLN_CITIES_PRO_VAL(val) USB.println(float(val)); + + +extern volatile uint8_t pwrCitiesPRORegister; +extern volatile uint8_t pwrGasPRORegister; + +/****************************************************************************** + * Class + ******************************************************************************/ + + //! WaspSensorCitiesPRO Class +/*! + WaspSensorCitiesPRO Class defines all the variables and functions used for managing the Smart Cities PRO Sensor Board + */ +class WaspSensorCitiesPRO +{ + private: + + public: + + //! class constructor + /*! + It initializes the different digital pins + \param void + \return void + */ + WaspSensorCitiesPRO(); + + + //! Turns ON the sensor/socket + /*! + \param uint8_t socket_sensor: SENS_CITIES_PRO_NOISE + SENS_CITIES_PRO_POLI1 + SENS_CITIES_PRO_GAS1 + SENS_CITIES_PRO_DUST + SENS_CITIES_PRO_POLI2 + SENS_CITIES_PRO_GAS2 + \return void + */ + void ON(uint8_t socket_sensor); + + + //! Turns OFF the sensor/socket + /*! + \param uint8_t socket_sensor: SENS_CITIES_PRO_NOISE + SENS_CITIES_PRO_POLI1 + SENS_CITIES_PRO_GAS1 + SENS_CITIES_PRO_DUST + SENS_CITIES_PRO_POLI2 + SENS_CITIES_PRO_GAS2 + \return void + */ + void OFF(uint8_t socket_sensor); + +}; + +extern WaspSensorCitiesPRO SensorCitiesPRO; + +#endif + + +#ifndef NOISESENSOR_H + +#define FAST_MODE 0x00 +#define SLOW_MODE 0x01 + +class noiseSensor : WaspUART +{ + + public: + + // Constructor + noiseSensor(); + // Sound Pressure Level with A-Weighting + float SPLA; + // Get a new measure of SPLA + uint8_t getSPLA(); + // Get a new measure of SPLA with SLOW or FAST configuration + uint8_t getSPLA(uint8_t); + // Configure the UART for communicating with the sensor + void configure(); + + private: + +}; + +extern noiseSensor noise; + +#endif + diff --git a/libraries/SensorCities_PRO/keywords.txt b/libraries/SensorCities_PRO/keywords.txt new file mode 100644 index 0000000..a964693 --- /dev/null +++ b/libraries/SensorCities_PRO/keywords.txt @@ -0,0 +1,48 @@ +# Cities PRO Keywords # + +SENS_CITIES_PRO_NOISE LITERAL1 +SENS_CITIES_PRO_POLI1 LITERAL1 +SENS_CITIES_PRO_GAS1 LITERAL1 +SENS_CITIES_PRO_DUST LITERAL1 +SENS_CITIES_PRO_POLI2 LITERAL1 +SENS_CITIES_PRO_GAS2 LITERAL1 + +SENS_CITIES_PRO_PWR_3V3 LITERAL1 +SENS_CITIES_PRO_PWR_5V LITERAL1 +SENS_CITIES_PRO_PWR_BOTH LITERAL1 +SENS_CITIES_PRO_NO_PWR LITERAL1 + +SCP_PWR_POLI_1 LITERAL1 +SCP_I2C_MAIN_EN LITERAL1 +SCP_CS_NOISE LITERAL1 +SCP_PWR_NOISE LITERAL1 +SCP_PWR_DUST LITERAL1 +SCP_CS_DUST LITERAL1 +SCP_PWR_GAS_2 LITERAL1 +SCP_I2C_GAS_2 LITERAL1 +SCP_PWR_POLI_2 LITERAL1 +SCP_PWR_GAS_1 LITERAL1 +SCP_I2C_GAS_1 LITERAL1 +SCP_POLI_1_ADC LITERAL1 +SCP_POLI_2_ADC LITERAL1 +SCP_NOISE_ADC LITERAL1 + +FAST_MODE LITERAL1 +SLOW_MODE LITERAL1 + +WaspSensorCitiesPRO KEYWORD3 +ON KEYWORD2 +OFF KEYWORD2 +setBoardMode KEYWORD2 +setSensorMode KEYWORD2 +setThreshold KEYWORD2 +setAudioGain KEYWORD2 +readValue KEYWORD2 +showLUT KEYWORD2 +readNoise KEYWORD2 +getSPLA KEYWORD2 +SPLA KEYWORD2 +noiseSensor KEYWORD2 + +SensorCitiesPRO KEYWORD1 +noise KEYWORD1 diff --git a/libraries/SensorEvent_v20/WaspSensorEvent_v20.cpp b/libraries/SensorEvent_v20/WaspSensorEvent_v20.cpp index 319dbb7..60a9dfc 100755 --- a/libraries/SensorEvent_v20/WaspSensorEvent_v20.cpp +++ b/libraries/SensorEvent_v20/WaspSensorEvent_v20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascón * Implementation: Alberto Bielsa, David Cuartielles */ @@ -56,7 +56,7 @@ WaspSensorEvent_v20::WaspSensorEvent_v20() PWR.setSensorPower(SENS_3V3, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_EVENTS; + WaspRegisterSensor |= REG_EVENTS; // init interruption attribute flag _intEnabled = false; @@ -646,13 +646,19 @@ void WaspSensorEvent_v20::setDigipot1(uint8_t address, float value) thres *=128; thres /=3.3; threshold = (uint8_t) thres; - if( !Wire.I2C_ON ) Wire.begin(); + + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00010000); Wire.send(threshold); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -674,13 +680,19 @@ void WaspSensorEvent_v20::setDigipot0(uint8_t address, float value) thres *=128; thres /=3.3; threshold = (uint8_t) thres; - if( !Wire.I2C_ON ) Wire.begin(); + + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00000000); Wire.send(threshold); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } diff --git a/libraries/SensorEvent_v20/WaspSensorEvent_v20.h b/libraries/SensorEvent_v20/WaspSensorEvent_v20.h index f4fd92d..0a4495c 100755 --- a/libraries/SensorEvent_v20/WaspSensorEvent_v20.h +++ b/libraries/SensorEvent_v20/WaspSensorEvent_v20.h @@ -1,7 +1,7 @@ /*! \file WaspSensorEvent_v20.h \brief Library for managing the Event Sensor Board V2.0 - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 - Design: David Gascón + Version: 3.0 + Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra */ diff --git a/libraries/SensorEvent_v20/keywords.txt b/libraries/SensorEvent_v20/keywords.txt index 4e8be08..bb4dd6c 100644 --- a/libraries/SensorEvent_v20/keywords.txt +++ b/libraries/SensorEvent_v20/keywords.txt @@ -36,4 +36,4 @@ attachInt KEYWORD2 detachInt KEYWORD2 loadInt KEYWORD2 -SensorEventv20 KEYWORD3 +SensorEventv20 KEYWORD1 diff --git a/libraries/SensorEvent_v30/WaspSensorEvent_v30.cpp b/libraries/SensorEvent_v30/WaspSensorEvent_v30.cpp new file mode 100755 index 0000000..1cbb66b --- /dev/null +++ b/libraries/SensorEvent_v30/WaspSensorEvent_v30.cpp @@ -0,0 +1,1034 @@ +/* + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.1 + * Design: David Gascón + * Implementation: Carlos Bello + */ + + + +#ifndef __WPROGRAM_H__ + #include +#endif + +// BME280 library for reading temperature, humidity and pressure values +#include "BME280.h" +#include "Wire.h" +#include "WaspSensorEvent_v30.h" +#include + +//********************************************************************** +// EVENTOS SENSOR BOARD CLASS +//********************************************************************** + +//====================================================================== +// PUBLIC METHODS +//====================================================================== + +//!********************************************************************* +//! Name: EventsSensorClass() +//! Description: Class contructor +//! Param : void +//! Returns: void +//!********************************************************************* +WaspSensorEvent_v30::WaspSensorEvent_v30() +{ + //PWR.setSensorPower( SENS_5V, SENS_OFF); + //PWR.setSensorPower(SENS_3V3, SENS_OFF); + // init interruption attribute flag + _intEnabled = true; +} + +//!********************************************************************* +//! Name: getTemperature() +//! Description: Gets the temperature from the BME280 sensor +//! Param : void +//! Returns: float: temperature value read +//!********************************************************************* +float WaspSensorEvent_v30::getTemperature() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + value = BME.getTemperature(BME280_OVERSAMP_1X, 0); + #if DEBUG_EVN==1 + PRINT_EVENT(F("getTemperature:")); + USB.println(value); + #endif + + #if DEBUG_EVN==2 + PRINT_EVENT(F("getTemperature:")); + USB.println(value); + PRINT_EVENT(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + + // Read the temperature from the BME280 Sensor + return value; +} + +//!********************************************************************* +//! Name: getHumidity() +//! Description: Gets the Humidity from the BME280 sensor +//! Param : void +//! Returns: float: humidity value read +//!********************************************************************* +float WaspSensorEvent_v30::getHumidity() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + // Read the humidity from the BME280 Sensor + value = BME.getHumidity(BME280_OVERSAMP_1X); + #if DEBUG_EVN==1 + PRINT_EVENT(F("getHumidity:")); + USB.println(value); + #endif + + #if DEBUG_EVN==2 + PRINT_EVENT(F("getHumidity:")); + USB.println(value); + PRINT_EVENT(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + // Read the temperature from the BME280 Sensor + return value; +} + +//!********************************************************************* +//! Name: getPressure() +//! Description: Gets the Pressure from the BME280 sensor +//! Param : void +//! Returns: float: pressure value read +//!********************************************************************* +float WaspSensorEvent_v30::getPressure() { + float value = 0; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + //Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + // Read the pressure from the BME280 Sensor + value = BME.getPressure(BME280_OVERSAMP_1X, 0); + delay(100); + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + #if DEBUG_EVN==1 + PRINT_EVENT(F("getPressure:")); + USB.println(value); + #endif + + #if DEBUG_EVN==2 + PRINT_EVENT(F("getPressure:")); + USB.println(value); + PRINT_EVENT(F("BME280_OVERSAMP_1X")); + USB.println(BME280_OVERSAMP_1X); + #endif + // Read the temperature from the BME280 Sensor + return value; +} +//====================================================================== +// PUBLIC METHODS +//====================================================================== +//!********************************************************************* +//! Name: ON() +//! Description: Switch ON the power supply and configure the I/O pins +//! Param : void +//! Returns: void +//!********************************************************************* +void WaspSensorEvent_v30::ON() { + // Configure the internal reference + //analogReference(INTERNAL2V56); + //pinMode(DIGITAL5,INPUT); //PULS FLOW CHANNEL A + // Configure pins + pinMode(ANA0,INPUT); //REL_EXT_INT EVENTS + pinMode(ANA1,OUTPUT); //K1 OUT + pinMode(ANA2,INPUT); //PULS E + pinMode(ANA3,INPUT); //PULS D + pinMode(ANA4,INPUT); //PULS C + pinMode(ANA5,OUTPUT); //I2C MAIN PIN + pinMode(DIGITAL5,INPUT); //PULS FLOW CHANNEL A + pinMode(DIGITAL1,INPUT); //PULS FLOW CHANNEL A + pinMode(SENS_INT_CLK_INH,OUTPUT); //PULS FLOW CHANNEL A + pinMode(SENS_INT_CLK_REG,OUTPUT); //PULS FLOW CHANNEL A + pinMode(SENS_INT_ENABLE,OUTPUT); //PULS FLOW CHANNEL A + pinMode(SENS_INT_ENABLE,OUTPUT); //PULS FLOW CHANNEL A + delay(10); + //Set Firts Time Values + digitalWrite(DIGITAL0,LOW); + digitalWrite(ANA0,LOW); + digitalWrite(ANA1,LOW); + digitalWrite(ANA2,LOW); + digitalWrite(ANA3,LOW); + digitalWrite(ANA4,LOW); + digitalWrite(ANA5,LOW); + //I2C ISOLATOR PIN ENABLE + pinMode(I2C_PIN_OE, OUTPUT); + digitalWrite(I2C_PIN_OE, LOW); + // Switch ON 3V3 and 5V for supplying the board + PWR.setSensorPower(SENS_5V, SENS_ON); + PWR.setSensorPower(SENS_3V3, SENS_ON); + _intEnabled = true; + + if (_boot_version < 'H') + { + USB.println(F("\n*************** WARNING *******************")); + USB.println(F("This example is valid only for Waspmote v15.")); + USB.println(F("Your Waspmote version is v12.")); + USB.println(F("*******************************************")); + return (void)0; + } +} + +//!********************************************************************* +//! Name: OFF() +//! Description: Switch OFF the power supply +//! Param : void +//! Returns: void +//!********************************************************************* +void WaspSensorEvent_v30::OFF(){ + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + Wire.isBoard = false; + // Switch OFF 3V3 and 5V + PWR.setSensorPower(SENS_5V, SENS_OFF); + PWR.setSensorPower(SENS_3V3, SENS_OFF); + delay(100); +} +//!********************************************************************* +//! Name: attachInt() +//! Description: enable Interrupts +//! Param : void +//!********************************************************************* +void WaspSensorEvent_v30::attachInt() +{ + #if DEBUG_EVN > 0 + PRINT_EVENT(F("attachInt function\r\n\r\n")); + #endif + //digitalWrite(SENS_INT_ENABLE,HIGH); + digitalWrite(SENS_INT_ENABLE,HIGH); + enableInterrupts(SENS_INT); + _intEnabled = true; +} +//!********************************************************************* +//! Name: detachInt() +//! Description: disable Interrupts +//! Param : void +//!********************************************************************* +void WaspSensorEvent_v30::detachInt() +{ + #if DEBUG_EVN > 0 + PRINT_EVENT(F("detachInt function\r\n")); + #endif + digitalWrite(SENS_INT_ENABLE,LOW); + disableInterrupts(SENS_INT); + _intEnabled = false; +} + + + +/* loadInt: Loads shift register through parallel input to check the sensor + * that generates the interruption updating 'intFlag' + * Parameters: void + * Return: uint8_t loadInt : as long as updating the 'intFlag' variable, it + * returns the same value as a uint8_t + * + */ +void WaspSensorEvent_v30::loadInt() +{ + input1Flag = false; + input2Flag = false; + input3Flag = false; + input4Flag = false; + input6Flag = false; + flowFlag = false; + + #if DEBUG_EVN > 0 + PRINT_EVENT(F("loadInt function\r\n")); + #endif + + digitalWrite(SENS_INT_ENABLE,LOW); + delay(10); + digitalWrite(SENS_INT_CLK_INH, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + flowFlag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + input6Flag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + input3Flag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + input2Flag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + input1Flag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + input4Flag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + flowFlag = true; + } + delay(2); + digitalWrite(SENS_INT_CLK_REG, LOW); + delay(2); + digitalWrite(SENS_INT_CLK_REG, HIGH); + if(digitalRead(DIGITAL1) == 1){ + flowFlag = true; + } + delay(200); + digitalWrite(SENS_INT_ENABLE, HIGH); + digitalWrite(SENS_INT_ENABLE,HIGH); + digitalWrite(SENS_INT_CLK_INH, HIGH); +} + + +//!********************************************************************* +//! Name: readInput() +//! Description: Read digital information about objets inputs +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t WaspSensorEvent_v30::readInput(uint8_t _socket){ + uint8_t aux = 0; + // get actual interruption state flag + bool isEnabled = _intEnabled;// disable interruption + Events.detachInt(); + switch (_socket){ + case SOCKET_1: + case SOCKET_C: + aux = digitalRead(PULS_C); + #if DEBUG_EVN > 1 + PRINT_EVENT(F("Read SOCKET_1 or SOCKET_C\r\n")); + #endif + break; + case SOCKET_2: + case SOCKET_D: + aux = digitalRead(PULS_D); + #if DEBUG_EVN > 1 + PRINT_EVENT(F("Read SOCKET_2 or SOCKET_D\r\n")); + #endif + break; + case SOCKET_3: + case SOCKET_E: + aux = digitalRead(PULS_E); + #if DEBUG_EVN > 1 + PRINT_EVENT(F("Read SOCKET_3 or SOCKET_E\r\n")); + #endif + break; + case SOCKET_4: + case SOCKET_A: + aux = digitalRead(PULS_A); + #if DEBUG_EVN > 1 + PRINT_EVENT(F("Read SOCKET_4 or SOCKET_A\r\n")); + #endif + break; + case SOCKET_6: + aux = digitalRead(PULS_F); + #if DEBUG_EVN > 1 + PRINT_EVENT(F("Read SOCKET_6\r\n")); + #endif + break; + + default: + #if DEBUG_EVN > 0 + PRINT_EVENT(F("Incorrect input\r\n")); + #endif + break; + } + // re-enable interruption if needed + if( isEnabled == true ) + { + delay(50); + Events.attachInt(); + } + return aux; +} + +//!********************************************************************* +//! Name: getDistance() +//! Description: Gets distance from Ultrasound Sensor +//! Param : void +//! Returns: float: distance value read +//!********************************************************************* +uint16_t WaspSensorEvent_v30::getDistance(){ + uint16_t value; + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + value = Ultrasound.getDistance(); + delay(100); + // Switch OFF I2C + #if DEBUG_EVN > 0 + PRINT_EVENT(F("getDistance function: ")); + USB.println(value); + #endif + digitalWrite(I2C_PIN_OE, LOW); + return value; +} + + +//!********************************************************************* +//! Name: getLuxes() +//! Description: Gets luxes from TSL2561 +//! Param : gain ( OUTDOOR OR INDOOR) +//! Returns: float: luxes value read +//!********************************************************************* +uint32_t WaspSensorEvent_v30::getLuxes(uint8_t gain){ + uint32_t value; + TSL.ON(); + //Switch ON I2C + digitalWrite(I2C_PIN_OE, HIGH); + delay(100); + switch (gain) + { + case INDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_16); + break; + + case OUTDOOR: + default: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_1); + break; + + } + value = TSL.lux; + delay(100); + #if DEBUG_EVN > 0 + PRINT_EVENT(F("getLuxes function: ")); + USB.println(value); + #endif + // Switch OFF I2C + digitalWrite(I2C_PIN_OE, LOW); + return value; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// +WaspSensorEvent_v30 Events = WaspSensorEvent_v30(); +//************************************************************************************************** +// Hall Effect Class +//************************************************************************************************** +hallSensorClass::hallSensorClass(uint8_t socket){ + hallEffectSocket = socket; +} + + +//!********************************************************************* +//! Name: read() +//! Description: Read digital information about hallSensor +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t hallSensorClass::read(){ + return readInput(hallEffectSocket); +} + +//!********************************************************************* +//! Name: readHallSensor() +//! Description: Read digital information about hallSensor +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t hallSensorClass::readHallSensor(){ + return readInput(hallEffectSocket); +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* +bool hallSensorClass::getInt(){ + bool aux = false; + #if DEBUG_EVN > 0 + PRINT_EVENT(F("getInt function: \r\n")); + #endif + + switch (hallEffectSocket){ + case SOCKET_1: + case SOCKET_C: + aux = Events.input1Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: \r\n")); + USB.println(aux); + #endif + break; + case SOCKET_2: + case SOCKET_D: + aux = Events.input2Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: \r\n")); + USB.println(aux); + #endif + break; + case SOCKET_3: + case SOCKET_E: + aux = Events.input3Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: \r\n")); + USB.println(aux); + #endif + break; + case SOCKET_4: + case SOCKET_A: + aux = Events.input4Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_6: + aux = Events.input6Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + default: + break; + } + return aux; +} +//************************************************************************************************** +// PIR Sensor Class +//************************************************************************************************** +pirSensorClass::pirSensorClass(uint8_t socket){ + pirSensorSocket = socket; +} + + +//!********************************************************************* +//! Name: read() +//! Description: Read digital information about pir sensor +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t pirSensorClass::read(){ + return readInput(pirSensorSocket); +} +//!********************************************************************* +//! Name: readPirSensor() +//! Description: Read digital information about pir sensor +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t pirSensorClass::readPirSensor(){ + return readInput(pirSensorSocket); +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* + +bool pirSensorClass::getInt(){ + bool aux = false; + + switch (pirSensorSocket){ + case SOCKET_1: + case SOCKET_C: + aux = Events.input1Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_2: + case SOCKET_D: + aux = Events.input2Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_3: + case SOCKET_E: + aux = Events.input3Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_4: + case SOCKET_A: + aux = Events.input4Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_6: + aux = Events.input6Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + default: + break; + } + return aux; +} + +//************************************************************************************************** +// Liquid Level Class +//************************************************************************************************** +liquidLevelClass::liquidLevelClass(uint8_t socket){ + liquidLevelSocket = socket; +} + +//!********************************************************************* +//! Name: read() +//! Description: Read digital information about liquid level +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t liquidLevelClass::read(){ + return readInput(liquidLevelSocket); +} +//!********************************************************************* +//! Name: readliquidLevel() +//! Description: Read digital information about liquid level +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t liquidLevelClass::readliquidLevel(){ + return readInput(liquidLevelSocket); +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* +bool liquidLevelClass::getInt(){ + bool aux = false; + + switch (liquidLevelSocket){ + case SOCKET_1: + case SOCKET_C: + aux = Events.input1Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_2: + case SOCKET_D: + aux = Events.input2Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_3: + case SOCKET_E: + aux = Events.input3Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_4: + case SOCKET_A: + aux = Events.input4Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_6: + aux = Events.input6Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + default: + break; + } + return aux; +} +//************************************************************************************************** +// Liquid Presence Sensor Class +//************************************************************************************************** +liquidPresenceClass::liquidPresenceClass(uint8_t socket){ + liquidPresenceSocket = socket; +} + + +//!********************************************************************* +//! Name: readliquidPresence() +//! Description: Read digital information about liquid presence +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t liquidPresenceClass::read(){ + return readInput(liquidPresenceSocket); +} +//!********************************************************************* +//! Name: readliquidPresence() +//! Description: Read digital information about liquid presence +//! Call readInput() function from WaspSensorEvents +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t liquidPresenceClass::readliquidPresence(){ + return readInput(liquidPresenceSocket); +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* +bool liquidPresenceClass::getInt(){ + bool aux = false; + + switch (liquidPresenceSocket){ + case SOCKET_1: + case SOCKET_C: + aux = Events.input1Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_2: + case SOCKET_D: + aux = Events.input2Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_3: + case SOCKET_E: + aux = Events.input3Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_4: + case SOCKET_A: + aux = Events.input4Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + case SOCKET_6: + aux = Events.input6Flag; + #if DEBUG_EVN > 1 + PRINT_EVENT(F("getInt function: ")); + USB.println(aux); + #endif + break; + default: + break; + } + return aux; +} +//************************************************************************************************** +// Relay Class +//************************************************************************************************** +//!************************************************************************************* +//! Name: relayClass() +//! Description: Class contructor +//! Param : void +//! Returns: void +//!************************************************************************************* +relayClass::relayClass() +{ +} + +//!********************************************************************* +//! Name: read() +//! Description: Read digital information about In Rel +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t relayClass::read(){ + return readInRel(); +} + +//!********************************************************************* +//! Name: readInRel() +//! Description: Read digital information about In Rel +//! Param : void +//! Returns: int: 0 or 1 +//!********************************************************************* +uint8_t relayClass::readInRel(){ + uint8_t aux = 0; + // get actual interruption state flag + bool isEnabled = _intEnabled;// disable interruption + detachInt(); + aux = digitalRead(PULS_F); + // re-enable interruption if needed + if( isEnabled == true ) + { + delay(50); + attachInt(); + } + return aux; +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* +bool relayClass::getInt(){ + bool aux = false; + aux = Events.input6Flag; + return aux; +} +//!********************************************************************* +//! Name: relayON() +//! Description: Switch ON Relay Output +//! Param : void +//!********************************************************************* +void relayClass::relayON() +{ + #if DEBUG_EVN > 0 + PRINT_EVENT(F("Relay On\r\n")); + #endif + digitalWrite(ANA1,HIGH); +} +//!********************************************************************* +//! Name: relayOFF() +//! Description: Switch ON Relay Output +//! Param : void +//!********************************************************************* +void relayClass::relayOFF() +{ + #if DEBUG_EVN > 0 + PRINT_EVENT(F("Relay Off\r\n")); + #endif + digitalWrite(ANA1,LOW); +} +//************************************************************************************************** +// flowClass Class +//************************************************************************************************** +//!************************************************************************************* +//! Name: flowClass() +//! Description: Class contructor +//! Param : void +//! Returns: void +//!************************************************************************************* +flowClass::flowClass(uint8_t model) +{ + _model = model; + disableFlowInt(); +} +/* flowReading: reads the analog to digital converter input indicated + * in socket and converts the value into distance in + * function of the sensor selected in mode + * Parameters: uint8_t socket : digital input to be read (FLOW_B) + * uint8_t model + * - SENS_FLOW_FS100 : Selects FS100A flow sensor + * - SENS_FLOW_FS200 : Selects FS200A flow sensor + * - SENS_FLOW_FS400 : Selects FS400A flow sensor + * - SENS_FLOW_YFS401 : Selects YFS401 flow sensor + * - SENS_FLOW_FS300 : Selects FS300 flow sensor + * - SENS_FLOW_YFG1 : Selects YFG1 flow sensor + * + * Return: float flow : flow measured by the sensor in litres/minute + * -1.0 for error in sensor type selection + * + */ +//!********************************************************************* +//! Name: read() +//! Description: Count pulses from input flow +//! Param : void +//! Returns: float: flow value read +//!********************************************************************* +float flowClass::read() +{ + return flowReading(); +} + + +//!********************************************************************* +//! Name: flowReading() +//! Description: Count pulses from input flow +//! Param : void +//! Returns: float: flow value read +//!********************************************************************* +float flowClass::flowReading() +{ + float flow = 0.0; + int value = 0; + long start = 0; + int previous_reading = 0; + int reading = 0; + bool isEnabled = _intEnabled;// disable interruption + detachInt(); + start = millis(); + while((millis()-start)<=1000) + { + previous_reading = reading; + reading = digitalRead(DIGITAL5); + if((previous_reading == 1)&&(reading == 0)) + { + value++; + } + if( millis() < start ) + { + value = 0; + start = millis(); + } + } + delay(100); + #if DEBUG_EVN > 0 + PRINT_EVENT(F("Flow control\r\n")); + #endif + switch(_model) + { + case SENS_FLOW_FS100 : flow = float(value) / 65; + break; + + case SENS_FLOW_FS200 : flow = float(value) / 7.5; + break; + + case SENS_FLOW_FS400 : flow = float(value) / 6.5; + break; + + case SENS_FLOW_YFS401 : flow = float(value) / 96; + break; + + case SENS_FLOW_FS300 : flow = float(value) / 5.5; + break; + + case SENS_FLOW_YFG1 : flow = float(value) / 1.85; + break; + + default : flow = -1.0; + break; + } + if( isEnabled == true ) + { + delay(50); + attachInt(); + } + return flow; +} + +//!********************************************************************* +//! Name: getInt() +//! Description: Get interruption from object +//! Param : void +//! Returns: bool: True or False +//!********************************************************************* +bool flowClass::getInt(){ + bool aux = false; + aux = Events.flowFlag; + return aux; +} + + + +//!********************************************************************* +//! Name: enableFlowInt() +//! Description: enable Interrupts from the flow sensor +//! Param : void +//!********************************************************************* +void flowClass::enableFlowInt() +{ + // get current 'intFlag' and sensor output + uint8_t flag = intFlag & SENS_INT; + uint8_t output = digitalRead(DIGITAL5); + + // enable flow ints + pinMode(SENS_INT_FLOW_EN, OUTPUT); + digitalWrite(SENS_INT_FLOW_EN, HIGH); + + // clear 'intFlag' if enabling triggered the event + if ((output == HIGH) && (flag == 0)) + { + intFlag &= ~(SENS_INT); + } +} + +//!********************************************************************* +//! Name: disableFlowInt() +//! Description: disable Interrupts from the flow sensor +//! Param : void +//!********************************************************************* +void flowClass::disableFlowInt() +{ + // disable flow ints + pinMode(SENS_INT_FLOW_EN, OUTPUT); + digitalWrite(SENS_INT_FLOW_EN, LOW); + +} + diff --git a/libraries/SensorEvent_v30/WaspSensorEvent_v30.h b/libraries/SensorEvent_v30/WaspSensorEvent_v30.h new file mode 100755 index 0000000..0b2514f --- /dev/null +++ b/libraries/SensorEvent_v30/WaspSensorEvent_v30.h @@ -0,0 +1,228 @@ +/*! \file WaspSensorEvent_v30.h + \brief Library for managing the Events Sensor Board + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.1 + Design: David Gascón + Implementation: Carlos Bello + +*/ + + /*! \def WaspSensorGas_h + \brief The library flag + + */ +#ifndef WaspSensorEvent_v30_h +#define WaspSensorEvent_v30_h + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include +#include "UltrasoundSensor.h" +#include +//********************************************************************** +// DEBUG MODES +//********************************************************************** + +/*! Possible values: + * 0: No debug mode enabled + * 1: debug 1 + * 2: debug 2 + */ +#define DEBUG_EVN 0 + +// define print message +#define PRINT_EVENT(str) USB.print(F("[EVENT] ")); USB.print(str); + + +//********************************************************************** +// DEFINES INPUTS INPUTS +//********************************************************************** +#define FLOW_B DIGITAL5 +#define I2C_PIN_OE ANA5 +#define PULS_A ANA6 +#define PULS_C ANA4 +#define PULS_D ANA3 +#define PULS_E ANA2 +#define PULS_F ANA0 +// Event Sensor Board +#define SENS_INT_PIN_MON DIGITAL2 // PA2 +#define SENS_INT_CLK_REG DIGITAL7 // PC4 +#define SENS_INT_DO DIGITAL1 // PE3 +#define SENS_INT_ENABLE DIGITAL8 // PC5 +#define SENS_INT_CLK_INH DIGITAL3 // PA4 +#define SENS_INT_FLOW_EN DIGITAL4 +//********************************************************************** +// DEFINES FLOW SENSORS +//********************************************************************** +#define SENS_FLOW_FS100 1 +#define SENS_FLOW_FS200 2 +#define SENS_FLOW_FS400 3 +#define SENS_FLOW_YFS401 4 +#define SENS_FLOW_FS300 5 +#define SENS_FLOW_YFG1 6 + + +//************************************************************************************************** +// Smart Agriculture Board Class +//************************************************************************************************** +class WaspSensorEvent_v30 +{ + public: + + WaspSensorEvent_v30(); + void ON(void); + void OFF(void); + void attachInt(); + void detachInt(); + uint8_t readInput(uint8_t); + void loadInt(); + float getTemperature(); + float getHumidity(); + float getPressure(); + uint16_t getDistance(); + uint32_t getLuxes(uint8_t); + friend class relayClass; + friend class flowClass; + friend class hallSensorClass; + friend class pirSensorClass; + friend class liquidLevelClass; + friend class liquidPresenceClass; + bool _intEnabled; + + // Interruption Inputs Vars + bool input1Flag; + bool input2Flag; + bool input3Flag; + bool input4Flag; + bool input6Flag; + bool flowFlag; +}; +extern WaspSensorEvent_v30 Events; +#endif + +//************************************************************************************************** +// Hall Effect class +//************************************************************************************************** +#ifndef hallSensorClass_h +#define hallSensorClass_h + +class hallSensorClass : public WaspSensorEvent_v30 +{ + public: + hallSensorClass(uint8_t); + uint8_t read(); + uint8_t readHallSensor(); + bool getInt(); + private: + uint8_t hallEffectSocket; +}; +#endif + +//************************************************************************************************** +// PIR Sensor class +//************************************************************************************************** +#ifndef pirSensorClass_h +#define pirSensorClass_h + +class pirSensorClass : public WaspSensorEvent_v30 +{ + public: + pirSensorClass(uint8_t); + uint8_t read(); + uint8_t readPirSensor(); + bool getInt(); + private: + uint8_t pirSensorSocket; +}; +#endif + +//************************************************************************************************** +// Liquid Level Class +//************************************************************************************************** +#ifndef liquidLevelClass_h +#define liquidLevelClass_h + +class liquidLevelClass : public WaspSensorEvent_v30 +{ + public: + liquidLevelClass(uint8_t); + uint8_t read(); + uint8_t readliquidLevel(); + bool getInt(); + private: + uint8_t liquidLevelSocket; +}; +#endif + +//************************************************************************************************** +// Liquid Presence Sensor Class +//************************************************************************************************** +#ifndef liquidPresenceClass_h +#define liquidPresenceClass_h + +class liquidPresenceClass : public WaspSensorEvent_v30 +{ + public: + liquidPresenceClass(uint8_t); + uint8_t read(); + uint8_t readliquidPresence(); + bool getInt(); + private: + uint8_t liquidPresenceSocket; +}; +#endif +//************************************************************************************************** +// Relay class +//************************************************************************************************** +#ifndef relayClass_h +#define relayClasss_h + +class relayClass : public WaspSensorEvent_v30 +{ + public: + relayClass(); + uint8_t read(); + uint8_t readInRel(); + void relayON(); + void relayOFF(); + bool getInt(); +}; +#endif + +//************************************************************************************************** +// flowReadingClass class +//************************************************************************************************** +#ifndef flowClass_h +#define flowClass_h + +class flowClass : public WaspSensorEvent_v30 +{ + public: + flowClass(uint8_t); + float flowReading(); + float read(); + bool getInt(); + void enableFlowInt(); + void disableFlowInt(); + private: + uint8_t _model; +}; +#endif diff --git a/libraries/SensorEvent_v30/keywords.txt b/libraries/SensorEvent_v30/keywords.txt new file mode 100644 index 0000000..de7d96a --- /dev/null +++ b/libraries/SensorEvent_v30/keywords.txt @@ -0,0 +1,42 @@ +# Event_v30 keywords # + +Events KEYWORD1 + +WaspSensorEvent_v30 KEYWORD2 +ON KEYWORD2 +OFF KEYWORD2 +getDistance KEYWORD2 +getLuxes KEYWORD2 +getPressure KEYWORD2 +getTemperature KEYWORD2 +getHumidity KEYWORD2 +attachInt KEYWORD2 +detachInt KEYWORD2 +loadInt KEYWORD2 +enableFlowInt KEYWORD2 +disableFlowInt KEYWORD2 + +getInt KEYWORD2 +flowClass KEYWORD2 +flowReading KEYWORD2 +hallSensorClass KEYWORD2 +readHallSensor KEYWORD2 +liquidLevelClass KEYWORD2 +readliquidLevel KEYWORD2 +liquidPresenceClass KEYWORD2 +readliquidPresence KEYWORD2 +pirSensorClass KEYWORD2 +readPirSensor KEYWORD2 +relayClass KEYWORD2 +readInRel KEYWORD2 +relayOFF KEYWORD2 +relayON KEYWORD2 + +SENS_FLOW_FS100 LITERAL1 +SENS_FLOW_FS200 LITERAL1 +SENS_FLOW_FS400 LITERAL1 +SENS_FLOW_YFS401 LITERAL1 +SENS_FLOW_FS300 LITERAL1 +SENS_FLOW_YFG1 LITERAL1 +OUTDOOR LITERAL1 +INDOOR LITERAL1 diff --git a/libraries/SensorGas_PRO/LMP91000.cpp b/libraries/SensorGas_PRO/LMP91000.cpp index a584c14..5dc003d 100755 --- a/libraries/SensorGas_PRO/LMP91000.cpp +++ b/libraries/SensorGas_PRO/LMP91000.cpp @@ -1,7 +1,7 @@ /* * Library for managing the LMP91000 AFE * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ @@ -54,7 +54,7 @@ bool LMP91000::check() &status, LMP91000_STATUS_REG_STATUS__POS); - if ((answer != 1) || (status == 0)) + if ((answer != 0) || (status == 0)) { return 0; } @@ -127,18 +127,23 @@ int8_t LMP91000::getRgain() uint8_t r_gain; #if LMP_DEBUG>0 - USB.println(F("LMP.Reading r_gain")); + USB.print(F("LMP.Reading r_gain...")); #endif answer = Wire.readBits( I2C_ADDRESS_GASPRO_LMP91000, LMP91000_TIAC_REG, &r_gain, LMP91000_TIAC_REG_REF_R_GAIN__POS, LMP91000_TIAC_REG_REF_R_GAIN__LEN); - if (answer == 1) - { + if (answer == 0) + { + #if LMP_DEBUG>0 + USB.println(r_gain, DEC); + #endif return r_gain; } - + #if LMP_DEBUG>0 + USB.println(F("error")); + #endif return answer; } @@ -189,7 +194,7 @@ int8_t LMP91000::getInternalZero() &internal_zero, LMP91000_REFC_REG_REF_INT_Z__POS, LMP91000_REFC_REG_REF_INT_Z__LEN); - if (answer == 1) + if (answer == 0) { return internal_zero; } @@ -239,7 +244,7 @@ int8_t LMP91000::getRefSource() LMP91000_REFC_REG, &ref_source, LMP91000_REFC_REG_REF_SOURCE__POS); - if (answer == 1) + if (answer == 0) { return ref_source; } @@ -283,7 +288,7 @@ uint8_t LMP91000::getTIAConReg() &buffer, 1); - if (answer == 1) + if (answer == 0) { return buffer; } @@ -309,7 +314,7 @@ uint8_t LMP91000::getRefConReg() &buffer, 1); - if (answer == 1) + if (answer == 0) { return buffer; } @@ -335,7 +340,7 @@ uint8_t LMP91000::getModeReg() &buffer, 1); - if (answer == 1) + if (answer == 0) { return buffer; } diff --git a/libraries/SensorGas_PRO/LMP91000.h b/libraries/SensorGas_PRO/LMP91000.h index fe2c3d6..3540d09 100755 --- a/libraries/SensorGas_PRO/LMP91000.h +++ b/libraries/SensorGas_PRO/LMP91000.h @@ -1,7 +1,7 @@ /*! \file LMP91000.h \brief Library for managing the LMP91000 AFE - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego diff --git a/libraries/SensorGas_PRO/MCP3421.cpp b/libraries/SensorGas_PRO/MCP3421.cpp index d1a79a0..efb0442 100755 --- a/libraries/SensorGas_PRO/MCP3421.cpp +++ b/libraries/SensorGas_PRO/MCP3421.cpp @@ -1,7 +1,7 @@ /* * Library for managing the MCP3421 ADC * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Alejandro Gállego */ @@ -34,6 +34,7 @@ MCP3421::MCP3421(){ } + /* Function: This function performs a conversion with the desired parameters * Parameters: resolution: resolution value for ADC conversion * MCP3421_RES_12_BIT or MCP3421_LOW_RES @@ -48,7 +49,28 @@ MCP3421::MCP3421(){ * conversion: MCP3421_RAW or MCP3421_VOLTS * Return: measure in milliVolts or raw */ -float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ +float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ) +{ + return readADC(I2C_ADDRESS_GASPRO_MCP3421_A1, resolution, gain, conversion); +} + + +/* Function: This function performs a conversion with the desired parameters + * Parameters: ADC_addr: I2C address for the ADC + * resolution: resolution value for ADC conversion + * MCP3421_RES_12_BIT or MCP3421_LOW_RES + * MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + * MCP3421_RES_16_BIT or MCP3421_HIGH_RES + * MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + * gain: gain setting for ADC + * MCP3421_GAIN_1 + * MCP3421_GAIN_2 + * MCP3421_GAIN_4 + * MCP3421_GAIN_8 + * conversion: MCP3421_RAW or MCP3421_VOLTS + * Return: measure in milliVolts or raw + */ +float MCP3421::readADC(uint8_t ADC_addr, uint8_t resolution, uint8_t gain, uint8_t conversion ){ uint8_t config_reg, val1, val2, val3; @@ -58,12 +80,12 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ long aux_val; - if( !Wire.I2C_ON ) Wire.begin(); + if( !Wire.isON ) Wire.begin(); // Primero se manda la orden de conversion - Wire.beginTransmission(I2C_ADDRESS_GASPRO_MCP3421); + Wire.beginTransmission(ADC_addr); - config_reg = 128 + (resolution * 4) + gain; + config_reg = 128 +(resolution * 4) + gain; Wire.send(config_reg); // start from address theAddress Wire.endTransmission(); @@ -74,7 +96,7 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ case MCP3421_RES_12_BIT: delay(6); //Leer 3 bytes ( 2 de datos + configuracion) - Wire.requestFrom(I2C_ADDRESS_GASPRO_MCP3421, 0x03); + Wire.requestFrom(ADC_addr, (uint8_t)0x03); tempo = millis(); while((Wire.available() < 3) && ((millis() - tempo) < MCP3421_I2C_READ_TIMEOUT)) { @@ -104,7 +126,7 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ case MCP3421_RES_14_BIT: delay(18); //Leer 3 bytes ( 2 de datos + configuracion) - Wire.requestFrom(I2C_ADDRESS_GASPRO_MCP3421, 0x03); + Wire.requestFrom(ADC_addr, (uint8_t)0x03); tempo = millis(); while((Wire.available() < 3) && ((millis() - tempo) < MCP3421_I2C_READ_TIMEOUT)) { @@ -135,7 +157,7 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ case MCP3421_RES_16_BIT: delay(68); //Leer 3 bytes ( 2 de datos + configuracion) - Wire.requestFrom(I2C_ADDRESS_GASPRO_MCP3421, 0x03); + Wire.requestFrom(ADC_addr, (uint8_t)0x03); tempo = millis(); while((Wire.available() < 3) && ((millis() - tempo) < MCP3421_I2C_READ_TIMEOUT)) { @@ -166,7 +188,7 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ case MCP3421_RES_18_BIT: delay(300); //Leer 3 bytes ( 3 de datos + configuracion) - Wire.requestFrom(I2C_ADDRESS_GASPRO_MCP3421, 0x04); + Wire.requestFrom(ADC_addr, (uint8_t)0x04); tempo = millis(); while((Wire.available() < 4) && ((millis() - tempo) < MCP3421_I2C_READ_TIMEOUT)) { @@ -206,7 +228,10 @@ float MCP3421::readADC(uint8_t resolution, uint8_t gain, uint8_t conversion ){ } - + if ((config_reg & 0x80) != 0) + { + USB.print("ADC N_RDY"); + } return value; } diff --git a/libraries/SensorGas_PRO/MCP3421.h b/libraries/SensorGas_PRO/MCP3421.h index 741d977..f0e60ab 100755 --- a/libraries/SensorGas_PRO/MCP3421.h +++ b/libraries/SensorGas_PRO/MCP3421.h @@ -1,7 +1,7 @@ /*! \file MCP3421.h \brief Library for managing the MCP3421 ADC - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego @@ -46,9 +46,9 @@ #define MCP3421_RES_18_BIT 3 #define MCP3421_LOW_RES 0 -#define MCP3421_MEDIUM_RES 1 -#define MCP3421_HIGH_RES 2 -#define MCP3421_ULTRA_HIGH_RES 3 +#define MCP3421_MEDIUM_RES 1 +#define MCP3421_HIGH_RES 2 +#define MCP3421_ULTRA_HIGH_RES 3 // gain setting for ADC #define MCP3421_GAIN_1 0 @@ -57,7 +57,7 @@ #define MCP3421_GAIN_8 3 // conversion -#define MCP3421_RAW 0 +#define MCP3421_RAW 0 #define MCP3421_VOLTS 1 /****************************************************************************** @@ -70,9 +70,9 @@ */ class MCP3421 { - private: + private: - public: + public: MCP3421(); @@ -94,6 +94,25 @@ class MCP3421 */ float readADC(uint8_t resolution, uint8_t gain, uint8_t conversion); + /*! + \param uint8_t ADC_addr: I2C address for the ADC + \param uint8_t resolution: resolution value for ADC conversion + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param uint8_t gain: gain setting for ADC + MCP3421_GAIN_1 + MCP3421_GAIN_2 + MCP3421_GAIN_4 + MCP3421_GAIN_8 + \param uint8_t conversion: returns the raw value or converted to millivolts + MCP3421_RAW + MCP3421_VOLTS + \return measure in milliVolts or raw + */ + float readADC(uint8_t ADC_addr, uint8_t resolution, uint8_t gain, uint8_t conversion); + }; extern MCP3421 MCP; diff --git a/libraries/SensorGas_PRO/WaspSensorGas_Pro.cpp b/libraries/SensorGas_PRO/WaspSensorGas_Pro.cpp index acd2e06..e6ea65e 100755 --- a/libraries/SensorGas_PRO/WaspSensorGas_Pro.cpp +++ b/libraries/SensorGas_PRO/WaspSensorGas_Pro.cpp @@ -1,7 +1,7 @@ /* * Library for managing the Gas Pro Sensor Board * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.4 + * Version: 3.1 * Design: David Gascón * Implementation: Alejandro Gállego */ @@ -44,32 +44,37 @@ Gas::Gas(int socket) switch (socket) { - case 1: + case SOCKET_1: + case SOCKET_C: sensor_config.power_pin = DIGITAL3; sensor_config.I2C_pin = DIGITAL4; sensor_config.socket = 1; break; - case 2: + case SOCKET_2: sensor_config.power_pin = DIGITAL5; sensor_config.I2C_pin = DIGITAL6; sensor_config.socket = 2; break; - case 3: + case SOCKET_3: + case SOCKET_F: sensor_config.power_pin = DIGITAL7; sensor_config.I2C_pin = DIGITAL8; sensor_config.socket = 3; break; - case 4: + case SOCKET_4: + case SOCKET_A: sensor_config.power_pin = ANA6; sensor_config.I2C_pin = ANA5; sensor_config.socket = 4; break; - case 5: + case SOCKET_5: + case SOCKET_B: sensor_config.power_pin = ANA4; sensor_config.I2C_pin = ANA3; sensor_config.socket = 5; break; - case 6: + case SOCKET_6: + case SOCKET_D: sensor_config.power_pin = ANA2; sensor_config.I2C_pin = ANA1; sensor_config.socket = 6; @@ -84,7 +89,7 @@ Gas::Gas(int socket) sensor_config.sensor_type = UNDEFINED_SENSOR; sensor_config.m_conc = 1; sensor_config.baseline = 0; - sensor_config.val_aux = 1; + sensor_config.aux_baseline = 1; for (int x = 0; x < 7; x++) { @@ -109,7 +114,7 @@ Gas::Gas(int socket) pinMode(ANA3, OUTPUT); pinMode(ANA2, OUTPUT); pinMode(ANA1, OUTPUT); - pinMode(ANA0, OUTPUT); + pinMode(I2C_MAIN_EN, OUTPUT); digitalWrite(DIGITAL3, HIGH); digitalWrite(DIGITAL5, HIGH); @@ -123,7 +128,7 @@ Gas::Gas(int socket) digitalWrite(ANA5, LOW); digitalWrite(ANA3, LOW); digitalWrite(ANA1, LOW); - digitalWrite(ANA0, LOW);*/ + digitalWrite(I2C_MAIN_EN, LOW);*/ pwrGasPRORegister = 0; } @@ -136,7 +141,7 @@ Gas::Gas(int socket, uint8_t sensor_type, int power_pin, int I2C_pin, float m_co sensor_config.power_pin = power_pin; sensor_config.I2C_pin = I2C_pin; sensor_config.m_conc = m_conc; - sensor_config.val_aux = aux_var; + sensor_config.aux_baseline = aux_var; sensor_config.baseline = baseline; pinMode(DIGITAL3, OUTPUT); @@ -188,10 +193,10 @@ float Gas::getBaselineTempComp(float temperature) } if(temperature < 20) - { + { val_low = pgm_read_float(&table_baseline_temp_comp[sensor_config.sensor_type][0]); val_high = pgm_read_float(&table_baseline_temp_comp[sensor_config.sensor_type][1]); - comp_ppm = val_low + (((val_high - val_low) / 40) * (temperature - -20)); + comp_ppm = val_low + (((val_high - val_low) / 40) * (temperature - (-20))); } else if((temperature >= 20) && (temperature < 40)) @@ -207,6 +212,10 @@ float Gas::getBaselineTempComp(float temperature) val_high = pgm_read_float(&table_baseline_temp_comp[sensor_config.sensor_type][3]); comp_ppm = val_low + (((val_high - val_low) / 10) * (temperature - 40)); } + else + { + comp_ppm = 0; + } #if GAS_DEBUG==1 USB.print(F("GP.Baseline compensation: ")); @@ -216,6 +225,8 @@ float Gas::getBaselineTempComp(float temperature) #if GAS_DEBUG==2 USB.print(F("GP.Baseline compensation: ")); USB.print(comp_ppm); + USB.print(F(" | temp: ")); + USB.print(temperature); USB.print(F(" | H_val: ")); USB.print(val_high); USB.print(F(" | L_val: ")); @@ -264,8 +275,12 @@ float Gas::getSensitivityTempComp(float temperature) val_high = pgm_read_float(&table_sensitivity_temp_comp[sensor_config.sensor_type][4]); comp_sens = val_low + (((val_high - val_low) / 10) * (temperature - 40)); } + else + { + comp_sens = 1; + } - comp_sens = 1 - (1 - comp_sens); + comp_sens = 1/comp_sens; #if GAS_DEBUG==1 USB.print(F("GP.Sensitivity compensation: ")); @@ -275,6 +290,8 @@ float Gas::getSensitivityTempComp(float temperature) #if GAS_DEBUG==2 USB.print(F("GP.Sensitivity compensation: ")); USB.print(comp_sens); + USB.print(F(" | temp: ")); + USB.print(temperature); USB.print(F(" | H_val: ")); USB.print(val_high); USB.print(F(" | L_val: ")); @@ -285,7 +302,7 @@ float Gas::getSensitivityTempComp(float temperature) } -//! ONLY FOR 4-ELECTRODE AMPERIOMETRIC BOARD +//! ONLY FOR 4-ELECTRODE AMPERIOMETRIC BOARD (V12) /* Function: This function sets the resistance to an specific digipot * Parameters: electrode: electrode asociated to each digipot * resistor: resistor value to set in Ohms @@ -293,8 +310,53 @@ float Gas::getSensitivityTempComp(float temperature) */ void Gas::setAmplifier(bool electrode, float resistor) { - uint8_t value=0; - value = 128.0 * (resistor / 100000.0); + uint8_t value; + uint8_t aux[2]; + + value=0; + + Wire.readBytes(I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | READ_COMMAND, aux, 2); + //delay(100); + + if(resistor <= 100000) + { + // Connect the resistor + + value = 128.0 * (resistor / 100000.0); + + if (electrode == AUXILIARY_ELECTRODE) + { + aux[0] = aux[1] | 0x04; + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | WRITE_COMMAND | 0x01, aux, 1); + //delay(100); + value = 128 - value; + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_WIPER_0_REG | WRITE_COMMAND, &value, 1); + } + else + { + aux[0] = aux[1] | 0x10; + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | WRITE_COMMAND | 0x01, aux, 1); + // delay(100); + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_WIPER_1_REG | WRITE_COMMAND, &value, 1); + } + } + else + { + + // Disconnect the resistor + if (electrode == AUXILIARY_ELECTRODE) + { + value = aux[1] & 0xFB; + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | WRITE_COMMAND | 0x01, &value, 1); + } + else + { + value = aux[1] & 0xEF; + Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | WRITE_COMMAND | 0x01, &value, 1); + + } + + } #if GAS_DEBUG>0 USB.print(F("GP.Setting R ")); @@ -305,16 +367,6 @@ void Gas::setAmplifier(bool electrode, float resistor) USB.println(value, HEX); #endif - if (electrode == AUXILIARY_ELECTRODE) - { - value = 128 - value; - Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_WIPER_0_REG | WRITE_COMMAND, &value, 1); - } - else - { - Wire.writeBytes( I2C_ADDRESS_GASPRO_MCP4146, VOL_WIPER_1_REG | WRITE_COMMAND, &value, 1); - } - } /* Function: This function gets the resistance from an specific digipot @@ -327,6 +379,20 @@ float Gas::getAmplifier(bool electrode) uint16_t wiper; float resistor; + Wire.readBytes(I2C_ADDRESS_GASPRO_MCP4146, VOL_TCON_REG | READ_COMMAND, aux, 2); + if ((aux[1] == 0xEF) || (aux[1] == 0xFB) || (aux[1] == 0xEB)) + { + #if GAS_DEBUG>0 + USB.print(F("GP.Reading wiper ")); + USB.print(electrode, DEC); + USB.print(F(": ")); + USB.println(F(" external resistors")); + #endif + resistor = 1000000; + return resistor; + } + + //delay(10); if (electrode == AUXILIARY_ELECTRODE) { Wire.readBytes(I2C_ADDRESS_GASPRO_MCP4146, VOL_WIPER_0_REG | READ_COMMAND, aux, 2); @@ -343,34 +409,949 @@ float Gas::getAmplifier(bool electrode) wiper = 128 - wiper; } - resistor = (float(wiper) / 128.0) * 100000.0; + resistor = (float(wiper) / 128.0) * 100000.0; + + #if GAS_DEBUG>0 + USB.print(F("GP.Reading wiper ")); + USB.print(electrode); + USB.print(F(": ")); + USB.print(wiper, DEC); + USB.print(F("/128 || Resistor value: ")); + USB.print(resistor); + USB.println(F(" Ohms")); + #endif + + return resistor; +} + +/* Function: Specific function to read 3 electrode sensors + * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) + * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + * Returns: The concetration value in ppm +*/ +float Gas::read3ElectrodeSensor(uint8_t resolution, float temperature) +{ + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + // Selects amperiometric mode + LMP.setModeReg( LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + delay(100); + + V_conc = 0; + for ( int i = 0; i < 4; i++) + { + // Reads the ADC + aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/4 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + + V_conc /= 4; + + + // Gets the Vref + switch (LMP.getRefSource()) + { + case 0: + V_ref = 3300; + break; + case 1: + V_ref = 2048; + break; + } + + switch (LMP.getInternalZero()) + { + case 0: + V_ref *= 0.2; + break; + case 1: + V_ref *= 0.5; + break; + case 2: + V_ref *= 0.67; + break; + case 3: + V_ref *= 1; + break; + } + + // Gets the Rgain used + r_gain_LMP = LMP.getRgain(); + switch (r_gain_LMP) + { + case 0: + R_gain = 1000000; + break; + case 1: + R_gain = 2750; + break; + case 2: + R_gain = 3500; + break; + case 3: + R_gain = 7000; + break; + case 4: + R_gain = 14000; + break; + case 5: + R_gain = 35000; + break; + case 6: + R_gain = 120000; + break; + case 7: + R_gain = 350000; + break; + default: + R_gain = 0; + } + + + // Disable communication with AFE + digitalWrite(sensor_config.I2C_pin, LOW); + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.print(F(" mV")); + + USB.print(F(" || V_ref: ")); + USB.print(V_ref); + USB.print(F(" mV")); + + USB.print(F(" || R_gain: ")); + USB.print(R_gain, DEC); + USB.println(F(" Ohms")); + #endif + + #if GAS_DEBUG>1 + if(r_gain_LMP != 0) + { + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[r_gain_LMP-1][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[r_gain_LMP-1][1]); + } + else + { + USB.println(F("GP.External resistor: ")); + USB.print(sensor_config.calibration[7][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[7][1]); + } + + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" nA/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" nA")); + #endif + + conc = (V_conc - V_ref); // Vconc(mV) - Vzero(mV) + + conc = (conc / R_gain) * 1000; // V(mV) --> I(uA) + + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + if(r_gain_LMP != 0) + { + conc = ((conc + sensor_config.calibration[r_gain_LMP-1][0]) / (sensor_config.calibration[r_gain_LMP-1][1])); // Adjust resistor + } + else + { + conc = ((conc + sensor_config.calibration[7][0]) / (sensor_config.calibration[7][1])); // Adjust resistor + } + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + #if GAS_DEBUG>0 + USB.print(F("GP.I: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + conc -= (sensor_config.baseline / 1000); // Subtracts baseline current + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + if ((sensor_config.sensor_type == CL2_SS) || + (sensor_config.sensor_type == NO2_SS_CLE) || + (sensor_config.sensor_type == O2_SS)) + { + conc *= -1; + } + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + conc *= getSensitivityTempComp(temperature); // Output current temperature compensation + + #if I_DEBUG>0 + USB.print(getSensitivityTempComp(temperature)); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + conc = (conc * 1000) / sensor_config.m_conc; // I(nA) --> concentración(ppm) + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + conc -= getBaselineTempComp(temperature); // Baseline temperature compensation + + #if I_DEBUG>0 + USB.print(getBaselineTempComp(temperature)); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + if (conc < 0) + { + conc = 0; + } + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(ppm2ugm3(conc)); + USB.print(F("#")); + USB.print(temperature); + USB.print(F("\r\n")); + #endif + + return conc; + +} + +/* Function: Specific function to read pellistor sensors + * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) + * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + * Returns: The concetration value in %/LEL +*/ +float Gas::readPellistorSensor(uint8_t resolution, float temperature) +{ + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + + V_conc = 0; + for ( int i = 0; i < 4; i++) + { + // Reads the ADC + aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/4 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + + // Disable communication + digitalWrite(sensor_config.I2C_pin, LOW); + + V_conc /= -4; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + + #if GAS_DEBUG>1 + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" mV/% || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" mV")); + #endif + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + V_conc = (V_conc - sensor_config.calibration[0][0]) / sensor_config.calibration[0][1]; + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + + V_conc -= sensor_config.baseline; // Vconc(mV) - Voffset(mV) sensor + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc baseline compensated: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + V_conc -= getBaselineTempComp(temperature); // Baseline temperature compensation + #if I_DEBUG>0 + USB.print(getBaselineTempComp(temperature)); + USB.print(F("#")); + USB.print(V_conc); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc offset compensated: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + V_conc *= getSensitivityTempComp(temperature); // Output current temperature compensation + #if I_DEBUG>0 + USB.print(getSensitivityTempComp(temperature)); + USB.print(F("#")); + USB.print(V_conc); + USB.print(F("#")); + #endif + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc sens compensated: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + conc = V_conc / (sensor_config.m_conc); // conc(mV) --> concentración(% LEL) + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.conc: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + + if (conc < 0) + { + conc = 0; + } + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(temperature); + USB.print(F("\r\n")); + #endif + return conc; + +} + +/* Function: Specific function to read NDIR sensors + * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) + * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + * Returns: The concetration value in ppm +*/ +float Gas::readNDIR(uint8_t resolution, float temperature) +{ + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + + V_conc = 0; + for ( int i = 0; i < 4; i++) + { + // Reads the ADC + aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/4 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + + // Disable communication + digitalWrite(sensor_config.I2C_pin, LOW); + + V_conc /= 4; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.println(F(" mV")); + #endif + + #if GAS_DEBUG>1 + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" mV/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" mV")); + #endif + + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + // NDIR sensor from Solidsense doesn't need temperature compensation + V_conc = (V_conc - sensor_config.calibration[0][0]) / sensor_config.calibration[0][1]; + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + + V_conc -= sensor_config.baseline; // Vconc(mV) - Voffset(mV) sensor + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + #endif + + conc = V_conc * sensor_config.m_conc; // conc(mV) --> concentración(% LEL) + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + if (conc < 0) + { + conc = 0; + } + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(temperature); + USB.print(F("\r\n")); + #endif + + return conc; +} + +// For old O3 sensors +/* Function: Specific function to read O3 sensors (v12 sensors) + * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) + * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + * Returns: The concetration value in ppm +*/ +float Gas::read4ElectrodeSensorv100(uint8_t resolution, float temperature) +{ + + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + + float R_gain; + + // Selects amperiometric mode + LMP.setModeReg(LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + + // Measuring + conc = 0; + conc_aux = 0; + + /// Read WE + #if GAS_DEBUG>0 + USB.println(F("GP.Reading working electrode")); + #endif + + aux_resistor = getAmplifier(AUXILIARY_ELECTRODE); + setAmplifier(AUXILIARY_ELECTRODE, 0); + + delay(1000); + + V_conc = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC")); + #endif + for ( int i = 0; i < 8; i++) + { + // Reads the ADC + delay(100); + aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); + #if GAS_DEBUG>1 + USB.print(F("Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + V_conc /=8; + + setAmplifier(AUXILIARY_ELECTRODE, aux_resistor); + R_gain = getAmplifier(WORKING_ELECTRODE); + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.print(F(" mV || R_gain: ")); + USB.print(R_gain, DEC); + USB.println(F(" Ohms")); + #endif + + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[0][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[0][1]); + + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" nA/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" nA")); + #endif + + conc = (V_conc / (R_gain)) * -1000; // V(mV) --> I(uA) + conc = ((conc + sensor_config.calibration[0][0]) / (sensor_config.calibration[0][1]));// Adjust resistor + + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + /// Read auxiliary electrode + #if GAS_DEBUG>0 + USB.println(F("GP.Reading auxiliary electrode")); + #endif + aux_resistor = getAmplifier(WORKING_ELECTRODE); + setAmplifier(WORKING_ELECTRODE, 0); + + delay(2000); + + V_conc = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC")); + #endif + for ( int i = 0; i < 8; i++) + { + // Reads the ADC + delay(100); + + aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + + V_conc /=8; + + setAmplifier(WORKING_ELECTRODE, aux_resistor); + R_gain = getAmplifier(AUXILIARY_ELECTRODE); + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc_aux: ")); + USB.print(V_conc); + USB.print(F(" mV || R_gain: ")); + USB.print(R_gain, DEC); + USB.println(F(" Ohms")); + #endif + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[1][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[1][1]); + #endif + + conc_aux = (V_conc / (R_gain)) * 1000;// V(mV) --> I(uA) + conc_aux = ((conc_aux + sensor_config.calibration[1][0]) / (sensor_config.calibration[1][1]));// Adjust resistor + + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + USB.print(conc_aux); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.Iwe: ")); + USB.print(conc); + USB.println(F(" uA")); + USB.print(F("GP.Iae: ")); + USB.print(conc_aux); + USB.println(F(" uA")); + #endif + + /// Substracts offset currents + conc -= (sensor_config.baseline / 1000); // Subtracts baseline current + conc_aux -= (sensor_config.aux_baseline / 1000); // Subtracts auxiliary baseline current + #if GAS_DEBUG>0 + USB.print(F("GP.Iwe without offset: ")); + USB.print(conc); + USB.println(F(" uA")); + USB.print(F("GP.Iae without offset: ")); + USB.print(conc_aux); + USB.println(F(" uA")); + #endif + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(conc_aux); + USB.print(F("#")); + #endif + + /// Compensates WE with AE + conc -= conc_aux; + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.I: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + conc *= getSensitivityTempComp(temperature); // Output current temperature compensation + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + conc = (conc * 1000) / sensor_config.m_conc; // I(uA) --> concentración(ppm) + + #if GAS_DEBUG>0 + USB.print(F("GP.conc: ")); + USB.print(conc); + USB.println(F(" ppm")); + #endif + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + if (conc < 0) + { + conc = 0; + } + + // Disable communication with AFE + digitalWrite(sensor_config.I2C_pin, LOW); + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(ppm2ugm3(conc)); + USB.print(F("#")); + USB.print(temperature); + USB.print(F("\r\n")); + #endif + + return conc; + +} + +// For new 4 electrode AFE boards +/* Function: Specific function to read 4 electrode sensors + * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) + * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + * NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. + * Only for O3 sensor, for other sensors use 0.0 value + * Returns: The concetration value in ppm +*/ +float Gas::read4ElectrodeSensorv301(uint8_t resolution, float temperature, float NO2_conc) +{ + + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + + // Selects amperiometric mode + LMP.setModeReg(LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + + // Measuring + conc = 0; + conc_aux = 0; + + ///**************************************************** + /// Read WE + #if GAS_DEBUG>0 + USB.println(F("GP.Reading working electrode")); + #endif + + V_conc = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC we")); + #endif + for ( int i = 0; i < 8; i++) + { + // Reads the ADC + aux_val = MCP.readADC(I2C_ADDRESS_GASPRO_MCP3421_A1, resolution, MCP3421_GAIN_1, MCP3421_VOLTS); + #if GAS_DEBUG>1 + USB.print(F("Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + V_conc /= -8; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.print(F(" mV || R_gain: ")); + USB.print(110000, DEC); + USB.println(F(" Ohms")); + #endif + + + conc = (V_conc / (110000)) * 1000; // V(mV) --> I(uA) + // Adjust electronic offset and gain for WE + conc = ((conc + sensor_config.calibration[0][0]) / (sensor_config.calibration[0][1]));// Adjust resistor + #if GAS_DEBUG>0 + USB.print(F("GP.Iwe: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[0][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[0][1]); + + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" nA/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" nA")); + #endif + + // Substract WE offset current + conc -= (sensor_config.baseline / 1000); // Subtracts baseline current + + #if GAS_DEBUG>0 + USB.print(F("GP.Iwe without offset: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + ///**************************************************** + /// Read AE + #if GAS_DEBUG>0 + USB.println(F("GP.Reading auxiliary electrode")); + #endif + + V_conc_aux = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC ae")); + #endif + for ( int i = 0; i < 8; i++) + { + //Reads the ADC + aux_val = MCP.readADC(I2C_ADDRESS_GASPRO_MCP3421_A2, resolution, MCP3421_GAIN_1, MCP3421_VOLTS); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc_aux += aux_val; + } + + V_conc_aux /= -8; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc_aux: ")); + USB.print(V_conc_aux); + USB.print(F(" mV || R_gain: ")); + USB.print(110000, DEC); + USB.println(F(" Ohms")); + #endif + + conc_aux = (V_conc_aux / (110000)) * 1000;// V(mV) --> I(uA) + // Adjust electronic offset and gain for AE + conc_aux = ((conc_aux + sensor_config.calibration[1][0]) / (sensor_config.calibration[1][1]));// Adjust resistor + #if I_DEBUG>0 + USB.print(V_conc_aux); + USB.print(F("#")); + USB.print(conc_aux); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.Iae: ")); + USB.print(conc_aux); + USB.println(F(" uA")); + #endif + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[0][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[0][1]); + + USB.print(F("GP.baseline: ")); + USB.print(sensor_config.aux_baseline); + USB.println(F(" nA")); + #endif + + // Substracts AE offset current + conc_aux -= (sensor_config.aux_baseline / 1000); // Subtracts auxiliary baseline current + #if GAS_DEBUG>0 + USB.print(F("GP.Iae without offset: ")); + USB.print(conc_aux); + USB.println(F(" uA")); + #endif + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(conc_aux); + USB.print(F("#")); + #endif + + ///**************************************************** + /// Compensates WE with AE + conc -= conc_aux; + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.I: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + conc *= getSensitivityTempComp(temperature); // Output current temperature compensation + #if I_DEBUG>0 + USB.print(getSensitivityTempComp(temperature)); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + if(sensor_config.sensor_type == O3_AS) + { + conc = conc - (sensor_config.OX_NO2_sens * NO2_conc / 1000); + } + #if GAS_DEBUG>0 + USB.print(F("GP.I-NO2 (only OX): ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + #if I_DEBUG>0 + USB.print(sensor_config.OX_NO2_sens * NO2_conc / 1000); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + conc = (conc * 1000) / sensor_config.m_conc; // I(uA) --> concentración(ppm) + #if GAS_DEBUG>0 - USB.print(F("GP.Reading wiper ")); - USB.print(electrode); - USB.print(F(": ")); - USB.print(wiper, DEC); - USB.print(F("/128 || Resistor value: ")); - USB.print(resistor); - USB.println(F(" Ohms")); - #endif + USB.print(F("GP.conc: ")); + USB.print(conc); + USB.println(F(" ppm")); + #endif + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + if (conc < 0) + { + conc = 0; + } + + // Disable communication with AFE + digitalWrite(sensor_config.I2C_pin, LOW); + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + USB.print(ppm2ugm3(conc)); + USB.print(F("#")); + USB.print(temperature); + USB.print(F("\r\n")); + #endif + + return conc; - return resistor; } //! MISCELANEUS /* Function: This function reads the sensor information from EEPROM - * Return: Nothing + * Return: '1' if checksum is correct, '0' if not */ -void Gas::readSensorInfo() +uint8_t Gas::readSensorInfo() { - uint8_t buffer[4]; + uint8_t buffer[4]; + uint8_t EEPROM_checksum, generated_checksum; // First read the board version and sensor type // This parameters are common for all sensors - Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, VER_BOARD_REG, &sensor_config.sensor_type, 1); + Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, VER_BOARD_REG, &sensor_config.AFE_ver, 1); Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, SENSOR_TYPE_REG, &sensor_config.sensor_type, 1); + // Then read the calibration values according the sensor type // Each kind of sensor has different calibration patterns @@ -424,10 +1405,23 @@ void Gas::readSensorInfo() Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, CAL_REG + (x * 8) + 4, buffer, 4); memcpy(&sensor_config.calibration[x][1], buffer, 4); } + + if (sensor_config.AFE_ver >= 3) + { + Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, CAL_REG + 56, buffer, 4); + memcpy(&sensor_config.calibration[7][0], buffer, 4); + Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, CAL_REG + 60, buffer, 4); + memcpy(&sensor_config.calibration[7][1], buffer, 4); + } + break; // 4 electrodes PCB case O3_AS: + case NO2_AS: + case NO_AS: + case SO2_AS: + case CO_AS: case CALIBRATION_4E: Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, SENSITIVITY_REG, buffer, 4); @@ -435,7 +1429,7 @@ void Gas::readSensorInfo() Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, OFFSET_REG, buffer, 4); memcpy(&sensor_config.baseline, buffer, 4); Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, SENS_AE_REG, buffer, 4); - memcpy(&sensor_config.val_aux, buffer, 4); + memcpy(&sensor_config.OX_NO2_sens, buffer, 4); // Reads calibration values for working electrode Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, CAL_WE_REG, buffer, 4); @@ -449,8 +1443,47 @@ void Gas::readSensorInfo() Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, CAL_AE_REG + 4, buffer, 4); memcpy(&sensor_config.calibration[1][1], buffer, 4); + sensor_config.aux_baseline = 0; + switch (sensor_config.AFE_ver) + { + case 3: + Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, AE_OFFSET_REG, buffer, 4); + memcpy(&sensor_config.aux_baseline, buffer, 4); + break; + } + break; } + + + + if (sensor_config.AFE_ver >= 3) + { + Wire.readBytes(I2C_ADDRESS_GASPRO_E2PROM, SENSOR_CHECKSUM, &EEPROM_checksum, 1); + memcpy(buffer, &sensor_config.m_conc, 4); + + generated_checksum = sensor_config.AFE_ver ^ + sensor_config.sensor_type ^ + buffer[0] ^ + buffer[1] ^ + buffer[2] ^ + buffer[3]; + + if (EEPROM_checksum != generated_checksum) + { + #if GAS_DEBUG>0 + USB.println(F("GP.Error with EEPROM parameters")); + USB.print(F("GP.Generated 0x")); + USB.printHex(generated_checksum); + USB.print(F("; extracted 0x")); + USB.printHex(EEPROM_checksum); + #endif + return 0; + } + } + + return 1; + } @@ -469,6 +1502,7 @@ int8_t Gas::ON() /* Function: This function powers on the sensor, configures the AFE and selects the gain * Parameters: R_gain: resistor value for transimpendance amplifier * Returns: 1 if OK + * 0 if error with EEPROM memory * -1 no communication with LMP91000 */ int8_t Gas::ON(float R_gain) @@ -477,8 +1511,8 @@ int8_t Gas::ON(float R_gain) uint8_t mask; #ifndef CALIBRATION_MODE - pinMode(ANA0, OUTPUT); - digitalWrite(ANA0, HIGH); + pinMode(I2C_MAIN_EN, OUTPUT); + digitalWrite(I2C_MAIN_EN, HIGH); if ((pwrGasPRORegister == 0) || ((WaspRegister & REG_3V3) == 0)) { @@ -498,33 +1532,19 @@ int8_t Gas::ON(float R_gain) //Enable communication with the AFE digitalWrite(sensor_config.I2C_pin, HIGH); delay(1); - readSensorInfo(); + answer = readSensorInfo(); + if (answer == 0) + { + // Clear bit in pwrGasPRORegister + mask = ~(1 << sensor_config.socket); + pwrGasPRORegister &= mask; + + return 0; + + } #if GAS_DEBUG>1 showSensorInfo(); - /*USB.println(F("************ Sensor data ************")); - USB.print(F("Sensor type: ")); - USB.println(sensor_config.sensor_type, DEC); - USB.print(F("power_pin: ")); - USB.println(sensor_config.power_pin, DEC); - USB.print(F("I2C_pin: ")); - USB.println(sensor_config.I2C_pin, DEC); - USB.print(F("m_conc: ")); - USB.println(sensor_config.m_conc); - USB.print(F("baseline: ")); - USB.println(sensor_config.baseline); - USB.print(F("val_aux: ")); - USB.println(sensor_config.val_aux); - - USB.println(F("Calibration table")); - for (int x = 0; x < 7; x++) - { - USB.print(x, DEC); - USB.print(F(": ")); - USB.print(sensor_config.calibration[x][0]); - USB.print(F(" ; ")); - USB.println(sensor_config.calibration[x][1]); - }*/ #endif delay(1000); @@ -595,13 +1615,13 @@ uint8_t Gas::OFF(uint8_t enable_FET) USB.println(F("GP.3V3 to OFF")); #endif PWR.setSensorPower(SENS_3V3, SENS_OFF); - pinMode(ANA0, OUTPUT); - digitalWrite(ANA0, LOW); + pinMode(I2C_MAIN_EN, OUTPUT); + digitalWrite(I2C_MAIN_EN, LOW); } else if (pwrGasPRORegister == 0x01) { - pinMode(ANA0, OUTPUT); - digitalWrite(ANA0, LOW); + pinMode(I2C_MAIN_EN, OUTPUT); + digitalWrite(I2C_MAIN_EN, LOW); } #endif @@ -630,7 +1650,10 @@ int8_t Gas::configureAFE(float R_gain) float gain_4E; // NDIR and pellistor sensors don't need to configure the AFE - if ((sensor_config.sensor_type == LEL_AS) || (sensor_config.sensor_type == NDIR_CO2_SS)) + if ((sensor_config.sensor_type == LEL_AS) || + (sensor_config.sensor_type == NDIR_CO2_SS) || + (sensor_config.sensor_type == CALIBRATION_NDIR) || + (sensor_config.sensor_type == CALIBRATION_PEL)) { digitalWrite(sensor_config.I2C_pin, LOW); return 1; @@ -658,7 +1681,11 @@ int8_t Gas::configureAFE(float R_gain) // No gain selected if (R_gain == -1000) { - if (sensor_config.sensor_type == O3_AS) // Basic gain for O3 sensor + if ((sensor_config.sensor_type == O3_AS) || // Basic gain for O3 sensor + (sensor_config.sensor_type == NO2_AS) || + (sensor_config.sensor_type == NO_AS) || + (sensor_config.sensor_type == SO2_AS) || + (sensor_config.sensor_type == CO_AS)) { gain_4E = MCP_GAIN_2; } @@ -671,7 +1698,12 @@ int8_t Gas::configureAFE(float R_gain) gain_3E = LMP91000_TIAC_REG_REF_R_GAIN_35K; } } - else if ((R_gain > 7) && (sensor_config.sensor_type != O3_AS)) // Incorrect gain for 3 electrode sensors + else if ( (R_gain > 7) && + (sensor_config.sensor_type != O3_AS) && + (sensor_config.sensor_type != NO2_AS) && + (sensor_config.sensor_type != NO_AS) && + (sensor_config.sensor_type != SO2_AS) && + (sensor_config.sensor_type != CO_AS)) // Incorrect gain for 3 electrode sensors { gain_3E = LMP91000_TIAC_REG_REF_R_GAIN_35K; } @@ -771,10 +1803,6 @@ int8_t Gas::configureAFE(float R_gain) LMP91000_REFC_REG_REF_INT_Z_50, LMP91000_REFC_REG_REF_BIAS_PERC_18, LMP91000_REFC_REG_REF_POLARITY_NEGATIVE); - /* LMP.setRefConReg( LMP91000_REFC_REG_REF_SOURCE_EXTERNAL_REF, - LMP91000_REFC_REG_REF_INT_Z_67, - LMP91000_REFC_REG_REF_BIAS_PERC_24, - LMP91000_REFC_REG_REF_POLARITY_NEGATIVE);*/ break; case PH3_SS: @@ -799,8 +1827,63 @@ int8_t Gas::configureAFE(float R_gain) LMP91000_REFC_REG_REF_INT_Z_50, LMP91000_REFC_REG_REF_BIAS_PERC_0, LMP91000_REFC_REG_REF_POLARITY_POSITIVE); - setAmplifier(WORKING_ELECTRODE, gain_4E); - setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + if (sensor_config. AFE_ver != 3) + { + setAmplifier(WORKING_ELECTRODE, gain_4E); + setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + } + break; + + case NO2_AS: + LMP.setTIAConReg(LMP91000_TIAC_REG_REF_R_GAIN_EXT, LMP91000_TIAC_REG_REF_R_LOAD_33R); + LMP.setRefConReg( LMP91000_REFC_REG_REF_SOURCE_EXTERNAL_REF, + LMP91000_REFC_REG_REF_INT_Z_50, + LMP91000_REFC_REG_REF_BIAS_PERC_0, + LMP91000_REFC_REG_REF_POLARITY_POSITIVE); + if (sensor_config. AFE_ver != 3) + { + setAmplifier(WORKING_ELECTRODE, gain_4E); + setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + } + break; + + case NO_AS: + LMP.setTIAConReg(LMP91000_TIAC_REG_REF_R_GAIN_EXT, LMP91000_TIAC_REG_REF_R_LOAD_33R); + LMP.setRefConReg( LMP91000_REFC_REG_REF_SOURCE_EXTERNAL_REF, + LMP91000_REFC_REG_REF_INT_Z_50, + LMP91000_REFC_REG_REF_BIAS_PERC_10, + LMP91000_REFC_REG_REF_POLARITY_POSITIVE); + if (sensor_config. AFE_ver != 3) + { + setAmplifier(WORKING_ELECTRODE, gain_4E); + setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + } + break; + + case SO2_AS: + LMP.setTIAConReg(LMP91000_TIAC_REG_REF_R_GAIN_EXT, LMP91000_TIAC_REG_REF_R_LOAD_33R); + LMP.setRefConReg( LMP91000_REFC_REG_REF_SOURCE_EXTERNAL_REF, + LMP91000_REFC_REG_REF_INT_Z_50, + LMP91000_REFC_REG_REF_BIAS_PERC_0, + LMP91000_REFC_REG_REF_POLARITY_POSITIVE); + if (sensor_config. AFE_ver != 3) + { + setAmplifier(WORKING_ELECTRODE, gain_4E); + setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + } + break; + + case CO_AS: + LMP.setTIAConReg(LMP91000_TIAC_REG_REF_R_GAIN_EXT, LMP91000_TIAC_REG_REF_R_LOAD_33R); + LMP.setRefConReg( LMP91000_REFC_REG_REF_SOURCE_EXTERNAL_REF, + LMP91000_REFC_REG_REF_INT_Z_50, + LMP91000_REFC_REG_REF_BIAS_PERC_0, + LMP91000_REFC_REG_REF_POLARITY_POSITIVE); + if (sensor_config. AFE_ver != 3) + { + setAmplifier(WORKING_ELECTRODE, gain_4E); + setAmplifier(AUXILIARY_ELECTRODE, gain_4E); + } break; case CALIBRATION_3E: @@ -858,9 +1941,13 @@ float Gas::getTemp() float Gas::getTemp(bool sensor) { uint8_t last_mode; - float temp; + float temp = -1000; - if (sensor == 0) + if ((sensor == 0) && + (sensor_config.sensor_type != LEL_AS) && + (sensor_config.sensor_type != O3_AS) && + (sensor_config.sensor_type != NO2_AS) && + (sensor_config.sensor_type != NDIR_CO2_SS)) { //Enable communication with the AFE digitalWrite(sensor_config.I2C_pin, HIGH); @@ -955,34 +2042,34 @@ float Gas::getConc(uint8_t resolution) float BME280_temp; BME280_temp = BME.getTemperature(BME280_OVERSAMP_1X, 0); - return getConc(resolution, BME280_temp, COMPENSATED); + return getConc(resolution, BME280_temp, 0); } -/* Function: This function reads concentration value (used to select an specific eletrode in 4 electrode sensors) +/* Function: This function reads concentration value (used only with O3 sensor) * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) - * electrode: electrode to read (WORKING_ELECTRODE or AUXILIARY_ELECTRODE) + * NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. Only for O3 sensor * Returns: The concetration value in ppm / %LEL, -1000 if error. */ -float Gas::getConc(uint8_t resolution, uint8_t electrode) +float Gas::getConc(uint8_t resolution, float NO2_conc) { float BME280_temp; BME280_temp = BME.getTemperature(BME280_OVERSAMP_1X, 0); - return getConc(resolution, BME280_temp, electrode); + return getConc(resolution, BME280_temp, NO2_conc); } /* Function: This function reads concentration value (base function) * Parameters: resolution: resolution value for ADC (RES_12_BIT, RES_14_BIT, RES_16_BIT or RES_18_BIT) * temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) - * electrode: electrode to read (WORKING_ELECTRODE or AUXILIARY_ELECTRODE) + * NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. Only for O3 sensor * Returns: The concetration value in ppm / %LEL * -1 if the sensors is not initializated * -1000 if error. */ -float Gas::getConc(uint8_t resolution, float temperature, uint8_t electrode) +float Gas::getConc(uint8_t resolution, float temperature, float NO2_conc) { - float V_conc = 0; + float V_conc = 0, V_conc_aux = 0; float conc=0, conc_aux=0; float aux_val; float aux_resistor; @@ -1034,155 +2121,14 @@ float Gas::getConc(uint8_t resolution, float temperature, uint8_t electrode) USB.print(F("; t: ")); USB.println(millis() - sensor_config.tempo, DEC); #endif - // Selects amperiometric mode - LMP.setModeReg( LMP91000_MODEC_REG_FET_NOT_SHORTED, - LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); - delay(100); - - V_conc = 0; - for ( int i = 0; i < 4; i++) - { - // Reads the ADC - aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); - - #if GAS_DEBUG>1 - USB.print(F("GP.Measure ")); - USB.print(i+1, DEC); - USB.print(F("/4 from ADC: ")); - USB.print(aux_val); - USB.println(F(" mV")); - #endif - - V_conc += aux_val; - } - - V_conc /=4; - - - // Gets the Vref - switch (LMP.getRefSource()) - { - case 0: - V_ref = 3300; - break; - case 1: - V_ref = 2048; - break; - } - - switch (LMP.getInternalZero()) - { - case 0: - V_ref *= 0.2; - break; - case 1: - V_ref *= 0.5; - break; - case 2: - V_ref *= 0.67; - break; - case 3: - V_ref *= 1; - break; - } - - // Gets the Rgain used - r_gain_LMP = LMP.getRgain(); - switch (r_gain_LMP) - { - case 1: - R_gain = 2750; - break; - case 2: - R_gain = 3500; - break; - case 3: - R_gain = 7000; - break; - case 4: - R_gain = 14000; - break; - case 5: - R_gain = 35000; - break; - case 6: - R_gain = 120000; - break; - case 7: - R_gain = 350000; - break; - default: - R_gain = 0; - } - - - // Disable communication with AFE - digitalWrite(sensor_config.I2C_pin, LOW); - - #if GAS_DEBUG>0 - USB.print(F("GP.V_conc: ")); - USB.print(V_conc); - USB.print(F(" mV")); - - USB.print(F(" || V_ref: ")); - USB.print(V_ref); - USB.print(F(" mV")); - - USB.print(F(" || R_gain: ")); - USB.print(R_gain, DEC); - USB.println(F(" Ohms")); - #endif - - #if GAS_DEBUG>1 - USB.print(F("GP.Compensation values: ")); - USB.print(sensor_config.calibration[r_gain_LMP-1][0]); - USB.print(F("; ")); - USB.println(sensor_config.calibration[r_gain_LMP-1][1]); - USB.print(F("GP.m_conc: ")); - USB.print(sensor_config.m_conc); - USB.print(F(" nA/ppm || baseline: ")); - USB.print(sensor_config.baseline); - USB.println(F(" nA")); - #endif - - conc = (V_conc - V_ref); // Vconc(mV) - Vzero(mV) - - conc = (conc / R_gain) * 1000; // V(mV) --> I(uA) - - conc = ((conc + sensor_config.calibration[r_gain_LMP-1][0]) / (sensor_config.calibration[r_gain_LMP-1][1])); // Adjust resistor - - - #if GAS_DEBUG>0 - USB.print(F("GP.I: ")); - USB.print(conc); - USB.println(F(" uA")); - #endif - if ((sensor_config.sensor_type == CL2_SS) || - (sensor_config.sensor_type == NO2_SS_CLE) || - (sensor_config.sensor_type == O2_SS)) - { - conc *= -1; - } - - conc -= (sensor_config.baseline / 1000); // Subtracts baseline current - - conc *= getSensitivityTempComp(temperature); // Output current temperature compensation + conc = read3ElectrodeSensor( resolution, temperature); - conc = (conc * 1000) / sensor_config.m_conc; // I(nA) --> concentración(ppm) - - conc -= getBaselineTempComp(temperature); // Baseline temperature compensation - - if (conc < 0) - { - conc = 0; - } - break; /*************************************** - * PELLISTOR BOARD * + * PELLISTOR BOARD * ***************************************/ case LEL_AS: case CALIBRATION_PEL: @@ -1191,331 +2137,68 @@ float Gas::getConc(uint8_t resolution, float temperature, uint8_t electrode) USB.print(F("GP.Reading pellistor sensor; t:")); USB.println(millis() - sensor_config.tempo, DEC); #endif - - V_conc = 0; - for ( int i = 0; i < 4; i++) - { - // Reads the ADC - aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); - - #if GAS_DEBUG>1 - USB.print(F("GP.Measure ")); - USB.print(i+1, DEC); - USB.print(F("/4 from ADC: ")); - USB.print(aux_val); - USB.println(F(" mV")); - #endif - - V_conc += aux_val; - } - - // Disable communication - digitalWrite(sensor_config.I2C_pin, LOW); - - V_conc /= -4; - - #if GAS_DEBUG>0 - USB.print(F("GP.V_conc: ")); - USB.print(V_conc); - USB.println(F(" mV")); - #endif - - #if GAS_DEBUG>1 - USB.print(F("GP.m_conc: ")); - USB.print(sensor_config.m_conc); - USB.print(F(" mV/% || baseline: ")); - USB.print(sensor_config.baseline); - USB.println(F(" mV")); - #endif - - V_conc = (V_conc - sensor_config.calibration[0][0]) / sensor_config.calibration[0][1]; - - V_conc -= sensor_config.baseline; // Vconc(mV) - Voffset(mV) sensor - - conc -= getBaselineTempComp(temperature); // Baseline temperature compensation - - V_conc *= getSensitivityTempComp(temperature); // Output current temperature compensation - - conc = V_conc / (sensor_config.m_conc); // conc(mV) --> concentración(% LEL) - - if (conc < 0) - { - conc = 0; - } - break; - - case NDIR_CO2_SS: - case CALIBRATION_NDIR: - - #if GAS_DEBUG>0 - USB.print(F("GP.Reading NDIR sensor; t: ")); - USB.println(millis() - sensor_config.tempo, DEC); - #endif - - V_conc = 0; - for ( int i = 0; i < 4; i++) - { - // Reads the ADC - aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); - - #if GAS_DEBUG>1 - USB.print(F("GP.Measure ")); - USB.print(i+1, DEC); - USB.print(F("/4 from ADC: ")); - USB.print(aux_val); - USB.println(F(" mV")); - #endif - - V_conc += aux_val; - } - - // Disable communication - digitalWrite(sensor_config.I2C_pin, LOW); - - V_conc /= 4; - - #if GAS_DEBUG>0 - USB.print(F("GP.V_conc: ")); - USB.print(V_conc); - USB.println(F(" mV")); - #endif - - #if GAS_DEBUG>1 - USB.print(F("GP.m_conc: ")); - USB.print(sensor_config.m_conc); - USB.print(F(" mV/ppm || baseline: ")); - USB.print(sensor_config.baseline); - USB.println(F(" mV")); - #endif - - // NDIR sensor from Solidsense doesn't need temperature compensation - - V_conc = (V_conc - sensor_config.calibration[0][0]) / sensor_config.calibration[0][1]; + conc = readPellistorSensor(resolution, temperature); + + break; + + /*************************************** + * NDIR BOARD * + ***************************************/ + case NDIR_CO2_SS: + case CALIBRATION_NDIR: + + #if GAS_DEBUG>0 + USB.print(F("GP.Reading NDIR sensor; t: ")); + USB.println(millis() - sensor_config.tempo, DEC); + #endif + conc = readNDIR(resolution, temperature); - V_conc -= sensor_config.baseline; // Vconc(mV) - Voffset(mV) sensor - - conc = V_conc * sensor_config.m_conc; // conc(mV) --> concentración(% LEL) - - if (conc < 0) - { - conc = 0; - } break; - /*************************************** - * 4-ELECTRODE AMPERIOMETRIC BOARD * - ***************************************/ - case O3_AS: - case CALIBRATION_4E: - #if GAS_DEBUG>0 - USB.print(F("GP.Reading 4E sensor; t: ")); - USB.println(millis() - sensor_config.tempo, DEC); - #endif - // Selects amperiometric mode - LMP.setModeReg( LMP91000_MODEC_REG_FET_NOT_SHORTED, - LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); - - // Measuring - conc = 0; - conc_aux = 0; - - if ((electrode == WORKING_ELECTRODE) || (electrode == COMPENSATED)) - { - #if GAS_DEBUG>0 - USB.println(F("GP.Reading working electrode")); - #endif - - aux_resistor = getAmplifier(AUXILIARY_ELECTRODE); - setAmplifier(AUXILIARY_ELECTRODE, 0); - - V_conc = 0; - for ( int i = 0; i < 8; i++) - { - // Reads the ADC - - delay(100); - digitalWrite(sensor_config.I2C_pin, HIGH); - - aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); - - #if GAS_DEBUG>1 - USB.print(F("Measure ")); - USB.print(i+1, DEC); - USB.print(F("/8 from ADC: ")); - USB.print(aux_val); - USB.println(F(" mV")); - #endif - - V_conc += aux_val; - } - - V_conc /=8; - - setAmplifier(AUXILIARY_ELECTRODE, aux_resistor); - - R_gain = getAmplifier(WORKING_ELECTRODE); - - #if GAS_DEBUG>0 - USB.print(F("GP.V_conc: ")); - USB.print(V_conc); - USB.print(F(" mV || R_gain: ")); - USB.print(R_gain, DEC); - USB.println(F(" Ohms")); - #endif - - #if GAS_DEBUG>1 - USB.print(F("GP.Compensation values: ")); - USB.print(sensor_config.calibration[0][0]); - USB.print(F("; ")); - USB.println(sensor_config.calibration[0][1]); - - USB.print(F("GP.m_conc: ")); - USB.print(sensor_config.m_conc); - USB.print(F(" nA/ppm || baseline: ")); - USB.print(sensor_config.baseline); - USB.println(F(" nA")); - #endif - - - conc = (V_conc / (R_gain)) * 1000; // V(mV) --> I(uA) - - conc = ((conc + sensor_config.calibration[0][0]) / (sensor_config.calibration[0][1])); - - conc *= -1; - - #if GAS_DEBUG>0 - USB.print(F("GP.Iwe: ")); - USB.print(conc); - USB.println(F(" uA")); - #endif - - conc -= (sensor_config.baseline / 1000); // Subtracts baseline current - - conc -= getBaselineTempComp(temperature); // Baseline temperature compensation - - //conc *= getSensitivityTempComp(temperature); // Output current temperature compensation - - conc = (conc * 1000) / sensor_config.m_conc; // I(uA) --> concentración(ppm) - - #if GAS_DEBUG>0 - USB.print(F("GP.conc: ")); - USB.print(conc); - USB.println(F(" ppm")); - #endif - - if (conc < 0) - { - conc = 0; - } - - } - - if ((electrode == AUXILIARY_ELECTRODE) || (electrode == COMPENSATED)) - { - #if GAS_DEBUG>0 - USB.println(F("GP.Reading auxiliary electrode")); - #endif - - aux_resistor = getAmplifier(WORKING_ELECTRODE); - setAmplifier(WORKING_ELECTRODE, 0); - - V_conc = 0; - for ( int i = 0; i < 8; i++) - { - // Reads the ADC - delay(100); - digitalWrite(sensor_config.I2C_pin, HIGH); - - aux_val = (MCP.readADC(resolution, MCP3421_GAIN_1, MCP3421_VOLTS)); - - #if GAS_DEBUG>1 - USB.print(F("GP.Measure ")); - USB.print(i+1, DEC); - USB.print(F("/8 from ADC: ")); - USB.print(aux_val); - USB.println(F(" mV")); - #endif - - V_conc += aux_val; - } - - V_conc /=8; - - setAmplifier(WORKING_ELECTRODE, aux_resistor); - - R_gain = getAmplifier(AUXILIARY_ELECTRODE); - - #if GAS_DEBUG>0 - USB.print(F("GP.V_conc: ")); - USB.print(V_conc); - USB.print(F(" mV || R_gain: ")); - USB.print(R_gain, DEC); - USB.println(F(" Ohms")); - #endif - - #if GAS_DEBUG>1 - USB.print(F("GP.Compensation values: ")); - USB.print(sensor_config.calibration[0][0]); - USB.print(F("; ")); - USB.println(sensor_config.calibration[0][1]); - - USB.print(F("GP.val_aux: ")); - USB.print(sensor_config.val_aux); - USB.print(F(" nA/ppm || baseline: ")); - USB.print(sensor_config.baseline); - USB.println(F(" nA")); - #endif - - conc_aux = (V_conc / (R_gain)) * 1000; // V(mV) --> I(uA) - - conc_aux = ((conc_aux + sensor_config.calibration[1][0]) / (sensor_config.calibration[1][1])); - #if GAS_DEBUG>0 - USB.print(F("GP.Iae: ")); - USB.print(conc_aux); - USB.println(F(" uA")); - #endif - conc_aux -= (sensor_config.baseline / 1000); // Subtracts baseline current - - //conc_aux -= getBaselineTempComp(temperature); // Baseline temperature compensation - - //conc *= getSensitivityTempComp(temperature); // Output current temperature compensation - - conc_aux = (conc_aux * 1000) / sensor_config.val_aux; // I(uA) --> concentración(ppm) - - #if GAS_DEBUG>0 - USB.print(F("GP.conc_aux: ")); - USB.print(conc_aux); - USB.println(F(" ppm")); - #endif - if (conc_aux < 0) - { - conc_aux = 0; - } + /*************************************** + * O3 AND OXIDISING BOARD * + ***************************************/ + case O3_AS: + case CALIBRATION_4E: + #if GAS_DEBUG>0 + USB.print(F("GP.Reading OX sensor; t: ")); + USB.println(millis() - sensor_config.tempo, DEC); + #endif - } - - // Compose concentration - if (electrode == AUXILIARY_ELECTRODE) + if(sensor_config.AFE_ver == 3) { - conc = conc_aux; + conc = read4ElectrodeSensorv301(resolution, temperature, NO2_conc); } else { - conc = conc - conc_aux; - + conc = read4ElectrodeSensorv100(resolution, temperature); } + + break; + - if (conc < 0) + /*************************************** + * 4-ELECTRODE AMPERIOMETRIC BOARD * + ***************************************/ + case NO2_AS: + case NO_AS: + case SO2_AS: + case CO_AS: + #if GAS_DEBUG>0 + USB.print(F("GP.Reading 4E sensor; t: ")); + USB.println(millis() - sensor_config.tempo, DEC); + #endif + + if (sensor_config.AFE_ver == 3) { - conc = 0; + conc = read4ElectrodeSensorv301(resolution, temperature, 0); } - - // Disable communication with AFE - digitalWrite(sensor_config.I2C_pin, LOW); - - break; - + else + { + conc = read4ElectrodeSensorv100(resolution, temperature); + } + break; } @@ -2137,6 +2820,19 @@ float Gas::ppm2perc(float ppm_conc) } +/* Function: This function converts concentration in ppm to ugm3 + * Parameters: ppm_conc: concentration in ppm + * Returns: The concetration value in % +*/ +float Gas::ppm2ugm3(float ppm_conc) +{ + float aux_val; + aux_val = pgm_read_float(&table_ppm2ugm3[sensor_config.sensor_type]); + return (ppm_conc * aux_val); + +} + + /* Function: This function converts temperature in Celsius degrees to Fahrenheit degrees * Parameters: temp: concentration in Celsius degrees * Returns: The concetration value in Fahrenheit degrees @@ -2166,6 +2862,8 @@ void Gas::showSensorInfo() USB.println(F("************ Sensor data ************")); USB.print(F("Serial n.: ")); USB.println(sensor_no); + USB.print(F("AFE version n.: ")); + USB.println(sensor_config.AFE_ver, DEC); USB.print(F("Sensor type: ")); switch (sensor_config.sensor_type) { @@ -2217,6 +2915,18 @@ void Gas::showSensorInfo() case NDIR_CO2_SS: USB.println("CO2"); break; + case NO2_AS: + USB.println("NO2 4E"); + break; + case NO_AS: + USB.println("NO 4E"); + break; + case SO2_AS: + USB.println("SO2 4E"); + break; + case CO_AS: + USB.println("CO 4E"); + break; default: USB.println(sensor_config.sensor_type, DEC); break; @@ -2254,15 +2964,32 @@ void Gas::showSensorInfo() USB.println(F(" nA")); } - if ((sensor_config.sensor_type == O3_AS) || (sensor_config.sensor_type == CALIBRATION_4E)) - { - USB.print(F("aux_conc: ")); - USB.print(sensor_config.val_aux); - USB.println(F(" nA/ppm")); + if ((sensor_config.sensor_type == O3_AS) || + (sensor_config.sensor_type == NO2_AS) || + (sensor_config.sensor_type == NO_AS) || + (sensor_config.sensor_type == SO2_AS) || + (sensor_config.sensor_type == CO_AS) || + (sensor_config.sensor_type == CALIBRATION_4E)) + { + USB.print(F("OX_NO2_sens: ")); + USB.print(sensor_config.OX_NO2_sens); + USB.println(F(" nA/ppm")); + + if(sensor_config.AFE_ver == 3) + { + USB.print(F("aux_baseline: ")); + USB.print(sensor_config.aux_baseline); + USB.println(F(" nA")); + } } + - if ( (sensor_config.sensor_type == O3_AS) - || (sensor_config.sensor_type == CALIBRATION_4E)) + if ((sensor_config.sensor_type == O3_AS) || + (sensor_config.sensor_type == NO2_AS) || + (sensor_config.sensor_type == NO_AS) || + (sensor_config.sensor_type == SO2_AS) || + (sensor_config.sensor_type == CO_AS) || + (sensor_config.sensor_type == CALIBRATION_4E)) { USB.println(F("Adjust values:")); USB.print(sensor_config.calibration[0][0]); @@ -2293,8 +3020,380 @@ void Gas::showSensorInfo() USB.print(F(" ; ")); USB.println(sensor_config.calibration[x][1]); } + if(sensor_config.AFE_ver >= 3) + { + USB.print(7, DEC); + USB.print(F(": ")); + USB.print(sensor_config.calibration[7][0]); + USB.print(F(" ; ")); + USB.println(sensor_config.calibration[7][1]); + } + + } + +} + + +//! ONlY FOR MANUFACTURER +/* Function: This function reads the value for working electrode + * Returns: Value from working electrode +*/ +float Gas::readWorkingElectrode3E() +{ + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + // Selects amperiometric mode + LMP.setModeReg( LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + delay(100); + + V_conc = 0; + for ( int i = 0; i < 4; i++) + { + // Reads the ADC + aux_val = (MCP.readADC(MCP3421_ULTRA_HIGH_RES, MCP3421_GAIN_1, MCP3421_VOLTS)); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/4 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; + } + + V_conc /= 4; + + + // Gets the Vref + switch (LMP.getRefSource()) + { + case 0: + V_ref = 3300; + break; + case 1: + V_ref = 2048; + break; + } + + switch (LMP.getInternalZero()) + { + case 0: + V_ref *= 0.2; + break; + case 1: + V_ref *= 0.5; + break; + case 2: + V_ref *= 0.67; + break; + case 3: + V_ref *= 1; + break; + } + + // Gets the Rgain used + r_gain_LMP = LMP.getRgain(); + switch (r_gain_LMP) + { + case 0: + R_gain = 1000000; + break; + case 1: + R_gain = 2750; + break; + case 2: + R_gain = 3500; + break; + case 3: + R_gain = 7000; + break; + case 4: + R_gain = 14000; + break; + case 5: + R_gain = 35000; + break; + case 6: + R_gain = 120000; + break; + case 7: + R_gain = 350000; + break; + default: + R_gain = 0; + } + + + // Disable communication with AFE + digitalWrite(sensor_config.I2C_pin, LOW); + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.print(F(" mV")); + + USB.print(F(" || V_ref: ")); + USB.print(V_ref); + USB.print(F(" mV")); + + USB.print(F(" || R_gain: ")); + USB.print(R_gain, DEC); + USB.println(F(" Ohms")); + #endif + + #if GAS_DEBUG>1 + if(r_gain_LMP != 0) + { + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[r_gain_LMP-1][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[r_gain_LMP-1][1]); + } + else + { + USB.println(F("GP.External resistor: ")); + USB.print(sensor_config.calibration[7][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[7][1]); + } + + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" nA/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" nA")); + #endif + + conc = (V_conc - V_ref); // Vconc(mV) - Vzero(mV) + + conc = (conc / R_gain) * 1000; // V(mV) --> I(uA) + + #if I_DEBUG>0 + USB.print(V_conc); + USB.print(F("#")); + USB.print(conc); + USB.print(F("#")); + #endif + + if(r_gain_LMP != 0) + { + conc = ((conc + sensor_config.calibration[r_gain_LMP-1][0]) / (sensor_config.calibration[r_gain_LMP-1][1])); // Adjust resistor + } + else + { + conc = ((conc + sensor_config.calibration[7][0]) / (sensor_config.calibration[7][1])); // Adjust resistor + } + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + #if GAS_DEBUG>0 + USB.print(F("GP.I: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + conc = (conc * 1000) / sensor_config.m_conc; // I(nA) --> concentración(ppm) + + #if I_DEBUG>0 + USB.print(conc); + USB.print(F("#")); + #endif + + + return conc; + +} + +/* Function: This function reads the value for working electrode + * Returns: Value from working electrode +*/ +float Gas::readWorkingElectrode4E() +{ + + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + + // Selects amperiometric mode + LMP.setModeReg(LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + + // Measuring + conc = 0; + + ///**************************************************** + /// Read WE + #if GAS_DEBUG>0 + USB.println(F("GP.Reading working electrode")); + #endif + + V_conc = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC we")); + #endif + for ( int i = 0; i < 8; i++) + { + // Reads the ADC + aux_val = MCP.readADC(I2C_ADDRESS_GASPRO_MCP3421_A1, MCP3421_ULTRA_HIGH_RES, MCP3421_GAIN_1, MCP3421_VOLTS); + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc += aux_val; } + V_conc /= -8; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc: ")); + USB.print(V_conc); + USB.print(F(" mV || R_gain: ")); + USB.print(110000, DEC); + USB.println(F(" Ohms")); + #endif + + conc = V_conc / 110; // V(mV) --> I(uA) + + #if GAS_DEBUG>0 + USB.print(F("GP.Iwe: ")); + USB.print(conc); + USB.println(F(" uA")); + #endif + + + // Adjust electronic offset and gain for WE + conc = ((conc + sensor_config.calibration[0][0]) / (sensor_config.calibration[0][1]));// Adjust resistor + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[0][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[0][1]); + USB.print(F("GP.m_conc: ")); + USB.print(sensor_config.m_conc); + USB.print(F(" nA/ppm || baseline: ")); + USB.print(sensor_config.baseline); + USB.println(F(" nA")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.conc compensated: ")); + USB.println(conc); + #endif + + return conc; + +} + +/* Function: This function reads the value for auxiliary electrode + * Returns: Value from auxiliary electrode +*/ +float Gas::readAuxiliaryElectrode4E() +{ + + float V_conc = 0, V_conc_aux = 0; + float conc=0, conc_aux=0; + float aux_val; + float aux_resistor; + int r_gain_LMP; + + float V_ref=0, R_gain; + + // Selects amperiometric mode + LMP.setModeReg(LMP91000_MODEC_REG_FET_NOT_SHORTED, + LMP91000_MODEC_REG_PWR_MODE_3_LEAD_AMPERIOMETRIC); + + // Measuring + conc = 0; + conc_aux = 0; + + ///**************************************************** + /// Read AE + #if GAS_DEBUG>0 + USB.println(F("GP.Reading auxiliary electrode")); + #endif + + V_conc_aux = 0; + #if GAS_DEBUG>0 + USB.println(F("GP.ADC ae")); + #endif + for ( int i = 0; i < 8; i++) + { + //Reads the ADC + aux_val = MCP.readADC( I2C_ADDRESS_GASPRO_MCP3421_A2, + MCP3421_ULTRA_HIGH_RES, + MCP3421_GAIN_1, + MCP3421_VOLTS); + + #if GAS_DEBUG>1 + USB.print(F("GP.Measure ")); + USB.print(i+1, DEC); + USB.print(F("/8 from ADC: ")); + USB.print(aux_val); + USB.println(F(" mV")); + #endif + + V_conc_aux += aux_val; + } + + V_conc_aux /= -8; + + #if GAS_DEBUG>0 + USB.print(F("GP.V_conc_aux: ")); + USB.print(V_conc_aux); + USB.print(F(" mV || R_gain: ")); + USB.print(110000, DEC); + USB.println(F(" Ohms")); + #endif + + conc_aux = V_conc_aux / 110;// V(mV) --> I(uA) + + #if GAS_DEBUG>0 + USB.print(F("GP.Iae: ")); + USB.print(conc_aux); + USB.println(F(" uA")); + #endif + + // Adjust electronic offset and gain for AE + conc_aux = ((conc_aux + sensor_config.calibration[1][0]) / (sensor_config.calibration[1][1]));// Adjust resistor + + #if GAS_DEBUG>1 + USB.print(F("GP.Compensation values: ")); + USB.print(sensor_config.calibration[1][0]); + USB.print(F("; ")); + USB.println(sensor_config.calibration[1][1]); + + USB.print(F("GP.baseline: ")); + USB.print(sensor_config.aux_baseline); + USB.println(F(" nA")); + #endif + #if GAS_DEBUG>0 + USB.print(F("GP.conc_aux compensated: ")); + USB.println(conc_aux); + #endif + + + return conc_aux; + } + + diff --git a/libraries/SensorGas_PRO/WaspSensorGas_Pro.h b/libraries/SensorGas_PRO/WaspSensorGas_Pro.h index e26fde1..d4752cf 100755 --- a/libraries/SensorGas_PRO/WaspSensorGas_Pro.h +++ b/libraries/SensorGas_PRO/WaspSensorGas_Pro.h @@ -1,7 +1,7 @@ /*! \file WaspSensorGas_Pro.h \brief Library for managing the Gas Pro Sensor Board - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,13 +17,13 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.4 + Version: 3.1 Design: David Gascón Implementation: Alejandro Gállego */ -/*! \def OPC_N2_h +/*! \def WaspSensorGas_Pro_h \brief The library flag */ @@ -44,26 +44,12 @@ #include #define GAS_DEBUG 0 +// #define GAS_DEBUG 1 +// #define GAS_DEBUG 2 //#define GAS_PRO_AUTOGAIN_DEBUG -//#define CALIBRATION_MODE +// #define CALIBRATION_MODE -//!*************************************************************************** -//! SOCKET defines -//!*************************************************************************** -//! OEM -#define SOCKET_1 1 -#define SOCKET_2 2 -#define SOCKET_3 3 -#define SOCKET_4 4 -#define SOCKET_5 5 -#define SOCKET_6 6 - -//! P&S! -#define SOCKET_A 4 -#define SOCKET_B 5 -#define SOCKET_C 1 -#define SOCKET_D 6 -#define SOCKET_F 3 +// #define I_DEBUG 1 //!*************************************************************************** //! EEPROM defines @@ -73,18 +59,23 @@ // Common #define VER_BOARD_REG 0x00 // 1 Byte #define SENSOR_TYPE_REG 0x01 // 1 Byte -#define SENSITIVITY_REG 0x02 // 4 Bytes -#define OFFSET_REG 0x08 // 4 Bytes +#define SENSOR_CHECKSUM 0x06 // 1 Byte #define SENSOR_NO_REG 0x70 // 16 Bytes // 3 electrode board -#define CAL_REG 0x10 // 56 Bytes +#define SENSITIVITY_REG 0x02 // 4 Bytes +#define OFFSET_REG 0x08 // 4 Bytes +#define CAL_REG 0x10 // 64 Bytes // 4 electrode board #define SENS_WE_REG 0x02 // 4 Bytes +#define WE_OFFSET_REG 0x08 // 4 Bytes #define SENS_AE_REG 0x0C // 4 Bytes -#define CAL_WE_REG 0x10 // 40 Bytes -#define CAL_AE_REG 0x18 // 40 Bytes +#define CAL_WE_REG 0x10 // 16 Bytes +#define CAL_AE_REG 0x18 // 16 Bytes +#define CAL_WE_EXT_REG 0x20 // 16 Bytes +#define CAL_AE_EXT_REG 0x28 // 16 Bytes +#define AE_OFFSET_REG 0x30 // 4 Bytes // pellistor/CO2 board #define CAL_1_REG 0x10 // 4 Bytes @@ -123,6 +114,8 @@ #define MCP_GAIN_3 60000 #define MCP_GAIN_4 80000 #define MCP_GAIN_5 100000 +#define MCP_GAIN_6 1000000 + //!*************************************************************************** @@ -145,7 +138,11 @@ // ALPHASENSE gas sensors #define LEL_AS 13 // Pellistor -#define O3_AS 14 // 4 electrodos +#define O3_AS 14 // 4 electrode Vbias: 0V +#define NO2_AS 16 // 4 electrode Vbias: 0V +#define NO_AS 17 // 4 electrode Vbias: +200mV +#define SO2_AS 18 // 4 electrode Vbias: 0V +#define CO_AS 19 // 4 electrode Vbias: 0V // SOLIDSENSE NDIR #define NDIR_CO2_SS 15 // CO2 NDIR @@ -154,7 +151,7 @@ #define CALIBRATION_NDIR 251 #define CALIBRATION_3E 252 #define CALIBRATION_4E 253 -#define CALIBRATION_PEL 254 +#define CALIBRATION_PEL 254 #define UNDEFINED_SENSOR 255 @@ -186,21 +183,26 @@ //-20 ºC 20ºC 40ºC 50ºC const float table_baseline_temp_comp[][4] PROGMEM = { - {0,0,-0.05,-0.3}, // CL2_SS - {-0.3,0,0,-0.3}, // CO_SS_CLE - {-1,0,2.66,5}, // ETO_SS - {-2,0,0,-2.5}, // H2_SS_SEC - {0,0,0,-0.04}, // H2S_SS_SEC - {0,0,4,15}, // HCL_SS - {0,0,-0.1,0.1}, // HCN_SS - {-0.25,0,1.66,3}, // NH3_SS - {-0.6,0,4,9}, // NO_SS - {0.1,0,-0.5,-1.7}, // NO2_SS_CLE - {0,0,0,0}, // O2_SS - {0,0,0.15,0.4}, // PH3_SS - {0,0,0.2,0.6}, // SO2_SS - {0,0,0,0}, // LEL_AS - {0.01,0.025,0.12,0.25} // O3_AS + {0,0,-0.05,-0.3}, // CL2_SS + {-0.3,0,0,-0.3}, // CO_SS_CLE + {-1,0,2.66,5}, // ETO_SS + {-2,0,0,-2.5}, // H2_SS_SEC + {0,0,0,-0.04}, // H2S_SS_SEC + {0,0,4,15}, // HCL_SS + {0,0,-0.1,0.1}, // HCN_SS + {-0.25,0,1.66,3}, // NH3_SS + {-0.6,0,4,9}, // NO_SS + {0.1,0,-0.5,-1.7}, // NO2_SS_CLE + {0,0,0,0}, // O2_SS + {0,0,0.15,0.4}, // PH3_SS + {0,0,0.2,0.6}, // SO2_SS + {0,0,0,0}, // LEL_AS + {0.01,0.025,0.12,0.25}, // O3_AS + {0,0,0,0}, // NDIR_CO2_SS + {0.013,0.016,0.047,0.130}, // NO2_AS + {0.015,0.040,0.150,0.325}, // NO_AS + {0.,0.01,0.1,0.225}, // SO2_AS + {0,-0.025,-0.075,-0.150} // CO_AS }; //!Compensation values for sensitivity @@ -221,13 +223,46 @@ const float table_sensitivity_temp_comp[][5] PROGMEM = {0.8,0.9,1,1.05,1.05}, // PH3_SS {0.9,1,1,1.05,1}, // SO2_SS {1.055,1.035,1,1.015,1.0}, // LEL_AS - {0.7,0.92,1,1,0.92} // O3_AS + {0.7,0.92,1,1,0.92}, // O3_AS + {1,1,1,1,1}, // NDIR_CO2_SS + {0.7,0.77,1,1.1,1.13}, // NO2_AS + {0.4,0.8,1,1.2,1.3}, // NO_AS + {0.83,0.95,1,0.99,0.96}, // SO2_AS + {0.52,0.8,1,1.12,1.18} // CO_AS }; +//!Compensation values for sensitivity +//-20 ºC 0ºC 20ºC 40ºC 50ºC +const float table_ppm2ugm3[] PROGMEM = +{ + 2900, // CL2_SS + 1230, // CO_SS_CLE + 1984, // ETO_SS + 88.9, // H2_SS_SEC + 1500, // H2S_SS_SEC + 1605, // HCL_SS + 1189, // HCN_SS + 750, // NH3_SS + 1320, // NO_SS + 2030, // NO2_SS_CLE + 1410, // O2_SS + 772, // PH3_SS + 2820, // SO2_SS + 1, // LEL_AS + 2115, // O3_AS + 1940, // NDIR_CO2_SS + 2030, // NO2_AS + 1320, // NO_AS + 2820, // SO2_AS + 1230 // CO_AS +}; extern volatile uint8_t pwrGasPRORegister; +#define I2C_MAIN_EN ANA0 + + /****************************************************************************** * Class ******************************************************************************/ @@ -249,10 +284,12 @@ class Gas int power_pin; // GPIO asociated to the power pin int I2C_pin; // GPIO asociated to the I2C pin float m_conc; // nA/ppm or mV/% - float val_aux; // extra variable. nA/ppm, only for 4 electrode sensors (O3) float baseline; // nA or mV - float calibration[7][2]; // compensation values for AFE modules + float aux_baseline; // nA, offset for auxiliary electrode + float OX_NO2_sens; // nA/ppm + float calibration[8][2]; // compensation values for AFE modules uint32_t tempo; // timer + uint8_t AFE_ver; // AFE board version } sensor_config; @@ -290,11 +327,72 @@ class Gas */ float getAmplifier(bool electrode); + //! Specific function to read 3 electrode sensors + /*! + \param uint8_t resolution: resolution value for ADC + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + \return The concetration value in ppm + */ + float read3ElectrodeSensor(uint8_t resolution, float temperature); + + //! Specific function to read pellistor sensors + /*! + \param uint8_t resolution: resolution value for ADC + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + \return The concetration value %LEL + */ + float readPellistorSensor(uint8_t resolution, float temperature); + + //! Specific function to read NDIR sensors + /*! + \param uint8_t resolution: resolution value for ADC + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + \return The concetration value in ppm + */ + float readNDIR(uint8_t resolution, float temperature); + + //! Specific function to read O3 sensors (v12 sensors) + /*! + \param uint8_t resolution: resolution value for ADC + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + \return The concetration value in ppm + */ + float read4ElectrodeSensorv100(uint8_t resolution, float temperature); + + //! Specific function to read 4 electrode sensors + /*! + \param uint8_t resolution: resolution value for ADC + MCP3421_RES_12_BIT or MCP3421_LOW_RES + MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES + MCP3421_RES_16_BIT or MCP3421_HIGH_RES + MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES + \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) + \param float NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. Only for O3 sensor, for other sensors use 0.0 value + \return The concetration value in ppm + */ + float read4ElectrodeSensorv301(uint8_t resolution, float temperature, float NO2_conc); + //! This function reads the sensor information from EEPROM /*! \return nothing */ - void readSensorInfo(); + uint8_t readSensorInfo(); public: @@ -424,12 +522,10 @@ class Gas MCP3421_RES_14_BIT or MCP3421_MEDIUM_RES MCP3421_RES_16_BIT or MCP3421_HIGH_RES MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES - \param uint8_t electrode: electrode to read - WORKING_ELECTRODE - AUXILIARY_ELECTRODE + \param float NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. Only for O3 sensor \return The concetration value in ppm / %LEL, -1000 if error. */ - float getConc(uint8_t resolution, uint8_t electrode); + float getConc(uint8_t resolution, float NO2_conc); //! This function reads concentration value /*! @@ -439,12 +535,10 @@ class Gas MCP3421_RES_16_BIT or MCP3421_HIGH_RES MCP3421_RES_18_BIT or MCP3421_ULTRA_HIGH_RES \param float temperature: ambient temperature for sensor compensation (-1000 if doesn't needed) - \param uint8_t electrode: electrode to read - WORKING_ELECTRODE - AUXILIARY_ELECTRODE + \param float NO2_conc: NO2 concentration in ppm to compensate the cross-sensitivity. Only for O3 sensor \return The concetration value in ppm / %LEL, -1000 if error. */ - float getConc(uint8_t resolution, float temperature, uint8_t electrode); + float getConc(uint8_t resolution, float temperature, float NO2_conc); //! This function changes the gain and the Vref of the AFE module /*! @@ -460,6 +554,13 @@ class Gas */ float ppm2perc(float ppm_conc); + //! This function converts concentration in ppm to ugm3 + /*! + \param float ppm_conc: concentration in ppm + \return The concetration value in ugm3 + */ + float ppm2ugm3(float ppm_conc); + //! This function converts temperature in Celsius degrees to Fahrenheit degrees /*! \param temp: concentration in Celsius degrees @@ -473,7 +574,27 @@ class Gas /*! \return nothing */ - void showSensorInfo(); + void showSensorInfo(); + + + //! ONlY FOR MANUFACTURER + //! This function reads the value for working electrode + /*! + \return Value from working electrode + */ + float readWorkingElectrode3E(); + + //! This function reads the value for working electrode + /*! + \return Value from working electrode + */ + float readWorkingElectrode4E(); + + //! This function reads the value for auxiliary electrode + /*! + \return Value from auxiliary electrode + */ + float readAuxiliaryElectrode4E(); }; diff --git a/libraries/SensorGas_PRO/keywords.txt b/libraries/SensorGas_PRO/keywords.txt index aa069d8..4a74905 100644 --- a/libraries/SensorGas_PRO/keywords.txt +++ b/libraries/SensorGas_PRO/keywords.txt @@ -9,6 +9,7 @@ SOCKET_6 LITERAL1 SOCKET_A LITERAL1 SOCKET_B LITERAL1 SOCKET_C LITERAL1 +SOCKET_D LITERAL1 SOCKET_F LITERAL1 E2PROM_ADDR LITERAL1 VER_BOARD_REG LITERAL1 @@ -16,6 +17,7 @@ SENSOR_TYPE_REG LITERAL1 SENSITIVITY_REG LITERAL1 OFFSET_REG LITERAL1 SENSOR_NO_REG LITERAL1 +SENSOR_CHECKSUM LITERAL1 CAL_REG LITERAL1 SENS_WE_REG LITERAL1 SENS_AE_REG LITERAL1 @@ -50,6 +52,7 @@ MCP_GAIN_2 LITERAL1 MCP_GAIN_3 LITERAL1 MCP_GAIN_4 LITERAL1 MCP_GAIN_5 LITERAL1 +MCP_GAIN_6 LITERAL1 CL2_SS LITERAL1 CO_SS_SEC LITERAL1 ETO_SS LITERAL1 @@ -65,6 +68,7 @@ PH3_SS LITERAL1 SO2_SS LITERAL1 LEL_AS LITERAL1 O3_AS LITERAL1 +NO2_AS LITERAL1 NDIR_CO2_SS LITERAL1 CALIBRATION_NDIR LITERAL1 CALIBRATION_3E LITERAL1 @@ -84,6 +88,11 @@ URG LITERAL1 LRG LITERAL1 MAX_RANGE_FACTOR LITERAL1 MIN_RANGE_FACTOR LITERAL1 +WE_OFFSET_REG LITERAL1 +AE_OFFSET_REG LITERAL1 +CAL_WE_EXT_REG LITERAL1 +CAL_AE_EXT_REG LITERAL1 +I2C_MAIN_EN LITERAL1 Gas KEYWORD2 over_limit KEYWORD2 @@ -102,126 +111,7 @@ Celsius2Fahrenheit KEYWORD2 showSensorInfo KEYWORD2 WaspSensorGas_Pro KEYWORD2 - -# BME280 # - -BME280_I2C_ADDRESS1 LITERAL1 -BME280_I2C_ADDRESS2 LITERAL1 -BME280_I2C_ADDRESS LITERAL1 -BME280_SLEEP_MODE LITERAL1 -BME280_FORCED_MODE LITERAL1 -BME280_NORMAL_MODE LITERAL1 -BME280_SOFT_RESET_CODE LITERAL1 -BME280_STANDBY_TIME_1_MS LITERAL1 -BME280_STANDBY_TIME_63_MS LITERAL1 -BME280_STANDBY_TIME_125_MS LITERAL1 -BME280_STANDBY_TIME_250_MS LITERAL1 -BME280_STANDBY_TIME_500_MS LITERAL1 -BME280_STANDBY_TIME_1000_MS LITERAL1 -BME280_STANDBY_TIME_10_MS LITERAL1 -BME280_STANDBY_TIME_20_MS LITERAL1 -BME280_OVERSAMP_SKIPPED LITERAL1 -BME280_OVERSAMP_1X LITERAL1 -BME280_OVERSAMP_2X LITERAL1 -BME280_OVERSAMP_4X LITERAL1 -BME280_OVERSAMP_8X LITERAL1 -BME280_OVERSAMP_16X LITERAL1 -BME280_FILTER_COEFF_OFF LITERAL1 -BME280_FILTER_COEFF_2 LITERAL1 -BME280_FILTER_COEFF_4 LITERAL1 -BME280_FILTER_COEFF_8 LITERAL1 -BME280_FILTER_COEFF_16 LITERAL1 -BME280_DIG_T1_LSB_REG LITERAL1 -BME280_DIG_T1_MSB_REG LITERAL1 -BME280_DIG_T2_LSB_REG LITERAL1 -BME280_DIG_T2_MSB_REG LITERAL1 -BME280_DIG_T3_LSB_REG LITERAL1 -BME280_DIG_T3_MSB_REG LITERAL1 -BME280_DIG_P1_LSB_REG LITERAL1 -BME280_DIG_P1_MSB_REG LITERAL1 -BME280_DIG_P2_LSB_REG LITERAL1 -BME280_DIG_P2_MSB_REG LITERAL1 -BME280_DIG_P3_LSB_REG LITERAL1 -BME280_DIG_P3_MSB_REG LITERAL1 -BME280_DIG_P4_LSB_REG LITERAL1 -BME280_DIG_P4_MSB_REG LITERAL1 -BME280_DIG_P5_LSB_REG LITERAL1 -BME280_DIG_P5_MSB_REG LITERAL1 -BME280_DIG_P6_LSB_REG LITERAL1 -BME280_DIG_P6_MSB_REG LITERAL1 -BME280_DIG_P7_LSB_REG LITERAL1 -BME280_DIG_P7_MSB_REG LITERAL1 -BME280_DIG_P8_LSB_REG LITERAL1 -BME280_DIG_P8_MSB_REG LITERAL1 -BME280_DIG_P9_LSB_REG LITERAL1 -BME280_DIG_P9_MSB_REG LITERAL1 -BME280_DIG_H1_REG LITERAL1 -BME280_DIG_H2_LSB_REG LITERAL1 -BME280_DIG_H2_MSB_REG LITERAL1 -BME280_DIG_H3_REG LITERAL1 -BME280_DIG_H4_MSB_REG LITERAL1 -BME280_DIG_H5_LSB_H4_LSB_REG LITERAL1 -BME280_DIG_H5_MSB_REG LITERAL1 -BME280_DIG_H6_REG LITERAL1 -BME280_CHIP_ID_REG LITERAL1 -BME280_RST_REG LITERAL1 -BME280_STAT_REG LITERAL1 -BME280_CTRL_MEAS_REG LITERAL1 -BME280_CTRL_HUMIDITY_REG LITERAL1 -BME280_CONFIG_REG LITERAL1 -BME280_PRESSURE_MSB_REG LITERAL1 -BME280_PRESSURE_LSB_REG LITERAL1 -BME280_PRESSURE_XLSB_REG LITERAL1 -BME280_TEMPERATURE_MSB_REG LITERAL1 -BME280_TEMPERATURE_LSB_REG LITERAL1 -BME280_TEMPERATURE_XLSB_REG LITERAL1 -BME280_HUMIDITY_MSB_REG LITERAL1 -BME280_HUMIDITY_LSB_REG LITERAL1 -BME280_CHIP_ID_REG_CHIP_ID LITERAL1 -BME280_STAT_REG_MEASURING__POS LITERAL1 -BME280_STAT_REG_MEASURING__MSK LITERAL1 -BME280_STAT_REG_MEASURING__LEN LITERAL1 -BME280_STAT_REG_IM_UPDATE__POS LITERAL1 -BME280_STAT_REG_IM_UPDATE__MSK LITERAL1 -BME280_STAT_REG_IM_UPDATE__LEN LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__POS LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__MSK LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__LEN LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__POS LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__MSK LITERAL1 -BME280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__LEN LITERAL1 -BME280_CTRL_MEAS_REG_POWER_MODE__POS LITERAL1 -BME280_CTRL_MEAS_REG_POWER_MODE__MSK LITERAL1 -BME280_CTRL_MEAS_REG_POWER_MODE__LEN LITERAL1 -BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__POS LITERAL1 -BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__MSK LITERAL1 -BME280_CTRL_HUMIDITY_REG_OVERSAM_HUMIDITY__LEN LITERAL1 -BME280_CONFIG_REG_TSB__POS LITERAL1 -BME280_CONFIG_REG_TSB__MSK LITERAL1 -BME280_CONFIG_REG_TSB__LEN LITERAL1 -BME280_CONFIG_REG_FILTER__POS LITERAL1 -BME280_CONFIG_REG_FILTER__MSK LITERAL1 -BME280_CONFIG_REG_FILTER__LEN LITERAL1 -BME280_CONFIG_REG_SPI3_ENABLE__POS LITERAL1 -BME280_CONFIG_REG_SPI3_ENABLE__MSK LITERAL1 -BME280_CONFIG_REG_SPI3_ENABLE__LEN LITERAL1 -BME280_PRESSURE_XLSB_REG_DATA__POS LITERAL1 -BME280_PRESSURE_XLSB_REG_DATA__MSK LITERAL1 -BME280_PRESSURE_XLSB_REG_DATA__LEN LITERAL1 -BME280_TEMPERATURE_XLSB_REG_DATA__POS LITERAL1 -BME280_TEMPERATURE_XLSB_REG_DATA__MSK LITERAL1 -BME280_TEMPERATURE_XLSB_REG_DATA__LEN LITERAL1 - -BME280 KEYWORD2 -ON KEYWORD2 -checkID KEYWORD2 -readCalibration KEYWORD2 -showCalibration KEYWORD2 -getTemperature KEYWORD2 -getPressure KEYWORD2 -getHumidity KEYWORD2 - -BME KEYWORD3 +BME KEYWORD1 # LMP91000 # @@ -320,8 +210,10 @@ getModeReg KEYWORD2 setTIAConReg KEYWORD2 setRefConReg KEYWORD2 setModeReg KEYWORD2 +configureAFE KEYWORD2 +ppm2ugm3 KEYWORD2 -LMP KEYWORD3 +LMP KEYWORD1 # MCP3421 # @@ -345,4 +237,19 @@ MCP3421_VOLTS LITERAL1 MCP3421 KEYWORD2 readADC KEYWORD2 -MCP KEYWORD3 +MCP KEYWORD1 +CO KEYWORD1 +CO2 KEYWORD1 +O2 KEYWORD1 +NO KEYWORD1 +NO2 KEYWORD1 +SO2 KEYWORD1 +NH3 KEYWORD1 +CH4 KEYWORD1 +H2 KEYWORD1 +H2S KEYWORD1 +HCl KEYWORD1 +HCN KEYWORD1 +PH3 KEYWORD1 +ETO KEYWORD1 +Cl2 KEYWORD1 diff --git a/libraries/SensorGas_v20/WaspSensorGas_v20.cpp b/libraries/SensorGas_v20/WaspSensorGas_v20.cpp index 152f4be..22f3687 100644 --- a/libraries/SensorGas_v20/WaspSensorGas_v20.cpp +++ b/libraries/SensorGas_v20/WaspSensorGas_v20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascón * Implementation: Alberto Bielsa, Manuel Calahorra */ @@ -55,7 +55,7 @@ WaspSensorGas_v20::WaspSensorGas_v20() PWR.setSensorPower(SENS_5V, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_GASES; + WaspRegisterSensor |= REG_GASES; } // Public Methods ////////////////////////////////////////////////////////////// @@ -559,13 +559,18 @@ void WaspSensorGas_v20::setResistor(uint8_t address, float value) auxiliar = auxiliar/100; resist = (uint8_t) 128-auxiliar; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00000000); Wire.send(resist); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } @@ -607,13 +612,18 @@ void WaspSensorGas_v20::setAmplifier(uint8_t address, uint8_t value) ampli= uint8_t(128-((128*(value-1))/100)); - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.beginTransmission(address); Wire.send(B00010000); Wire.send(ampli); Wire.endTransmission(); - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } diff --git a/libraries/SensorGas_v20/WaspSensorGas_v20.h b/libraries/SensorGas_v20/WaspSensorGas_v20.h index b8073ae..cf6e6f1 100644 --- a/libraries/SensorGas_v20/WaspSensorGas_v20.h +++ b/libraries/SensorGas_v20/WaspSensorGas_v20.h @@ -1,7 +1,7 @@ /*! \file WaspSensorGas_v20.h \brief Library for managing the Gas Sensor Board - Copyright (C) 2013 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,10 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 - - Design: David Gascón - + Version: 3.0 + Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra */ diff --git a/libraries/SensorGas_v20/keywords.txt b/libraries/SensorGas_v20/keywords.txt index 4d3b32f..8df5ac2 100644 --- a/libraries/SensorGas_v20/keywords.txt +++ b/libraries/SensorGas_v20/keywords.txt @@ -35,4 +35,4 @@ readValue KEYWORD2 calculateResistance KEYWORD2 calculateConcentration KEYWORD2 -SensorGasv20 KEYWORD3 +SensorGasv20 KEYWORD1 diff --git a/libraries/SensorGas_v30/WaspSensorGas_v30.cpp b/libraries/SensorGas_v30/WaspSensorGas_v30.cpp new file mode 100644 index 0000000..9274577 --- /dev/null +++ b/libraries/SensorGas_v30/WaspSensorGas_v30.cpp @@ -0,0 +1,1994 @@ +/*! \file WaspSensorGas_v30.cpp + * \brief Library for managing the Gas Sensor Board v30 + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Ahmad Saad + */ + + +#ifndef __WPROGRAM_H__ + #include +#endif + +#include "WaspSensorGas_v30.h" + + +//************************************************************************************ +// GASES SENSOR BOARD CLASS +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== + /*! + * @brief Class contructor + * @param void + * @return void + */ +GasSensorClass::GasSensorClass() +{ + WaspRegisterSensor |= REG_GASES; +} + + +/*! + * @brief Switch ON the power supply and configure the I/O pins + * @param void + * @return void + */ +void GasSensorClass::ON() +{ + // Configure the MULTIPLEXOR control pins + pinMode(A2, OUTPUT); // <--- ANALOG6 <--- A2 + pinMode(A1, OUTPUT); // <--- ANALOG4 <--- A1 + pinMode(A0, OUTPUT); // <--- ANALOG2 <--- A0 + pinMode(EN, OUTPUT); // <--- DIGITAL1 <--- EN + + // I2C ISOLTAOR PIN ENABLE + pinMode(I2C_PIN_OE, OUTPUT); + delay(10); + + // Switches configuration + pinMode(SOCKET2_ON_PIN, OUTPUT); + pinMode(SOCKET3_ON_PIN, OUTPUT); + pinMode(SOCKET4_ON_PIN, OUTPUT); + pinMode(SOCKET5_ON_PIN, OUTPUT); + pinMode(SOCKET6_ON_PIN, OUTPUT); + pinMode(SOCKET7_ON_PIN, OUTPUT); + // Switch OFF all sockets + digitalWrite(SOCKET2_ON_PIN, LOW); + digitalWrite(SOCKET3_ON_PIN, LOW); + digitalWrite(SOCKET4_ON_PIN, LOW); + digitalWrite(SOCKET5_ON_PIN, LOW); + digitalWrite(SOCKET6_ON_PIN, LOW); + digitalWrite(SOCKET7_ON_PIN, LOW); + // Configure the internal reference + analogReference(INTERNAL2V56); + // Switch ON 3V3 and 5V for supplying the board + PWR.setSensorPower( SENS_5V, SENS_ON); + PWR.setSensorPower(SENS_3V3, SENS_ON); + digitalWrite(I2C_PIN_OE, HIGH); + // Gases Sensor Borad state ON + state = ON_STATE; + + #if DEBUG_GASES > 1 + PRINTLN_GASES(F("Gases Board v30 switched ON")); + #endif + + // Configure the BME280 Sensor (Temperature, Humidity and Pressure) + BME.ON(); + delay(100); + + if (_boot_version < 'H') + { + USB.println(F("\n*************** WARNING *******************")); + USB.println(F("This example is valid only for Waspmote v15.")); + USB.println(F("Your Waspmote version is v12.")); + USB.println(F("*******************************************")); + } +} + + +/*! + * @brief Switch OFF the power supply of the sensor board (5v and 3v3) + * @param void + * @return void + */ +void GasSensorClass::OFF(void) +{ + // Switch OFF all SOCKETS + digitalWrite(SOCKET2_ON_PIN, LOW); + digitalWrite(SOCKET3_ON_PIN, LOW); + digitalWrite(SOCKET4_ON_PIN, LOW); + digitalWrite(SOCKET5_ON_PIN, LOW); + digitalWrite(SOCKET6_ON_PIN, LOW); + digitalWrite(SOCKET7_ON_PIN, LOW); + // Isolate I2C bus communication + digitalWrite(I2C_PIN_OE, LOW); + // Switch OFF 3V3 and 5V + PWR.setSensorPower(SENS_5V, SENS_OFF); + PWR.setSensorPower(SENS_3V3, SENS_OFF); + // Gases Sensor Borad state OFF + state = OFF_STATE; + + #if DEBUG_GASES > 1 + PRINTLN_GASES(F("Gases Board v30 switched OFF")); + #endif + + delay(100); +} + + +/*! + * @brief Gets the temperature from the BME280 sensor + * @param void + * @return The temperature value read + */ +float GasSensorClass::getTemperature(void) +{ + // Read the temperature from the BME280 Sensor + return BME.getTemperature(BME280_OVERSAMP_1X, 0); +} + + +/*! + * @brief Gets the Humidity from the BME280 sensor + * @param void + * @return The humidity value read + */ +float GasSensorClass::getHumidity(void) +{ + // Read the humidity from the BME280 Sensor + return BME.getHumidity(BME280_OVERSAMP_1X); +} + + +/*! + * @brief Gets the Pressure from the BME280 sensor + * @param void + * @return The pressure value read + */ +float GasSensorClass::getPressure() +{ + // Read the pressure from the BME280 Sensor + return BME.getPressure(BME280_OVERSAMP_1X, 0); +} + + +/*! + * @brief Gets the Luxes value from the TSL sensor + * @param uint8_t gain: INDOOR or OUTDOOR + * @return The luxes value read + */ +float GasSensorClass::getLuxes(uint8_t gain) +{ + TSL.ON(); + + switch (gain) + { + case OUTDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_1); + break; + + case INDOOR: + TSL.getLuminosity(TSL2561_HIGH_RES, TSL2561_GAIN_16); + break; + } + + return TSL.lux; +} + + +/*! + * @brief Gets the distance from the UltraSound sensor + * @param void + * @return The distance value read in cm + */ +float GasSensorClass::getDistance() +{ + return Ultrasound.getDistance(); +} +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Calculates the resistor value in function of the gain + * @param uint8_t address: I2C address of the digipot + * @param float value: gain value selected + * @return void + */ +void GasSensorClass::setAmplifier(uint8_t address, float value) +{ + float auxiliar = 0; + uint8_t ampli=0; + + auxiliar = 129*(value-1); + auxiliar = auxiliar/100; + ampli = uint8_t (129-auxiliar); + + if( !Wire.isON ) + { + Wire.secureBegin(); + } + + delay(50); + + #if DEBUG_GASES > 1 + PRINT_GASES(F("Resitor configured for amplifier stage (KOHMs): ")); + PRINTLN_GASES_VAL((128.0 - ampli) * 0.781 + 1.078) + #endif + + Wire.beginTransmission(address); + Wire.send(B00010000); + Wire.send(ampli); + Wire.endTransmission(); +} + +/*! + * @brief Configures the resistor of the digital potentiometer + * @param uint8_t address: I2C address of the digipot + * @param float value : resistor value selected + * @return void + */ +void GasSensorClass::setResistor(uint8_t address, float value, int pot) +{ + // Calculates the value to configure + float auxiliar = 0; + uint8_t resist=0; + + auxiliar = 128*value; + auxiliar = auxiliar / 100.0; + resist = (uint8_t) 128-auxiliar; + + #if DEBUG_GASES > 1 + PRINT_GASES(F("Load Resistor configured (KOHMs): ")); + PRINTLN_GASES_VAL((128.0 - resist) * 0.781 + 0.078); + #endif + + // Inits the I2C Bus + if( !Wire.isON ) + Wire.secureBegin(); + + delay(50); + + // Send the corresponding packets to configure the digipot + Wire.beginTransmission(address); + Wire.send(pot); + Wire.send(resist); + Wire.endTransmission(); +} + + +/*! + * @brief Save the calibration points + * + * @param float[]: calValues: Y values of the function + * @param float[]: calConcentrations: X values of the function + * @param uint8_t: numPoints: the number of points to be used in calibration + * + * @return + * @arg '-1' if error + * @arg '0' if all OK + */ +int GasSensorClass::saveCalibrationPoints(float calValues[], float calConcentrations[], uint8_t numPoints_) +{ + if (numPoints_ <= MAX_POINTS) + numPoints = numPoints_; + else + return -1; + + // Store the calibration values + for (int i = 0; i < numPoints; i++) + { + values[i] = calValues[i]; + concentrations[i] = calConcentrations[i]; + } + + #if DEBUG_GASES > 1 + PRINT_GASES(F("[POINT_1] Concentration: ")); + PRINTLN_GASES_VAL(concentrations[POINT_1]); + PRINT_GASES(F("[POINT_2] Concentration: ")); + PRINTLN_GASES_VAL(concentrations[POINT_2]); + PRINT_GASES(F("[POINT_3] Concentration: ")); + PRINTLN_GASES_VAL(concentrations[POINT_3]); + PRINT_GASES(F("[POINT_1] Values: ")); + PRINTLN_GASES_VAL(calValues[POINT_1]); + PRINT_GASES(F("[POINT_2] Values: ")); + PRINTLN_GASES_VAL(calValues[POINT_2]); + PRINT_GASES(F("[POINT_3] Values: ")); + PRINTLN_GASES_VAL(calValues[POINT_3]); + #endif + + return 0; +} + + +/*! + * @brief Prepare the calibration points + * @param float[]: calValues: Y values of the function + * @param float[]: calConcentrations: X values of the function + * @param uint8_t: numPoints: the number of points to be used in calibration + * @return + * @arg '-1' if error + * @arg '0' if all OK + */ +int GasSensorClass::setCalibrationPoints(float calValues[], float calConcentrations[], uint8_t numPoints_) +{ + + if (numPoints_ > MAX_POINTS) + { + #if DEBUG_GASES > 0 + PRINTLN_GASES("ERROR: MAX_POINTS allowed = 10 "); + #endif + + return -1; + } + + Ro = calValues[0]; + // Store the calibration values + for (int i = 0; i < numPoints_; i++) + { + calValues[i] = calValues[i] / Ro; + } + + #if DEBUG_GASES > 1 + PRINTLN_GASES(F("Saving calibration values")); + PRINT_GASES(F("Ro value: ")); + PRINTLN_GASES_VAL(Ro); + PRINT_GASES(F("Number of points: ")); + PRINTLN_GASES_VAL(numPoints_); + #endif + + return saveCalibrationPoints(calValues, calConcentrations, numPoints_); +} + + +/*! + * @brief Prepare the calibration points + * @param void + * @return void + * @arg '-1' if error + * @arg '0' if all OK + */ +int GasSensorClass::setCalibrationPoints() +{ + return setCalibrationPoints(values, concentrations, numPoints); +} + + +/*! + * @brief Description: Point to point calculation function + * @param float: input: input value for getting concentration + * @return the concentration value + */ +float GasSensorClass::getConcentration(float input) +{ + bool inRange = false; + int i = 0; + + // This loop is to find the range where the input is located + while ((!inRange) && (i < (numPoints-1))) { + + if ((input > values[i]) && (input <= values[i + 1])) + inRange = true; + else if ((input <= values[i]) && (input > values[i+1])) + inRange = true; + else + i++; + } + + float temp_slope = 0.0; + float temp_intersection = 0.0; + float concentration = 0.0; + + // If the voltage input is in a range, we calculate in the slope + // and the intersection of the logaritmic function + if (inRange) + { + // Slope of the logarithmic function + temp_slope = (values[i] - values[i+1]) / (log10(concentrations[i]) - log10(concentrations[i+1])); + // Intersection of the logarithmic function + temp_intersection = values[i] - temp_slope * log10(concentrations[i]); + } + // Else, we calculate the logarithmic function with the nearest point + else + { + if (fabs(input - values[0]) < fabs(input - values[numPoints-1])) { + // Slope of the logarithmic function + temp_slope = (values[1] - values[0]) / (log10(concentrations[1]) - log10(concentrations[0])); + // Intersection of the logarithmic function + temp_intersection = values[0] - temp_slope * log10(concentrations[0]); + } else { + // Slope of the logarithmic function + temp_slope = (values[numPoints-1] - values[numPoints-2]) / (log10(concentrations[numPoints-1]) - log10(concentrations[numPoints-2])); + // Intersection of the logarithmic function + temp_intersection = values[numPoints-1] - temp_slope * log10(concentrations[numPoints-1]); + } + } + + // Return the value of the concetration + concentration = pow(10, ((input - temp_intersection) / temp_slope)); + + if (concentration < 99999.9) + { + return concentration; + } + else + { + #if DEBUG_GASES > 1 + PRINTLN_GASES("Concentration out of range"); + #endif + + return -1.0; + } +} + +//************************************************************************************ +// O2 SENSOR CLASS +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== +/*! + * @brief Class contructor + * @param void + * @return void + */ +O2SensorClass::O2SensorClass() +{ + gain = 10; + socket = SOCKET_1; +} + + +/*! + * @brief Class contructor + * @param uint8_t: socket where the sensor is connected + * @return void + */ +O2SensorClass::O2SensorClass(uint8_t _socket) +{ + // Store the gain value of the stage + socket = _socket; + gain = 50; +} + + +/*! + * @brief Class contructor + * @param uint8_t: socket where the sensor is connected + * @param float: gain of the stage for O2 Sensor + * @return void + */ +O2SensorClass::O2SensorClass(uint8_t _socket, float _gain) +{ + // Store the gain value of the stage + gain = _gain; + socket = _socket; +} + + +/*! + * @brief Switch ON the O2 Sensor and configure the multiplexor + * @param void + * @return void + */ +void O2SensorClass::ON(void) +{ + #if DEBUG_GASES > 1 + if (socket == SOCKET_E) + { + PRINTLN_GASES("O2 Sensor configured in the SOCKET_E"); + + } else if (socket == SOCKET_1) + { + PRINTLN_GASES("O2 Sensor configured in the SOCKET_1"); + } + else + { + PRINTLN_GASES("O2 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_1 in OEM platform or SOCKET_E in Plug&Sense! platform"); + } + #endif + + state = ON_STATE; + + // Configure the Analog Multiplexor to read from SOCKET1 + setMUX(); + delay(10); + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); +} + + +/*! + * @brief Switch OFF the O2 Sensor + * @param void + * @return void + */ +void O2SensorClass::OFF(void) +{ + state = OFF_STATE; +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage + * @param void + * @return the voltage read from the Sensor in mV + */ +float O2SensorClass::readVoltage(void) +{ + float analogValue = 0.0; + + // Get 100 samples + for (int i = 0; i < 100; i++) { + analogValue = analogValue + analogRead(ANALOG3); + delay(1); + } + + // Return the correspondig value + return analogValue = (analogValue / 100.0) * ANALOG_REFERENCE * 1000 / (1024.0 * gain); +} + + +/*! + * @brief Read the ADC of the waspmote and return concetration + * @param void + * @return The concentration value in ppm + */ +float O2SensorClass::readConcentration() +{ + float O2mV = readVoltage(); + float O2Val = (O2mV - values[0]) / slope - concentrations[0]; + + if ((O2Val > 0.0) && (O2Val < 100.0)) + { + // Value obtained from the datasheet without a calibration process + return O2Val; + } + else + { + #if DEBUG_GASES > 1 + PRINT_GASES("O2 concentration out of range"); + #endif + + // Out of range + return -1.0; + } +} + + +/*! + * @brief Prepare the calibration points and store them + * @param float[]: calValues: Y values of the function + * @param float[]: calConcentrations: X values of the function + * @return void + */ +void O2SensorClass::setCalibrationPoints( float calValues[], + float calConcentrations[]) +{ + values[0] = calValues[0]; + values[1] = calValues[1]; + + concentrations[0] = calConcentrations[0]; + concentrations[1] = calConcentrations[1]; + + slope = (values[1] - values[0]) / (concentrations[1] - concentrations[0]); +} + + +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Configures the multiplexer to read from the SOCKET_1 or SOCKET_2 + * @param void + * @return void + */ +void O2SensorClass::setMUX(void) +{ + if (socket == SOCKET_1) { + // Configurin the ANALOG MULTIPLEXER + digitalWrite(A2, 0); + digitalWrite(A1, 0); + digitalWrite(A0, 0); + digitalWrite(EN, 1); + } else { + // Configure the Analog Multiplexor to read from SOCKET_2 + digitalWrite(A2, 0); + digitalWrite(A1, 0); + digitalWrite(A0, 1); + digitalWrite(EN, 1); + } +} + + +//************************************************************************************ +// CO2 SENSOR CLASS +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== +/*! + * @brief Class contructor + * @param uint8_t: socket where the sensor is connected + * @return void + */ +CO2SensorClass::CO2SensorClass() +{ + // Default gain of the stage + gain = 1.08; +} + + +/*! + * @brief Class contructor + * @param uint8_t: socket where the sensor is connected + * @return void + */ +CO2SensorClass::CO2SensorClass(uint8_t _socket) +{ + // Default gain of the stage + gain = 1.08; +} + + +/*! + * @brief Class contructor + * @param uint8_t: _gain: gain of the stage + * @param uint8_t: _socket: socket where the sensor is connected + * @return void + */ +CO2SensorClass::CO2SensorClass(uint8_t _socket, uint8_t _gain) +{ + // Store the gain value of the stage + if (_gain > 5) + { + _gain = 5; + } + + socket = _socket; + gain = _gain; +} + + +/*! + * @brief Switch ON the CO2 sensor and configures the multiplexer + * @param void + * @return void + */ +void CO2SensorClass::ON() +{ + state = ON_STATE; + digitalWrite(SOCKET2_ON_PIN, HIGH); + + #if DEBUG_GASES > 1 + if (socket == SOCKET_E) + { + PRINTLN_GASES("CO2 Sensor configured in the SOCKET_E"); + + } else if (socket == SOCKET_1) + { + PRINTLN_GASES("CO2 Sensor configured in the SOCKET_2"); + } + else + { + PRINTLN_GASES("O2 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_2 in OEM platform or SOCKET_E in Plug&Sense! platform"); + } + #endif + + // Configure the Analog Multiplexor to read from SOCKET_2 + setMUX(); + delay(10); + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); +} + + +/*! + * @brief Switch OFF the CO2 sensor in SOCKET_2 + * @param void + * @return void + */ +void CO2SensorClass::OFF() +{ + state = OFF_STATE; + digitalWrite(SOCKET2_ON_PIN , LOW); +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage (in V) + * @param void + * @return The voltage read from the SOCKET_2 + */ +float CO2SensorClass::readVoltage() +{ + float analogValue = 0.0; + + for (int i = 0; i < 100; i++) { + analogValue = analogValue + analogRead(ANALOG3); + delay(1); + } + + // Return the correspondig value + return ((analogValue/100.0) * ANALOG_REFERENCE / (1024.0 * gain)); +} + + +/*! + * @brief Gets the concentration in PPMs from CO2 sensor + * @param void + * @return The value of the concetration read + */ +float CO2SensorClass::readConcentration() +{ + return getConcentration(readVoltage()); +} + + +/*! + * @brief Store the calibration points for CO2 sensor + * + * @param float calValues[]: Y values of the function + * @param float calConcentrations[]: X values of the function + * @param uint8_t numPoints_: the number of points to be used in calibration + * + * @return + * @arg '-1' if error + * @arg '0' if all OK + */ +int CO2SensorClass::setCalibrationPoints( float calValues[], + float calConcentrations[], + uint8_t numPoints_) +{ + return saveCalibrationPoints(calValues, calConcentrations, numPoints_); +} + + +/*! + * @brief Store the calibration points for CO2 sensor + * + * @param void + * + * @return + * @arg '-1' if error + * @arg '0' if all OK + */ +int CO2SensorClass::setCalibrationPoints() +{ + return saveCalibrationPoints(values, concentrations, numPoints); +} + + +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Configure the Analog Multiplexor to read from SOCKET_2 + * @param void + * @return void + */ +void CO2SensorClass::setMUX() +{ + // Configure the Analog Multiplexor to read from SOCKET2 + digitalWrite(A2, 0); + digitalWrite(A1, 0); + digitalWrite(A0, 1); + digitalWrite(EN, 1); +} + + +//************************************************************************************ +// SOCKET3 SENSOR CLASS - 1v8 Sensors can be connected in this socket +//************************************************************************************ +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +socket3Class::socket3Class() +{ + gain = 1.08; + loadResistor = 12.50; +} + + +/*! + * @brief Consturctor of the class + * + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: Load resistor to be configured + * + * @return void + */ +socket3Class::socket3Class(float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage (in V) + * @param void + * @return The voltage read from the sensor + */ +float socket3Class::readVoltage() +{ + + float analogValue = 0.0; + + for (int i = 0; i < 100; i++) { + analogValue += analogRead(ANALOG3); + delay(1); + } + + // Return the correspondig value + return ((analogValue / 100.0) * ANALOG_REFERENCE ) / (1024.0 * gain); +} + + +/*! + * @brief Get the resistance from the voltage value read + * @param float: input: voltage value read + * @return The resistance value + */ +float socket3Class::readResistance(float input) +{ + return (SOCKET3_SUPPLY * (loadResistor * 1000.0)) / (input) - (loadResistor * 1000.0); +} + + +/*! + * @brief Get the resistance from the voltage value read + * @param float: input: voltage value read + * @return The resistance value + */ +float socket3Class::readResistance() +{ + return (SOCKET3_SUPPLY * (loadResistor * 1000.0)) / (readVoltage()) - (loadResistor * 1000.0); +} + + +/*! + * @brief Get the concentration from teh resistance value read + * @param float: input: the resistance value + * @return concentration value claculated + */ +float socket3Class::readConcentration(float input) +{ + return getConcentration((input / Ro ) / 1000.0); +} + + +/*! + * @brief Get the concentration from teh resistance value read + * @param float: input: the resistance value + * @return concentration value claculated + */ +float socket3Class::readConcentration() +{ + return getConcentration((readResistance() / Ro ) / 1000.0); +} + + +/*! + * @brief Switch the SOCKET3 ON and configure the multiplexer + * @param void + * @return void + */ +void socket3Class::ON(void) +{ + state = ON_STATE; + digitalWrite(SOCKET3_ON_PIN , HIGH); + + #if DEBUG_GASES > 1 + if (socket == SOCKET_D) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_D"); + } else if (socket == SOCKET_1) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_3"); + } + else + { + PRINTLN_GASES("O2 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_3 in OEM platform or SOCKET_D in Plug&Sense! platform"); + } + #endif + + // Configure the Analog Multiplexor to read from SOCKET3 + setMUX(); + delay(10); + + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); + setResistor(SOCKET3_DIGIPOT_ADDRESS, loadResistor, SOCKET3_POTENTIOMETER); +} + + +/*! + * @brief Switch the SOCKET3 OFF and configure the multiplexe + * @param void + * @return void + */ +void socket3Class::OFF() +{ + state = OFF_STATE; + digitalWrite(SOCKET3_ON_PIN , LOW); +} + + +/*! + * @brief Configure the Analog Multiplexor to read from SOCKET3 + * @param void + * @return void + */ +void socket3Class::setMUX(void) +{ + digitalWrite(A2, 0); + digitalWrite(A1, 1); + digitalWrite(A0, 0); + digitalWrite(EN, 1); +} + + +//************************************************************************************ +// NO2 SENSOR CLASS - Derives from SOCKET3 CLASS +//************************************************************************************ +/*! + * @brief Class constructor + * @param void + * @return void + */ +NO2SensorClass::NO2SensorClass() +{ + //~ #if DEBUG_GASES > 1 + //~ PRINTLN_GASES("NO2 Sensor configured in the SOCKET_3 by default"); + //~ #endif + + gain = 1.08; + loadResistor = 12.50; +} + + +/*! + * @brief Class constructor + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +NO2SensorClass::NO2SensorClass(uint8_t _socket) +{ + gain = 1.08; + loadResistor = 12.50; + + #if DEBUG_GASES > 1 + if (_socket == SOCKET_D) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_D"); + } else if (_socket == SOCKET_3) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_3"); + } + else + { + PRINTLN_GASES("NO2 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_3 in OEM platform or SOCKET_D in Plug&Sense! platform"); + } + #endif +} + +/*! + * @brief Class constructor + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: Gain of the stage + * @param float _loadResistor: The resistance to be configured + * + * @return void + */ +NO2SensorClass::NO2SensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; + + #if DEBUG_GASES > 1 + if (_socket == SOCKET_D) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_D"); + } else if (_socket == SOCKET_3) + { + PRINTLN_GASES("NO2 Sensor configured in the SOCKET_3"); + } + else + { + PRINTLN_GASES("NO2 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_3 in OEM platform or SOCKET_D in Plug&Sense! platform"); + } + #endif +} + + +//************************************************************************************ +// SOCKET4 SENSOR CLASS - NH3 and CO sensors can be connected +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +socket4Class::socket4Class() +{ + gain = 1.08; + loadResistor = 12.5; +} + + +/*! + * @brief Constructor of the class + * + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +socket4Class::socket4Class(float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Switch ON the SOCKET4 and configure the multiplexer + * @param void + * @return void + */ +void socket4Class::ON() +{ + state = ON_STATE; + + #if DEBUG_GASES > 1 + if (socket == SOCKET_A) { + + PRINTLN_GASES("CO & NH3 Sensor configured in the SOCKET_A"); + } else if (socket == SOCKET_4) + { + PRINTLN_GASES("CO & NH3 Sensor configured in the SOCKET_4"); + } + else + { + PRINTLN_GASES("CO & NH3 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_4 in OEM platform or SOCKET_A in Plug&Sense! platform"); + } + #endif + + // Configure the Analog Multiplexor to read from SOCKET4 + setMUX(); + delay(10); + + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); + setResistor(SOCKET4_DIGIPOT_ADDRESS, loadResistor, SOCKET4_POTENTIOMETER); +} + + +/*! + * @brief Switch OFF the SOCKET4 + * @param void + * @return void + */ +void socket4Class::OFF() +{ + state = OFF_STATE; +} + +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Configure the Analog Multiplexor to read from SOCKET4 + * @param void + * @return void + */ +void socket4Class::setMUX() +{ + + digitalWrite(A2, 0); + digitalWrite(A1, 1); + digitalWrite(A0, 1); + digitalWrite(EN, 1); +} + + +//====================================================================== +// CO Sensor Class +//====================================================================== +/*! + * @brief Class contructor + * @param void + * @return void + */ +COSensorClass::COSensorClass() +{ + gain = 1.08; + loadResistor = 12.0; +} + + +/*! + * @brief Class contructor + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +COSensorClass::COSensorClass(uint8_t _socket) +{ + socket = _socket; +} + + +/*! + * @brief Class contructor + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +COSensorClass::COSensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Store the gain value of the stage + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage (in mV) + * @param void + * @return The value of the volatge read from sensor + */ +float COSensorClass::readVoltage() +{ + float analogValue; + + digitalWrite(SOCKET4_ON_PIN, HIGH); + delay(14); + digitalWrite(SOCKET4_ON_PIN, LOW); + delay(981); + digitalWrite(SOCKET4_CONTROL_PIN, HIGH); + delay(3); + analogValue = analogRead(ANALOG3); + delay(2); + digitalWrite(SOCKET4_CONTROL_PIN, LOW); + + // Return the correspondig value + return ((analogValue * ANALOG_REFERENCE * 1000) / (1024 * gain)); +} + + +/*! + * @brief Calculate the resistance from input voltage value + * @param float input: voltage value + * @return The resistance value calculated + */ +float COSensorClass::readResistance(float input) +{ + return (SOCKET4_SUPPLY * (loadResistor * 1000.0)) / (input / 1000.0) - (loadResistor * 1000.0); +} + + +/*! + * @brief Calculate the resistance from a read value + * @param void + * @return The resistance value calculated + */ +float COSensorClass::readResistance() +{ + + return (SOCKET4_SUPPLY * (loadResistor * 1000.0)) / (readVoltage() / 1000.0) - (loadResistor * 1000.0); +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param float input: voltage value + * @return The concentration value calculated + */ +float COSensorClass::readConcentration(float input) +{ + return getConcentration((input / Ro ) / 1000.0); +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param void + * @return The concentration value calculated + */ +float COSensorClass::readConcentration() +{ + return getConcentration((readResistance() / Ro ) / 1000.0); +} + + +//====================================================================== +// NH3 Sensor Class +//====================================================================== +/*! + * @brief Class contructor + * @param void + * @return void + */ +NH3SensorClass::NH3SensorClass() +{ + gain = 1.08; + loadResistor = 12.5; +} + + +/*! + * @brief Class contructor + * @param uint8_t socket: socket where the sensor is connected + * @return void + */ +NH3SensorClass::NH3SensorClass(uint8_t socket) +{ + gain = 1.08; + loadResistor = 12.5; +} + + +/*! + * @brief Class contructor + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +NH3SensorClass::NH3SensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Store the gain value of the stage + gain = _gain; + loadResistor = _loadResistor; +} + +/*! + * @brief Read the ADC of the waspmote and return a voltage (in mV) + * @param void + * @return The voltage value read from the ADC + */ +float NH3SensorClass::readVoltage() +{ + + float analogValue = 0.0; + + for (int i = 0; i < 5; i++) { + + digitalWrite(SOCKET4_ON_PIN, HIGH); // <-- VCC switch ON + delay(2); + digitalWrite(SOCKET4_CONTROL_PIN, HIGH); // CONTROL switch ON + delay(4); + analogValue += analogRead(ANALOG3); // read value + delay(1); + digitalWrite(SOCKET4_CONTROL_PIN, LOW); + delay(7); + digitalWrite(SOCKET4_ON_PIN, LOW); + delay(235); + } + + return ( ((analogValue/5.0) * ANALOG_REFERENCE * 1000) / (1024 * gain) ); +} + +/*! + * @brief Get the resistance from the voltage value input + * @param float: input: voltage value read + * @return The resistance value + */ +float NH3SensorClass::readResistance(float input) +{ + return (SOCKET4_SUPPLY * (loadResistor * 1000.0)) / (input / 1000.0) - (loadResistor * 1000.0); +} + + +/*! + * @brief Get the resistance from the voltage value read + * @param void + * @return The resistance value + */ +float NH3SensorClass::readResistance() +{ + return (SOCKET4_SUPPLY * (loadResistor * 1000.0)) / (readVoltage() / 1000.0) - (loadResistor * 1000.0); +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param float input: voltage value + * @return the concentration value calculated + */ +float NH3SensorClass::readConcentration(float input) +{ + return getConcentration((input / Ro ) / 1000.0); +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param void + * @return The concentration value calculated + */ +float NH3SensorClass::readConcentration() +{ + return getConcentration((readResistance() / Ro ) / 1000.0); +} + +//************************************************************************************ +// SOCKET5 SENSOR CLASS - NO2 Sensor Class +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +socket5Class::socket5Class() +{ + gain = 1.08; + loadResistor = 12.5; +} + + +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +socket5Class::socket5Class(float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Switch ON the SOCKET5 and configure the multiplexer + * @param void + * @return void + */ +void socket5Class::ON() +{ + state = ON_STATE; + digitalWrite(SOCKET5_ON_PIN , HIGH); + + #if DEBUG_GASES > 1 + if (socket == SOCKET_B) + { + PRINTLN_GASES("VOC & O3 Sensor configured in the SOCKET_B"); + } + else if (socket == SOCKET_5) + { + PRINTLN_GASES("VOC & O3 Sensor configured in the SOCKET_5"); + } + else + { + PRINTLN_GASES("VOC & O3 Sensor wrong configured"); + PRINTLN_GASES("Use SOCKET_5 in OEM platform or SOCKET_B in Plug&Sense! platform"); + } + #endif + + // Configure the Analog Multiplexor to read from SOCKET5 + setMUX(); + delay(10); + + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); + setResistor(SOCKET5_DIGIPOT_ADDRESS, loadResistor, SOCKET5_POTENTIOMETER); +} + + +/*! + * @brief Switch OFF the SOCKET5 + * @param void + * @return void + */ +void socket5Class::OFF() +{ + state = OFF_STATE; + digitalWrite(SOCKET5_ON_PIN , LOW); +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage (in V) + * @param void + * @return The value of the volatge read from sensor + */ +float socket5Class::readVoltage() +{ + float analogValue = 0.0; + + for (int i = 0; i < 100; i++) { + analogValue += analogRead(ANALOG3); + delay(1); + } + + // Return the correspondig value + return ((analogValue / 100.0) * ANALOG_REFERENCE ) / (1024.0 * gain); +} + + +/*! + * @brief Calculate the resistance from input voltage value + * @param float input: voltage value + * @return The resistance value calculated + */ +float socket5Class::readResistance(float input) +{ + return (SOCKET5_SUPPLY * (loadResistor * 1000.0)) / (input) - (loadResistor * 1000.0); +} + + +/*! + * @brief Calculate the resistance from a read voltage + * @param void + * @return The resistance value calculated + */ +float socket5Class::readResistance() +{ + return (SOCKET5_SUPPLY * (loadResistor * 1000.0)) / (readVoltage()) - (loadResistor * 1000.0); +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param float input: voltage value + * @return The concentration value calculated + */ +float socket5Class::readConcentration(float input) +{ + return getConcentration((input / Ro ) / 1000.0); +} + + +/*! + * @brief Calculate the concentration from a read resistance value + * @param void + * @return The concentration value calculated + */ +float socket5Class::readConcentration() +{ + return getConcentration((readResistance() / Ro ) / 1000.0); +} + +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Configure the Analog Multiplexor to read from SOCKET5 + * @param void + * @return void + */ +void socket5Class::setMUX() +{ + digitalWrite(A2, 1); + digitalWrite(A1, 0); + digitalWrite(A0, 0); + digitalWrite(EN, 1); +} + + +//====================================================================== +// VOC Sensor Class +//====================================================================== +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +VOCSensorClass::VOCSensorClass() +{ + // Default values. Do not change except for expert user. + socket = SOCKET_5; + gain = 1.08; + loadResistor = 12.5; +} + + +/*! + * @brief Constructor of the class + * @param uint8_t socket: socket where the sensor is connected + * @return void + */ +VOCSensorClass::VOCSensorClass(uint8_t _socket) +{ + // Default values. Do not change except for expert user. + gain = 1.08; + loadResistor = 12.5; + socket = _socket; +} + + +/*! + * @brief Constructor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +VOCSensorClass::VOCSensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; + socket = _socket; +} + + +//====================================================================== +// O3 Sensor Class +//====================================================================== +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +O3SensorClass::O3SensorClass() +{ + // Default values. Do not change except for expert user. + gain = 1.08; + loadResistor = 12.5; + socket = SOCKET_5; +} + + +/*! + * @brief Constructor of the class + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +O3SensorClass::O3SensorClass(uint8_t _socket) +{ + // Default values. Do not change except for expert user. + gain = 1.08; + loadResistor = 12.5; + socket = _socket; +} + + +/*! + * @brief Constructor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +O3SensorClass::O3SensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + gain = _gain; + loadResistor = _loadResistor; + socket = _socket; +} + + +//************************************************************************************ +// SOCKET6 SENSOR CLASS +//************************************************************************************ +//====================================================================== +// PUBLIC METHODS +//====================================================================== + +/*! + * @brief Constructor of the class + * @param void + * @return void + */ +sockets5VClass::sockets5VClass() +{ + // Default Gain and Load Resistor + socket = SOCKET_6; + gain = 1.08; + loadResistor = 5.45; +} + +/*! + * @brief Constructor of the class + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +sockets5VClass::sockets5VClass(uint8_t _socket) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = 1.08; + loadResistor = 5.45; +} + +/*! + * @brief Constructor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: load resistor to be configured + * + * @return void + */ +sockets5VClass::sockets5VClass(uint8_t _socket, float _gain , float _loadResistor) +{ + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Switch ON the SOCKET6 and configure the multiplexer + * @param void + * @return void + */ +void sockets5VClass::ON() +{ + if ((socket == SOCKET_6) || (socket == SOCKET_F)) + { + state = ON_STATE; + digitalWrite(SOCKET6_ON_PIN , HIGH); + + #if DEBUG_GASES > 1 + PRINT_GASES("SOCKET_6 and SOCKET_7 (5V Sensors) switched ON. "); + PRINTLN_GASES("Configuring Amplifier stage and Load Resistor for SOCKET_6 "); + #endif + } + else if (socket == SOCKET_7) + { + state = ON_STATE; + digitalWrite(SOCKET7_ON_PIN , HIGH); + + #if DEBUG_GASES > 1 + PRINT_GASES("SOCKET_6 and SOCKET_7 (5V Sensors) switched ON. "); + PRINTLN_GASES("Configuring Amplifier stage and Load Resistor for SOCKET_7 "); + #endif + } + + // Configure the Analog Multiplexor to read from SOCKET_6 or SOCKET_7 + setMUX(); + delay(10); + + if ((socket == SOCKET_6) || (socket == SOCKET_F)) + { + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); + setResistor(SOCKET6_DIGIPOT_ADDRESS, loadResistor, SOCKET6_POTENTIOMETER); + } + else if (socket == SOCKET_7) + { + setAmplifier(GAIN_DIGIPOT_ADDRESS, gain); + setResistor(SOCKET7_DIGIPOT_ADDRESS, loadResistor, SOCKET7_POTENTIOMETER); + } +} + + +/*! + * @brief Switch OFF the SOCKET6 + * @param void + * @return void + */ +void sockets5VClass::OFF() +{ + if ((socket == SOCKET_6) || (socket == SOCKET_F)) + { + state = OFF_STATE; + digitalWrite(SOCKET6_ON_PIN , LOW); + } + else if (socket == SOCKET_7) + { + state = OFF_STATE; + digitalWrite(SOCKET7_ON_PIN , LOW); + } +} + + +/*! + * @brief Read the ADC of the waspmote and return a voltage + * @param void + * @return The value of the volatge read from sensor + */ +float sockets5VClass::readVoltage() +{ + float analogValue = 0.0; + + for (int i = 0; i < 100; i++) + { + analogValue += analogRead(ANALOG3); + delay(1); + } + + // Return the correspondig value + return ((analogValue / 100.0) * ANALOG_REFERENCE / ( 1024 * gain)); +} + + +/*! + * @brief Get the resistance from the voltage value read + * @param float: input: voltage value read + * @return The resistance value + */ +float sockets5VClass::readResistance(float input) +{ + return (SOCKET6_SUPPLY * (loadResistor * 1000.0)) / (input) - (loadResistor * 1000.0) ; +} + + +/*! + * @brief Get the resistance from the voltage value read + * @param void + * @return The resistance value + */ +float sockets5VClass::readResistance() +{ + return (SOCKET6_SUPPLY * (loadResistor * 1000.0)) / (readVoltage()) - (loadResistor * 1000.0) ; +} + + +/*! + * @brief Calculate the concentration from input resistance value + * @param float input: voltage value + * @return The concentration value calculated + */ +float sockets5VClass::readConcentration(float input) +{ + return getConcentration((input / Ro ) / 1000.0); +} + + +/*! + * @brief Calculate the concentration from read resistance value + * @param void + * @return The concentration value calculated + */ +float sockets5VClass::readConcentration() +{ + return getConcentration((readResistance() / Ro ) / 1000.0); +} + + +//====================================================================== +// PRIVATE METHODS +//====================================================================== +/*! + * @brief Configure the Analog Multiplexor to read from SOCKET6 + * @param void + * @return void + */ +void sockets5VClass::setMUX() +{ + if ((socket == SOCKET_6) || (socket == SOCKET_F)) + { + // Configurin the ANALOG MULTIPLEXER + digitalWrite(A2, 1); + digitalWrite(A1, 0); + digitalWrite(A0, 1); + digitalWrite(EN, 1); + } + else if (socket == SOCKET_7) + { + // Configurin the ANALOG MULTIPLEXER + digitalWrite(A2, 1); + digitalWrite(A1, 1); + digitalWrite(A0, 0); + digitalWrite(EN, 1); + } +} + + +/*! + * @brief Consturctor of the class + * + * @param void + * @return void + */ +CH4SensorClass::CH4SensorClass() +{ + // Default Gain and Load Resistor + socket = SOCKET_6; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * @param uint8_t _socket: socket where the sensor is connected * + * @return void + */ +CH4SensorClass::CH4SensorClass(uint8_t _socket) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: Load resistor to be configured + * + * @return void + */ +CH4SensorClass::CH4SensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Consturctor of the class + * @param void + * @return void + */ +APSensorClass::APSensorClass() +{ + // Default Gain and Load Resistor + socket = SOCKET_6; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +APSensorClass::APSensorClass(uint8_t _socket) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: Load resistor to be configured + * + * @return void + */ +APSensorClass::APSensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Consturctor of the class + * + * @param void + * @return void + */ +LPGSensorClass::LPGSensorClass() +{ + // Default Gain and Load Resistor + socket = SOCKET_6; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +LPGSensorClass::LPGSensorClass(uint8_t _socket) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: Load resistor to be configured + * + * @return void + */ +LPGSensorClass::LPGSensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + + +/*! + * @brief Consturctor of the class + * @param void + * @return void + */ +SVSensorClass::SVSensorClass() +{ + // Default Gain and Load Resistor + socket = SOCKET_6; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * @param uint8_t _socket: socket where the sensor is connected + * @return void + */ +SVSensorClass::SVSensorClass(uint8_t _socket) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = 1.08; + loadResistor = 5.45; +} + + +/*! + * @brief Consturctor of the class + * + * @param uint8_t _socket: socket where the sensor is connected + * @param float _gain: gain of the stage to be configured + * @param float _loadResistor: Load resistor to be configured + * + * @return void + */ +SVSensorClass::SVSensorClass(uint8_t _socket, float _gain, float _loadResistor) +{ + // Default Gain and Load Resistor + socket = _socket; + gain = _gain; + loadResistor = _loadResistor; +} + +// Instance of the GasSensorClass +GasSensorClass Gases = GasSensorClass(); + diff --git a/libraries/SensorGas_v30/WaspSensorGas_v30.h b/libraries/SensorGas_v30/WaspSensorGas_v30.h new file mode 100755 index 0000000..7aa42ef --- /dev/null +++ b/libraries/SensorGas_v30/WaspSensorGas_v30.h @@ -0,0 +1,461 @@ +/*! \file WaspSensorGas_v30.h + * \brief Library for managing the Gas Sensor Board v30 + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Ahmad Saad +*/ + + /*! \def WaspSensorGas_h + \brief The library flag + + */ +#ifndef WaspSensorGas_v30_h +#define WaspSensorGas_v30_h + +//********************************************************************** +// Includes +//********************************************************************** +#include + +// TSL2561 Sensor for reading luxes value +#include "TSL2561.h" +// BME280 library for reading temperature, humidity and pressure values +#include "BME280.h" +// Ultrasound library for readign distance +#include "UltrasoundSensor.h" + +//********************************************************************** +// DEFINES OF CALIBRATION POINTS +//********************************************************************** +#define POINT_1 0x00 +#define POINT_2 0x01 +#define POINT_3 0x02 +#define POINT_4 0x03 +#define POINT_5 0x04 +#define POINT_6 0x05 +#define POINT_7 0x06 +#define POINT_8 0x07 +#define POINT_9 0x08 +#define POINT_10 0x09 + +//********************************************************************** +// DEFINES FOR POWER CONTROL DIGITAL PINS +//********************************************************************** +#define SOCKET2_ON_PIN DIGITAL7 +#define SOCKET3_ON_PIN DIGITAL6 +#define SOCKET4_ON_PIN DIGITAL5 +#define SOCKET5_ON_PIN DIGITAL4 +#define SOCKET6_ON_PIN DIGITAL3 +#define SOCKET7_ON_PIN DIGITAL2 +#define SOCKET4_CONTROL_PIN DIGITAL8 + +//********************************************************************** +// DEFINES FOR MULTIPLEXER CONTROL +//********************************************************************** +#define A2 19 // ANALOG6 +#define A1 17 // ANALOG4 +#define A0 15 // ANALOG2 +#define EN DIGITAL1 // ENABLE MULTIPLEXOR + +//********************************************************************** +// DEFINES FOR DIGIPOT ADDRESSES +//********************************************************************** +#define GAIN_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT3 +#define SOCKET3_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT3 +#define SOCKET4_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT1 +#define SOCKET5_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT2 +#define SOCKET6_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT1 +#define SOCKET7_DIGIPOT_ADDRESS I2C_ADDRESS_GASES_DIGIPOT2 + +// ENABLE I2C ISOLATOR +#define I2C_PIN_OE 14 + +//********************************************************************** +// SENSOR STATE +//********************************************************************** +#define ON_STATE 0x01 +#define OFF_STATE 0x00 +#define MAX_POINTS 10 // MAX calibration points +#define ANALOG_REFERENCE 2.56 +#define SOCKET7_SUPPLY 5.0 +#define SOCKET6_SUPPLY 5.0 +#define SOCKET5_SUPPLY 2.5 +#define SOCKET3_SUPPLY 1.8 +#define SOCKET4_SUPPLY 5.0 + +#define SOCKET3_POTENTIOMETER 0x00 +#define SOCKET4_POTENTIOMETER 0x00 +#define SOCKET5_POTENTIOMETER 0x10 +#define SOCKET6_POTENTIOMETER 0x10 +#define SOCKET7_POTENTIOMETER 0x00 + + +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_GASES 0 +#define PRINT_GASES(str) USB.print(F("[GASES] ")); USB.print(str); +#define PRINT_GASES_VAL(val) USB.print(float(val)); +#define PRINTLN_GASES(str) USB.print(F("[GASES] ")); USB.println(str); +#define PRINTLN_GASES_VAL(val) USB.println(float(val)); + +class GasSensorClass +{ + //****************************************************************** + // Public methods of the class + //****************************************************************** + public: + + // Class constructor + GasSensorClass(); + //Power Control + void ON(); + void OFF(); + + // Atributes of the class + int state; + float gain; + float loadResistor; + float Ro; + uint8_t socket; + + // Public methos of the class + float readVoltage(); + float getPPM(); + float getResistance(); + + float getTemperature(); + float getHumidity(); + float getPressure(); + float getLuxes(uint8_t); + float getDistance(); + + float readConcentration(float); + float getConcentration(float input); + + int setCalibrationPoints(); + int setCalibrationPoints(float calValues[], float calConcentrations[], uint8_t numPoints_); + int saveCalibrationPoints(float calValues[], float calConcentrations[], uint8_t numPoints_); + + // Arrays for point to point calibration + float values[MAX_POINTS]; + float concentrations[MAX_POINTS]; + uint8_t numPoints; + + //****************************************************************** + // Protected methods of the class + //****************************************************************** + protected: + + // Configure the gain of the amplifier stage + void setAmplifier(uint8_t address, float value); + // Configure the load resistance + void setResistor(uint8_t address, float value, int pot); + + //****************************************************************** + // Private methods of the class + //****************************************************************** + + private: + + // Configures the ANALOG MULTIPLEXER for each socket + void setMUX(); +}; + +//********************************************************************** +// O2Sensor Class derives directly from the GasSensor Class +// In the SOCKET1, only this sensor can be connected +//********************************************************************** +class O2SensorClass : public GasSensorClass +{ + public: + + // Class constructors + O2SensorClass(); + O2SensorClass(uint8_t); + O2SensorClass(uint8_t, float); + + //Power Control + void ON(); + void OFF(); + + // Public methods for getting sensor values + float readConcentration(); + float readVoltage(); + + // Configure the calibration line + void setCalibrationPoints(float calVoltages[], float calConcentrations[]); + + private: + + // Configures the ANALOG MULTIPLEXER for SOCKET1 + void setMUX(); + // Private atributes of the class + float slope; +}; + +//********************************************************************** +// SOCKET2 Class for managing the CO2 Sensor +//********************************************************************** +class CO2SensorClass : public GasSensorClass +{ + public: + + // Class constrcutors + CO2SensorClass(); + CO2SensorClass(uint8_t); + CO2SensorClass(uint8_t, uint8_t); + + //Power Control + void ON(); + void OFF(); + + // Public methods for getting sensor values + float readVoltage(); + float readConcentration(); + int setCalibrationPoints(); + int setCalibrationPoints(float calValues[], float calConcentrations[], uint8_t numPoints_); + + private: + + // Configures the ANALOG MULTIPLEXER for SOCKET2 + void setMUX(); +}; + +//********************************************************************** +// SOCKET3 Class for managing NO2 Sensor +// 1v8 heather sensors +//********************************************************************** +class socket3Class : public GasSensorClass +{ + public: + // Class constrcutors + socket3Class(); + socket3Class(float, float); + + //Power Control + void ON(); + void OFF(); + + // Public methods for getting sensor values + float readVoltage(); + float readResistance(float); + float readConcentration(float); + + float readResistance(); + float readConcentration(); + + private: + // Configures the ANALOG MULTIPLEXER for SOCKET3 + void setMUX(); +}; + +class NO2SensorClass : public socket3Class +{ + public: + NO2SensorClass(); + NO2SensorClass(uint8_t); + NO2SensorClass(uint8_t, float, float); + + private: + +}; + +//********************************************************************** +// SOCKET4 Class for managing CO Sensor and NH3 Sensor +// Pulse reading sensor +//********************************************************************** +class socket4Class : public GasSensorClass +{ + public: + // Class constructors + socket4Class(); + socket4Class(float, float); + float readVoltage(); + + //Power Control + void ON(); + void OFF(); + + protected: + // Configures the ANALOG MULTIPLEXER for SOCKET4 + void setMUX(); +}; + +class COSensorClass : public socket4Class +{ + public: + + // Class constructors + COSensorClass(); + COSensorClass(uint8_t); + COSensorClass(uint8_t, float, float); + + // Public methods for getting sensor values + float readResistance(float); + float readConcentration(float); + float readVoltage(); + + float readResistance(); + float readConcentration(); +}; + +class NH3SensorClass : public socket4Class +{ + public: + + NH3SensorClass(); + NH3SensorClass(uint8_t); + NH3SensorClass(uint8_t, float, float); + + // Public methods for getting sensor values + float readResistance(float); + float readConcentration(float); + float readVoltage(); + + float readResistance(); + float readConcentration(); +}; + +//********************************************************************** +// SOCKET5 Class for managing VOC and O3 Sensors +// 2v5 heater sensors +//********************************************************************** +class socket5Class : public GasSensorClass +{ + public: + + // Class constrcutors + socket5Class(); + socket5Class(float, float); + + //Power Control + void ON(); + void OFF(); + + // Public methods for getting sensor values + float readVoltage(); + float readResistance(float input); + float readConcentration(float); + + float readResistance(); + float readConcentration(); + + private: + + // Configures the ANALOG MULTIPLEXER for SOCKET5 + void setMUX(); + +}; + +class O3SensorClass : public socket5Class +{ + public: + + O3SensorClass(); + O3SensorClass(uint8_t); + O3SensorClass(uint8_t, float, float); +}; + +class VOCSensorClass : public socket5Class +{ + public: + + VOCSensorClass(); + VOCSensorClass(uint8_t); + VOCSensorClass(uint8_t, float, float); + +}; + +//********************************************************************** +// SOCKET6 Class for managing CH4, API, APII, SV and LPG Sensors +// 5V heating sensors +//********************************************************************** +class sockets5VClass : public GasSensorClass +{ + public: + + // Class constrcutors + sockets5VClass(); + sockets5VClass(uint8_t); + sockets5VClass(uint8_t, float , float); + + //Power Control + void ON(); + void OFF(); + + // Public methods for getting sensor values + float readVoltage(); + + float readResistance(); + float readResistance(float); + + float readConcentration(); + float readConcentration(float); + + private: + + // Configures the ANALOG MULTIPLEXER for SOCKET6 + void setMUX(); +}; + +class CH4SensorClass : public sockets5VClass +{ + public: + + CH4SensorClass(); + CH4SensorClass(uint8_t); + CH4SensorClass(uint8_t, float, float); +}; + +class APSensorClass : public sockets5VClass +{ + public: + + APSensorClass(); + APSensorClass(uint8_t); + APSensorClass(uint8_t, float, float); +}; + +class LPGSensorClass : public sockets5VClass +{ + public: + + LPGSensorClass(); + LPGSensorClass(uint8_t); + LPGSensorClass(uint8_t, float, float); +}; + + +class SVSensorClass : public sockets5VClass +{ + public: + + SVSensorClass(); + SVSensorClass(uint8_t); + SVSensorClass(uint8_t, float, float); +}; + +extern GasSensorClass Gases; + +#endif + diff --git a/libraries/SensorGas_v30/keywords.txt b/libraries/SensorGas_v30/keywords.txt new file mode 100644 index 0000000..5d858e4 --- /dev/null +++ b/libraries/SensorGas_v30/keywords.txt @@ -0,0 +1,79 @@ +# Gas_v30 keywords # + +SOCKET_1 LITERAL1 +SOCKET_2 LITERAL1 +SOCKET_3 LITERAL1 +SOCKET_4 LITERAL1 +SOCKET_5 LITERAL1 +SOCKET_6 LITERAL1 +SOCKET_7 LITERAL1 +SOCKET_8 LITERAL1 + +SOCKET_A LITERAL1 +SOCKET_B LITERAL1 +SOCKET_C LITERAL1 +SOCKET_D LITERAL1 +SOCKET_E LITERAL1 +SOCKET_F LITERAL1 + +POINT_1 LITERAL1 +POINT_2 LITERAL1 +POINT_3 LITERAL1 +POINT_4 LITERAL1 +POINT_5 LITERAL1 +POINT_6 LITERAL1 +POINT_7 LITERAL1 +POINT_8 LITERAL1 +POINT_9 LITERAL1 +POINT_10 LITERAL1 + + +WaspSensorGas_v30 KEYWORD2 +ON KEYWORD2 +OFF KEYWORD2 + + +GasSensorClass KEYWORD2 +getTemperature KEYWORD2 +getPressure KEYWORD2 +getHumidity KEYWORD2 +readConcentration KEYWORD2 +setCalibrationPoints KEYWORD2 +readVoltage KEYWORD2 +readResistance KEYWORD2 +getLuxes KEYWORD2 +getDistance KEYWORD2 + +O2SensorClass KEYWORD2 +CO2SensorClass KEYWORD2 +NO2SensorClass KEYWORD2 +COSensorClass KEYWORD2 +NH3SensorClass KEYWORD2 +O3SensorClass KEYWORD2 +VOCSensorClass KEYWORD2 +CH4SensorClass KEYWORD2 +LPGSensorClass KEYWORD2 +APSensorClass KEYWORD2 +SVSensorClass KEYWORD2 + +socket1Class KEYWORD2 +socket2Class KEYWORD2 +socket3Class KEYWORD2 +socket4Class KEYWORD2 +socket5Class KEYWORD2 +socket6Class KEYWORD2 +socket7Class KEYWORD2 + +Gases KEYWORD1 + +O2Sensor KEYWORD1 +CO2Sensor KEYWORD1 +NO2Sensor KEYWORD1 +COSensor KEYWORD1 +NH3Sensor KEYWORD1 +VOCSensor KEYWORD1 +O3Sensor KEYWORD1 +CH4Sensor KEYWORD1 +LPGSensor KEYWORD1 +APPSensor KEYWORD1 +SVSensor KEYWORD1 diff --git a/libraries/SensorParking/WaspSensorParking.cpp b/libraries/SensorParking/WaspSensorParking.cpp index 28bc81b..3286cac 100755 --- a/libraries/SensorParking/WaspSensorParking.cpp +++ b/libraries/SensorParking/WaspSensorParking.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Manuel Calahorra */ @@ -61,7 +61,7 @@ WaspSensorParking::WaspSensorParking() PWR.setSensorPower(SENS_5V, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_PARKING; + WaspRegisterSensor |= REG_PARKING; } // Public Methods ////////////////////////////////////////////////////////////// diff --git a/libraries/SensorParking/WaspSensorParking.h b/libraries/SensorParking/WaspSensorParking.h index d9f4fc7..fe85303 100755 --- a/libraries/SensorParking/WaspSensorParking.h +++ b/libraries/SensorParking/WaspSensorParking.h @@ -1,7 +1,7 @@ /*! \file WaspSensorParking.h \brief Library for managing the Parking Sensor Board - Copyright (C) 2013 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra diff --git a/libraries/SensorParking/keywords.txt b/libraries/SensorParking/keywords.txt index e941ff5..d50247c 100644 --- a/libraries/SensorParking/keywords.txt +++ b/libraries/SensorParking/keywords.txt @@ -54,4 +54,4 @@ readParking KEYWORD2 readParkingSetReset KEYWORD2 estimateState KEYWORD2 -SensorParking KEYWORD3 +SensorParking KEYWORD1 diff --git a/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.cpp b/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.cpp index a365521..471370b 100755 --- a/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.cpp +++ b/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascón * Implementation: Alberto Bielsa, Manuel Calahorra */ @@ -40,7 +40,7 @@ WaspSensorPrototyping_v20::WaspSensorPrototyping_v20() PWR.setSensorPower(SENS_5V, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_PROTOTYPING; + WaspRegisterSensor |= REG_PROTOTYPING; } // Public Methods ////////////////////////////////////////////////////////////// @@ -108,14 +108,21 @@ float WaspSensorPrototyping_v20::readADC(void) uint16_t val; uint8_t i = 0; - if( !Wire.I2C_ON ) Wire.begin(); + if (!Wire.isON) + { + Wire.begin(); + } delay(100); Wire.requestFrom(B0010100, 2); - while(Wire.available()){ + + while (Wire.available()) + { valor[i] = Wire.receive(); i++; } - if( Wire.I2C_ON && !ACC.isON && RTC.isON!=1){ + + if (Wire.isON && !ACC.isON && RTC.isON!=1) + { PWR.closeI2C(); RTC.setMode(RTC_OFF, RTC_I2C_MODE); } diff --git a/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.h b/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.h index feac6e6..0c3f33b 100755 --- a/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.h +++ b/libraries/SensorPrototyping_v20/WaspSensorPrototyping_v20.h @@ -1,7 +1,7 @@ /*! \file WaspSensorPrototyping_v20.h \brief Library for managing the Prototyping v2.0 Sensor Board - Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,10 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 0.8 - - Design: David Gascón - + Version: 3.0 + Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra */ diff --git a/libraries/SensorPrototyping_v20/keywords.txt b/libraries/SensorPrototyping_v20/keywords.txt index bdf1ae6..821d775 100644 --- a/libraries/SensorPrototyping_v20/keywords.txt +++ b/libraries/SensorPrototyping_v20/keywords.txt @@ -7,4 +7,4 @@ setBoardMode KEYWORD2 readADC KEYWORD2 readAnalogSensor KEYWORD2 -SensorProtov20 KEYWORD3 +SensorProtov20 KEYWORD1 diff --git a/libraries/SensorRadiation/WaspSensorRadiation.cpp b/libraries/SensorRadiation/WaspSensorRadiation.cpp index 5825532..5a15445 100755 --- a/libraries/SensorRadiation/WaspSensorRadiation.cpp +++ b/libraries/SensorRadiation/WaspSensorRadiation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 0.1 + * Version: 3.0 * Design: David Gascón * Implementation: Marcos Yarza, Javier Siscart */ @@ -52,7 +52,7 @@ WaspRadiationBoard::WaspRadiationBoard() ledArray[4] = DIGITAL3; // update Waspmote Control Register - WaspRegister |= REG_RADIATION; + WaspRegisterSensor |= REG_RADIATION; } @@ -241,7 +241,7 @@ float WaspRadiationBoard::getCPM(long time) float k=0; float minute = 60000; unsigned long previous=millis(); - + enableInterrupts(RAD_INT); while( (millis()-previous. - Version: 0.1 + Version: 3.0 Design: David Gascón Implementation: Marcos Yarza, Javier Siscart diff --git a/libraries/SensorRadiation/keywords.txt b/libraries/SensorRadiation/keywords.txt index 48ce415..0c66e44 100644 --- a/libraries/SensorRadiation/keywords.txt +++ b/libraries/SensorRadiation/keywords.txt @@ -23,4 +23,4 @@ getCPM KEYWORD2 ledBar KEYWORD2 WaspSensorRadiation KEYWORD2 -RadiationBoard KEYWORD3 +RadiationBoard KEYWORD1 diff --git a/libraries/SensorSW/TurbiditySensor.cpp b/libraries/SensorSW/TurbiditySensor.cpp index dc69343..f63d580 100755 --- a/libraries/SensorSW/TurbiditySensor.cpp +++ b/libraries/SensorSW/TurbiditySensor.cpp @@ -1,7 +1,7 @@ /*! \file TurbiditySensor.cpp - \brief Library for managing the Smart Water Turbidity Sensor Board + \brief Library for managing the Smart Water Turbidity Sensor - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.1 Design: David Gascón Implementation: Ahmad Saad */ @@ -32,15 +32,24 @@ #include "TurbiditySensor.h" +/*********************************************************************** + * Class contructors + ***********************************************************************/ +turbidityClass::turbidityClass() +{ + // The sensor comes from factory with a default address + // This direction can be changed using the function configureSensorAddress +} + /*********************************************************************** * Class contructors ***********************************************************************/ -turbiditySensorClass::turbiditySensorClass() +turbidityClass::turbidityClass(uint8_t address) { // The sensor comes from factory with a default address // This direction can be changed using the function configureSensorAddress - ModbusMaster485 sensor(DEFAULT_ADDRESS); + sensor = ModbusMaster(RS232_COM, address); } /*********************************************************************** @@ -53,49 +62,46 @@ turbiditySensorClass::turbiditySensorClass() //! Param : void //! Returns: "0" if no error, "-1" if error //!************************************************************* -char turbiditySensorClass::ON() +uint8_t turbidityClass::ON() { - char result = -1; - - // Switch ON the power supply - PWR.setSensorPower(SENS_5V, SENS_ON); - // The sensor uses 9600 bps speed communication - sensor.begin(9600); - - // Important: Reset the registers of the sensor - resetSensor(); + + uint8_t result; - // Configure the sensor address - result = configureSensorAddress(SENSOR_ADDRESS); + delay(10); -#if DEBUG_MODE == 1 - // Check that the address has been well configured - if (result == -1) { - // If no response from the slave, print an error message - USB.println(F("Communication Error. The address hasn't been configured.")); - } - else { - USB.println(F("Sensor address configured correctly")); + if (_boot_version < 'H') + { + sensor = ModbusMaster(RS485_COM); + + // The sensor uses 9600 bps speed communication + sensor. begin(9600); + + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + + WaspRegister |= REG_RS485; } -#endif - - delay(10); + else + { + sensor = ModbusMaster(RS232_COM); - // Clear the Modbus buffers - clearBuffer(); + // The sensor uses 9600 bps speed communication + sensor.begin(9600, 1); + Utils.setMuxAux1(); // set Auxiliar1 socket - // Configure the type measurement of the temperature sensor - typeMeasurementConfiguration(TEMP_TYPE_CON, 0x0003); - delay(20); - clearBuffer(); + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + WaspRegister |= REG_SOCKET1; - // Configue the type measurement of the turbidity sensor - typeMeasurementConfiguration(TURB_TYPE_CON, 0x0003); - delay(20); - clearBuffer(); + // Turbidity Sensor ON + pinMode(PWR_TURBIDITY, OUTPUT); + digitalWrite(PWR_TURBIDITY, HIGH); + + } - // Configure the average measurement - average(25); + delay(100); + + result = init(); return result; } @@ -107,10 +113,16 @@ char turbiditySensorClass::ON() //! Param : void //! Returns: void //!************************************************************* -void turbiditySensorClass::OFF() -{ - // Supply the sensor using 5V output - PWR.setSensorPower(SENS_5V, SENS_OFF); +void turbidityClass::OFF() +{ + if (_boot_version >= 'H') + { + + // Turbidity Sensor ON + pinMode(PWR_TURBIDITY, OUTPUT); + digitalWrite(PWR_TURBIDITY, LOW); + + } } @@ -119,11 +131,11 @@ void turbiditySensorClass::OFF() //********************************************************************** //!************************************************************* //! Name: readTurbidity() -//! Description: Reads the turbidity value from the sensor +//! Description: Read the turbidity value from the sensor //! Param : void //! Returns: "0" if no error, "-1" if error //!************************************************************* -uint8_t turbiditySensorClass::readTurbidity() +uint8_t turbidityClass::readTurbidity() { //////////////////////////////////////////////////////////////////// // This declaration is used to generate a float from two integers @@ -136,7 +148,32 @@ uint8_t turbiditySensorClass::readTurbidity() } foo; - //readTemperature(); + + if (_boot_version < 'H') + { + // The sensor uses 9600 bps speed communication + sensor.begin(9600); + + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + + WaspRegister |= REG_RS485; + } + else + { + // The sensor uses 9600 bps speed communication + sensor.begin(9600, 1); + Utils.setMuxAux1(); // set Auxiliar1 socket + + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + WaspRegister |= REG_SOCKET1; + + // Turbidity Sensor ON + pinMode(PWR_TURBIDITY, OUTPUT); + digitalWrite(PWR_TURBIDITY, HIGH); + } + delay(10); //writeCalibrationValue(0x005D, getTemperature()); @@ -147,8 +184,8 @@ uint8_t turbiditySensorClass::readTurbidity() // This variable will store the result of the communication // result = 0 : no errors // result = 1 : error occurred - int result = -1; - int retries = 0; + uint8_t result = -1; + uint8_t retries = 0; while ((result !=0) && (retries < 20)) { @@ -159,18 +196,16 @@ uint8_t turbiditySensorClass::readTurbidity() result = sensor.getResponseBuffer(0); - #if DEBUG_MODE == 1 - USB.print(F("Turbidity measurement status: ")); - USB.print(result, BIN); - USB.print(F("\n")); + #if DEBUG_TURBIDITY > 1 + PRINT_TURBIDITY(F("Turbidity measurement status: ")); + PRINTLN_TURBIDITY_VAL(result); #endif result = sensor.getResponseBuffer(0) & 0x0007; - #if DEBUG_MODE == 1 - USB.print(F("Turbidity measurement status after mask: ")); - USB.print(result, BIN); - USB.print(F("\n")); + #if DEBUG_TURBIDITY > 1 + PRINT_TURBIDITY(F("Turbidity measurement status after mask: ")); + PRINTLN_TURBIDITY_VAL(result); #endif delay(10); } @@ -180,11 +215,11 @@ uint8_t turbiditySensorClass::readTurbidity() clearBuffer(); if (result != 0) { - #if DEBUG_MODE == 1 - USB.println(F("Communication error while reading turbidity measurement status...")); + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Communication error while reading turbidity measurement status...")); #endif - return -1; + return 1; } else { @@ -199,13 +234,13 @@ uint8_t turbiditySensorClass::readTurbidity() } if (result != 0) { - #if DEBUG_MODE == 1 + #if DEBUG_TURBIDITY > 0 // If no response from the slave, print an error message - USB.println(F("Communication error while reading Turbidity...")); + PRINTLN_TURBIDITY(F("Communication error while reading Turbidity")); #endif delay(150); - return -1; + return 1; } else { // If all OK @@ -226,13 +261,38 @@ uint8_t turbiditySensorClass::readTurbidity() //! Param : void //! Returns: The turbidity value //!************************************************************* -float turbiditySensorClass::getTurbidity() +float turbidityClass::getTurbidity() { - // Every sensor you use with digitalSmooth needs its own array + uint8_t status = -1; + uint8_t retries = 0; + + while ((status !=0) && (retries < 4)) + { + + delay(20); + retries++; + status = readTurbidity(); + + } + + if (status == 1) + { + //if readTurbidity function fails return -1000 + return -1000.0; + } + rawData1 = turbidity * 1000; smoothData1 = digitalSmooth(rawData1, sensSmoothArray1); float turbidity = smoothData1/1000.0; + + // negative values aren't usefull so return zeros + // if sensor returns zeros (negative values) is might be badly placed + if (turbidity<0.0) + { + turbidity = 0.0; + } + return turbidity; } @@ -247,9 +307,26 @@ float turbiditySensorClass::getTurbidity() //! Param : void //! Returns: The temperature value //!************************************************************* -float turbiditySensorClass::getTemperature() +float turbidityClass::getTemperature() { - return temperature; + uint8_t status = -1; + uint8_t retries = 0; + + while ((status !=0) && (retries < 4)) + { + + delay(20); + retries++; + status = readTemperature(); + + } + if (status==0) + { + return temperature; + } + + // if readTemperature function fails -1000 is returned + return -1000.0; } //********************************************************************** @@ -262,75 +339,36 @@ float turbiditySensorClass::getTemperature() //! config: The configuration to write //! Returns: void //!************************************************************* -void turbiditySensorClass::typeMeasurementConfiguration(uint16_t address, uint16_t config) +uint8_t turbidityClass::typeMeasurementConfiguration(uint16_t address, uint16_t config) { delay(100); - int result = sensor.writeSingleRegister(address, config); + uint8_t result = sensor.writeSingleRegister(address, config); delay(100); - #if DEBUG_MODE == 1 - // Chechk that the direction has been well writed - if (result == -1) { - // If no response from the slave, print an error message - USB.println(F("ERROR. Type Measurement Register not configured.")); - } - else { - USB.println(F("Type Measurement Register well configured")); - } - #endif - - clearBuffer(); - delay(150); -} - -/* - * // Not tested functions -void temperatureSensorCalibration() -{ - //Variable to read data from the serial monitor. - char serialByte = '0'; - - ///////////////////////////////////////////////////////////////////////////// - // OFFSET CALIBRATION PROCESS at 0ºC - ///////////////////////////////////////////////////////////////////////////// - average(1); - temporaryCoeficients(DISABLE); - - serialFlush(0); - - while(serialByte != 'R') - { - readTemperature(); - delay(250); - serialByte = serialRead(0); + // Chechk that the direction has been well writed + if (result == 0) + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Type Measurement Register well configured")); + #endif + + clearBuffer(); + delay(150); + return 0; + } + else + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("ERROR. Type Measurement Register not configured.")); + #endif + + clearBuffer(); + delay(150); + return 1; } - - writeCalibrationValue(TEMP_CAL1_REG, foo.toFloat); - temporaryCoeficients(OFFSET_0); - delay(5000); - - ///////////////////////////////////////////////////////////////////////////// - // CALIBRATION PROCESS at 25ºC - ///////////////////////////////////////////////////////////////////////////// - temporaryCoeficients(OFFSET_0); - - serialByte = '0'; - serialFlush(0); - - while(serialByte != 'R') - { - readTemperature(); - delay(250); - serialByte = serialRead(0); - } - +} - writeCalibrationValue(TEMP_CAL2_REG, foo.toFloat); - temporaryCoeficients(OFFSET_0 | TEMP_25); - writeNameDate(); - temporaryCoeficients(DISABLED); -}*/ //!************************************************************* @@ -339,10 +377,50 @@ void temperatureSensorCalibration() //! Param : void //! Returns: void //!************************************************************* -void turbiditySensorClass::resetSensor() +uint8_t turbidityClass::resetSensor() { - sensor.writeSingleRegister(RESET_REG, 0x000F); - delay(100); + // Result of the communication + uint8_t result; + + // Use the new address of the sensor + sensor.setSlaveAddress(DEFAULT_ADDRESS); + + result = sensor.writeSingleRegister(RESET_REG, 0x000F); + delay(200); + + if (result == 0) + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Reset well done")); + #endif + + return 0; + } + else + { + // Use the new address of the sensor + sensor.setSlaveAddress(SENSOR_ADDRESS); + + result = sensor.writeSingleRegister(RESET_REG, 0x000F); + delay(100); + + if (result == 0) + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Reset well done")); + #endif + + return 0; + } + else + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Reset failure")); + #endif + + return 1; + } + } } @@ -355,26 +433,32 @@ void turbiditySensorClass::resetSensor() //! Param : void //! Returns: void //!************************************************************* -void turbiditySensorClass::startMeasurment(uint8_t parameter) +uint8_t turbidityClass::startMeasurment(uint8_t parameter) { // Result of the communication - int result = -1; - + uint8_t result; + result = sensor.writeSingleRegister(NEW_MEAS_REG, parameter); delay(100); - #if DEBUG_MODE == 1 - // Chechk that the direction has been well writed - if (result == -1) { - // If no response from the slave, print an error message - USB.println(F("Communication Error. The sensor can't take a new measure.")); - } - else { - USB.println(F("Starting a new measure process...")); - } - #endif + // Chechk that the direction has been well writed + if (result == 0) + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Starting a new measure process...")); + #endif + + return 0; + } + else + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Communication Error. The sensor can't take a new measure.")); + #endif + init(); + return 1; + } - delay(10); } @@ -383,11 +467,11 @@ void turbiditySensorClass::startMeasurment(uint8_t parameter) //********************************************************************** //!************************************************************* //! Name: readTemperature() -//! Description: Reads the temperature value from the sensor +//! Description: Read the temperature value from the sensor //! Param : void //! Returns: "0" if no error, "-1" if error //!************************************************************* -uint8_t turbiditySensorClass::readTemperature() +uint8_t turbidityClass::readTemperature() { union { @@ -396,15 +480,39 @@ uint8_t turbiditySensorClass::readTemperature() } foo; - clearBuffer(); + if (_boot_version < 'H') + { + // The sensor uses 9600 bps speed communication + sensor.begin(9600); + + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + + WaspRegister |= REG_RS485; + } + else + { + // The sensor uses 9600 bps speed communication + sensor.begin(9600, 1); + Utils.setMuxAux1(); // set Auxiliar1 socket + + // Switch ON the power supply + PWR.setSensorPower(SENS_5V, SENS_ON); + WaspRegister |= REG_SOCKET1; + // Turbidity Sensor ON + pinMode(PWR_TURBIDITY, OUTPUT); + digitalWrite(PWR_TURBIDITY, HIGH); + } + + clearBuffer(); startMeasurment(TEMP_NEW_MEAS); // This variable will store the result of the communication // result = 0 : no errors // result = 1 : error occurred - int result = -1; - int retries = 0; + uint8_t result = -1; + uint8_t retries = 0; delay(100); @@ -416,18 +524,16 @@ uint8_t turbiditySensorClass::readTemperature() result = sensor.getResponseBuffer(0); - #if DEBUG_MODE == 1 - USB.print(F("Temperature measurement status: ")); - USB.print(result, BIN); - USB.print(F("\n")); + #if DEBUG_TURBIDITY > 1 + PRINT_TURBIDITY(F("Temperature measurement status: ")); + PRINTLN_TURBIDITY_VAL(result); #endif result = sensor.getResponseBuffer(0) & 0x0007; - #if DEBUG_MODE == 1 - USB.print(F("Temperature measurement status: ")); - USB.print(result, BIN); - USB.print(F("\n")); + #if DEBUG_TURBIDITY > 1 + PRINT_TURBIDITY(F("Temperature measurement status: ")); + PRINTLN_TURBIDITY_VAL(result); #endif delay(100); @@ -436,22 +542,22 @@ uint8_t turbiditySensorClass::readTemperature() delay(100); if (result != 0) { - #if DEBUG_MODE == 1 - USB.println(F("Communication error while reading temperature measurement status...")); + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Communication error while reading temperature measurement status...")); #endif - return -1; + return 1; } else { result = sensor.readHoldingRegisters(TEMP_VALUE_REG, 2); if (result != 0) { - #if DEBUG_MODE == 1 + #if DEBUG_TURBIDITY > 1 // If no response from the slave, print an error message - USB.println(F("Communication error while reading temperature...")); + PRINTLN_TURBIDITY(F("Communication error while reading temperature...")); #endif - return -1; + return 1; delay(100); } else { @@ -476,23 +582,29 @@ uint8_t turbiditySensorClass::readTemperature() //! Param : void //! Returns: void //!************************************************************* -void turbiditySensorClass::average(uint8_t average) +uint8_t turbidityClass::average(uint8_t average) { if (average > 50) average = 50; - int result = sensor.writeSingleRegister(AVRG_PARA_REG, average); + uint8_t result = sensor.writeSingleRegister(AVRG_PARA_REG, average); - #if DEBUG_MODE == 1 // Chechk that the direction has been well writed - if (result == -1) { - // If no response from the slave, print an error message - USB.println(F("Communication Error. Average not configured.")); - } - else { - USB.println(F("Average configured...")); - } - #endif + if (result == 0) + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Average configured...")); + #endif + return 0; + } + else + + { + #if DEBUG_TURBIDITY > 0 + PRINTLN_TURBIDITY(F("Communication Error. Average not configured.")); + #endif + return 1; + } } @@ -505,29 +617,31 @@ void turbiditySensorClass::average(uint8_t average) //! Param : address: the address to configure //! Returns: void //!************************************************************* -int turbiditySensorClass::configureSensorAddress(uint8_t address) +uint8_t turbidityClass::configureSensorAddress(uint8_t address) { - int result = -1; - int retries = 0; - - while ((result !=0) & (retries < 10)) - { + uint8_t result = -1; + uint8_t retries = 0; + + while ((result !=0) && (retries < 10)) + { retries ++; // Asign the address to the sensor result = sensor.writeSingleRegister(ADDRESS_REG, address); delay(50); } -#if DEBUG_MODE == 1 - if (result == -1) { - // If no response from the slave, print an error message - USB.println(F("Communication Error. Address not configured.")); - } - else { - USB.println(F("Address well configured")); - } -#endif + #if DEBUG_TURBIDITY > 0 + if (result == 0) + { + // If no response from the slave, print an error message + PRINTLN_TURBIDITY(F("Address well configured")); + } + else + { + PRINTLN_TURBIDITY(F("Communication Error. Address not configured.")); + } + #endif // Use the new address of the sensor sensor.setSlaveAddress(SENSOR_ADDRESS); @@ -538,8 +652,8 @@ int turbiditySensorClass::configureSensorAddress(uint8_t address) // If the address == 1, no errors if (sensor.getResponseBuffer(0) != 0x01) { - // If no response from the slave return -1 - return -1; + // If no response from the slave return 1 + return 1; } else { return 0; @@ -553,7 +667,7 @@ int turbiditySensorClass::configureSensorAddress(uint8_t address) //! Param : void //! Returns: void //!************************************************************* -void turbiditySensorClass::clearBuffer() +void turbidityClass::clearBuffer() { // Clear Response Buffer sensor.clearResponseBuffer(); @@ -561,49 +675,6 @@ void turbiditySensorClass::clearBuffer() delay(10); } -//********************************************************************** -// Frame 60 in the documentation for Temperature -// Not tested functions -//********************************************************************** -void turbiditySensorClass::readCompensationTemperature(uint16_t _register) -{ - - union - { - int ints[2]; - float toFloat; - } - foo; - // Result of the communication - //int result = -1; - - /* foo.toFloat = temperature; - node.setTransmitBuffer(0 , foo.ints[1]); - node.setTransmitBuffer(1 , foo.ints[0]); - -#if DEBUG_MODE == 1 - USB.println(F("Writting compensation temperature returned by Master")); -#endif - - node.writeMultipleRegisters(COMP_TEMP_REG, 2); - delay(100);*/ - -#if DEBUG_MODE == 1 - sensor.readHoldingRegisters(_register, 4); - USB.print(F("Temperature writed in register: ")); - USB.print(_register, HEX); - // Print the read data from the slave - USB.print(sensor.getResponseBuffer(0), DEC); - USB.print(F(" ")); - USB.print(sensor.getResponseBuffer(1), DEC); - USB.print(F(" ")); - - foo.ints[0]= sensor.getResponseBuffer(1); - foo.ints[1]= sensor.getResponseBuffer(0); - - USB.println(foo.toFloat); -#endif -} //!************************************************************* //! Name: digitalSmooth() @@ -612,7 +683,7 @@ void turbiditySensorClass::readCompensationTemperature(uint16_t _register) //! int *sensSmoothArray: array of previous values //! Returns: long: filtered value //!************************************************************* -long turbiditySensorClass::digitalSmooth(int rawIn, int *sensSmoothArray) +long turbidityClass::digitalSmooth(int rawIn, int *sensSmoothArray) { // "int *sensSmoothArray" passes an array to the function - the asterisk indicates the array name is a pointer long j, k, temp, top, bottom; @@ -666,3 +737,100 @@ long turbiditySensorClass::digitalSmooth(int rawIn, int *sensSmoothArray) +//!************************************************************* +//! Name: init() +//! Description: Initialization function +//! Returns: 1 reset error +//! 2 configure address error +//!************************************************************* + +uint8_t turbidityClass::init() +{ + uint8_t status = -1; + uint8_t retries = 0; + + while ((status !=0) && (retries < 4)) + { + + delay(20); + retries++; + + // Important: Reset the registers of the sensor + status = resetSensor(); + + } + + // Check that the reset has been done + if (status == 0) + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Sensor reset correctly")); + #endif + } + else + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Communication Error. The reset hasn't been done.")); + #endif + return 1; + } + + // Configure the sensor address + status = configureSensorAddress(SENSOR_ADDRESS); + + // Check that the address has been well configured + if (status == 0) + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Sensor address configured correctly")); + #endif + } + else + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Communication Error. The address hasn't been configured.")); + #endif + return 2; + } + + + delay(10); + + // Clear the Modbus buffers + clearBuffer(); + + status = -1; + retries = 0; + + while ((status !=0) && (retries < 4)) + { + retries++; + + // Configure the type measurement of the temperature sensor + status = typeMeasurementConfiguration(TEMP_TYPE_CON, 0x0003); + delay(20); + clearBuffer(); + + } + + // Check that the address has been well configured + if (status == 0) + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Sensor meassurement configured correctly")); + #endif + } + else + { + #if DEBUG_TURBIDIRY > 0 + PRINTLN_TURBIDITY(F("Communication Error. The meassurement type hasn't been configured.")); + #endif + return 3; + } + // Configure the average measurement + average(25); + + return 0; +} + + diff --git a/libraries/SensorSW/TurbiditySensor.h b/libraries/SensorSW/TurbiditySensor.h index b636553..f54bf6f 100755 --- a/libraries/SensorSW/TurbiditySensor.h +++ b/libraries/SensorSW/TurbiditySensor.h @@ -1,7 +1,7 @@ /*! \file TurbiditySensor.h - \brief Library for managing the Smart Water Turbidity Sensor Board + \brief Library for managing the Smart Water Turbidity Sensor - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,28 +17,25 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 - Design: David Gascón - Implementation: Ahmad Saad + Version: 3.1 + Design: David Gascón + Implementation: Ahmad Saad */ #ifndef TurbditySensor_h #define TurbditySensor_h -/****************************************************************************** - * Includes - ******************************************************************************/ +/***************************************************************************** +* Includes +******************************************************************************/ #include ///////////////////////////////////////////////////////////////////////////// // Include the neccesary libraries. -// The turbidity sensor uses RS-485 Modbus communication ///////////////////////////////////////////////////////////////////////////// -#include "../RS485/Wasp485.h" -#include "../ModbusMaster485/ModbusMaster485.h" - +#include "ModbusMaster.h" /****************************************************************************** * Definitions & Declarations ******************************************************************************/ @@ -58,7 +55,6 @@ #define TEMP_TYPE_CON 0x00A5 #define TURB_TYPE_CON 0x00A6 #define AVRG_PARA_REG 0x00AA -#define DISABLED 0x0000 #define TURB_MEAS_STATUS 0x0065 #define NEW_MEAS_REG 0x0001 #define TEMP_NEW_MEAS 0x0001 @@ -68,16 +64,28 @@ #define OFFSET_0 0x0001 #define TEMP_25 0x0002 +// Turbidity ON/OFF control Pin +#define PWR_TURBIDITY 17 + // This address will be configured as a first step #define SENSOR_ADDRESS 0x0001 #define DEFAULT_ADDRESS 0x0000 -// Debug mode define -#define DEBUG_MODE 0 +// FilterSamples should be an odd number, no smaller than 3 +#define filterSamples 7 -// FilterSamples should be an odd number, no smaller than 3 -#define filterSamples 11 +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_TURBIDITY 0 + +#define PRINT_TURBIDITY(str) USB.print(F("[TURBIDITY] ")); USB.print(str); +#define PRINT_TURBIDITY_VAL(val) USB.print(val, BIN); +#define PRINTLN_TURBIDITY(str) USB.print(F("[TURBIDITY] ")); USB.println(str); +#define PRINTLN_TURBIDITY_VAL(val) USB.println(val, BIN); /****************************************************************************** * Class @@ -88,33 +96,38 @@ This Class defines all the variables and functions used for managing the Turbidity Sensor */ -class turbiditySensorClass +class turbidityClass { public: // Public functions - turbiditySensorClass(); - char ON(); + turbidityClass(); + turbidityClass(uint8_t); + + uint8_t ON(); void OFF(); uint8_t readTurbidity(); float getTurbidity(); + + uint8_t readTemperature(); + float getTemperature(); private: // Sensor management functions - uint8_t readTemperature(); void readCompensationTemperature(uint16_t _register); - void startMeasurment(uint8_t parameter); - void typeMeasurementConfiguration(uint16_t address, uint16_t config); - void resetSensor(); - void average(uint8_t average); - int configureSensorAddress(uint8_t address); + uint8_t startMeasurment(uint8_t parameter); + uint8_t typeMeasurementConfiguration(uint16_t address, uint16_t config); + uint8_t resetSensor(); + uint8_t average(uint8_t average); + uint8_t configureSensorAddress(uint8_t address); void clearBuffer(); void writeCalibrationValue(uint16_t address, float value); - float getTemperature(); + + uint8_t init(); // For Mdobus management - ModbusMaster485 sensor; + ModbusMaster sensor; // Sensor variables float temperature; float turbidity; diff --git a/libraries/SensorSW/WaspSensorSW.cpp b/libraries/SensorSW/WaspSensorSW.cpp index 34a0ab0..a9794d8 100755 --- a/libraries/SensorSW/WaspSensorSW.cpp +++ b/libraries/SensorSW/WaspSensorSW.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.3 + * Version: 3.0 * Design: Ahmad Saad */ @@ -38,7 +38,7 @@ WaspSensorSW::WaspSensorSW() { // Update Waspmote Control Register - WaspRegister |= REG_WATER; + WaspRegisterSensor |= REG_WATER; } @@ -73,6 +73,13 @@ void WaspSensorSW::ON(void) delay(10); // Configure the ADC myADC.begin(); + + #if DEBUG_WATER > 1 + PRINTLN_WATER(F("Smart Water Sensor Board Switched ON")); + #endif + + // Enable SPI flag + //SPI.isSmartWater = true; } //!************************************************************************************* //! Name: OFF() @@ -82,14 +89,18 @@ void WaspSensorSW::ON(void) //!************************************************************************************* void WaspSensorSW::OFF(void) { - // disable Semtech SPI flag - SPI.isSmartWater = false; + // Enable SPI flag + //SPI.isSmartWater = false; // close SPI bus if it is posible - SPI.close(); + //SPI.close(); // Turn off the power switches in Waspmote PWR.setSensorPower(SENS_5V, SENS_OFF); - PWR.setSensorPower(SENS_3V3, SENS_OFF); + PWR.setSensorPower(SENS_3V3, SENS_OFF); + + #if DEBUG_WATER > 1 + PRINTLN_WATER(F("Smart Water Sensor Board Switched OFF")); + #endif } @@ -210,20 +221,12 @@ pHClass::pHClass() pHClass::pHClass(uint8_t channel) { // The pH sensor can be used in the DI and in the ORP sockets - if ((channel == DI_SOCKET) || (channel == ORP_SOCKET)) + if ((channel == ORP_SOCKET) || (channel == SOCKET_E)) { - if (channel == DI_SOCKET) - { - // Configuring the pH sensor to be used in the DI socket - pHChannel = DI_CHANNEL; - pHSwitch = ANA3; - } - else - { - // Configuring the pH sensor to be used in the ORP socket - pHChannel = ORP_CHANNEL; - pHSwitch = ANA1; - } + // Configuring the pH sensor to be used in the ORP socket + pHChannel = ORP_CHANNEL; + pHSwitch = ANA1; + } else { // Else, default configuration @@ -240,7 +243,18 @@ pHClass::pHClass(uint8_t channel) //!************************************************************************************* float pHClass::readpH() { - return SensorSW.getMeasure(pHChannel, pHSwitch); + #if DEBUG_WATER > 1 + if (pHChannel == PH_CHANNEL) + { + PRINTLN_WATER(F("Reading pH sensor in default SOCKET (Plug&Sense -> SOCKETA)")); + } + else + { + PRINTLN_WATER(F("Reading pH sensor from ORP SOCKET (Plug&Sense -> SOCKETD)")); + } + #endif + + return Water.getMeasure(pHChannel, pHSwitch); } //!************************************************************************************* @@ -341,7 +355,7 @@ conductivityClass::conductivityClass(){} float conductivityClass::readConductivity(void) { // Converts the voltage value into a resistance value - return resistanceConversion(SensorSW.getMeasure(COND_CHANNEL, DIGITAL7)); + return resistanceConversion(Water.getMeasure(COND_CHANNEL, DIGITAL7)); } //!************************************************************************************* @@ -473,21 +487,13 @@ ORPClass::ORPClass() ORPClass::ORPClass(uint8_t channel) { // The ORP sensor can be used in the DI and in the pH sockets - if ((channel == DI_SOCKET) || (channel == pH_SOCKET)) + if ((channel == pH_SOCKET) || (channel == SOCKET_A)) { - if (channel == DI_SOCKET) - { - // Configuring the ORP sensor to be used in the DI socket - ORPChannel = DI_CHANNEL; - ORPSwitch = ANA3; - } - else - { - // Configuring the ORP sensor to be used in the pH socket - ORPChannel = PH_CHANNEL; - ORPSwitch = DIGITAL8; - } - } else + // Configuring the ORP sensor to be used in the pH socket + ORPChannel = PH_CHANNEL; + ORPSwitch = DIGITAL8; + } + else { // Else, default configuration ORPChannel = ORP_CHANNEL; @@ -503,7 +509,18 @@ ORPClass::ORPClass(uint8_t channel) //!************************************************************************************* float ORPClass::readORP() { - return SensorSW.getMeasure(ORPChannel, ORPSwitch) - 2.048; + #if DEBUG_WATER > 1 + if (ORPChannel == ORP_CHANNEL) + { + PRINTLN_WATER(F("Reading ORP sensor in default SOCKET (Plug&Sense -> SOCKETD)")); + } + else + { + PRINTLN_WATER(F("Reading ORP sensor from pH SOCKET (Plug&Sense -> SOCKETA)")); + } + #endif + + return Water.getMeasure(ORPChannel, ORPSwitch) - 2.048; } //************************************************************************************************** @@ -517,7 +534,7 @@ float ORPClass::readORP() //!************************************************************************************* float DOClass::readDO() { - return SensorSW.getMeasure(DO_CHANNEL, ANA2); + return Water.getMeasure(DO_CHANNEL, ANA2); } //!************************************************************************************* @@ -601,7 +618,7 @@ DIClass::DIClass(uint8_t channel) //!************************************************************************************* float DIClass::readDI() { - return SensorSW.getMeasure(DIChannel, DISwitch); + return Water.getMeasure(DIChannel, DISwitch); } @@ -654,12 +671,12 @@ void DIClass::setCalibrationPoints(float calibrationValues[]) // Intersection of the logarithmic function intersection = SUMy_avg - (slope * SUMLogx_avg); - #if DEBUG_MODE == 1 - USB.print("Slope: "); - USB.println(slope); + #if DEBUG_WATER >1 + PRINT_WATER(F("Slope: ")); + PRINT_WATER_VAL(slope); - USB.print("Intersection: "); - USB.println(intersection); + PRINT_WATER(" | Intersection: "); + PRINTLN_WATER_VAL(intersection); #endif } @@ -727,12 +744,12 @@ void DIClass::setCalibrationPoints(float calVoltages[], float calConcentrations[ // Intersection of the logarithmic function intersection = SUMy_avg - (slope * SUMLogx_avg); - #if DEBUG_MODE == 1 - USB.print("Slope: "); - USB.println(slope); + #if DEBUG_WATER > 1 + PRINT_WATER(F("Slope: ")); + PRINT_WATER_VAL(slope); - USB.print("Intersection: "); - USB.println(intersection); + PRINT_WATER(" | Intersection: "); + PRINTLN_WATER_VAL(intersection); #endif } @@ -752,4 +769,4 @@ float DIClass::calculateConcentration(float input) //!************************************************************************************* //! Smart Water Object //!************************************************************************************* -WaspSensorSW SensorSW=WaspSensorSW(); +WaspSensorSW Water = WaspSensorSW(); diff --git a/libraries/SensorSW/WaspSensorSW.h b/libraries/SensorSW/WaspSensorSW.h index ff55c98..e7fd94e 100755 --- a/libraries/SensorSW/WaspSensorSW.h +++ b/libraries/SensorSW/WaspSensorSW.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,13 +15,13 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.2 + * Version: 3.0 * Design: Ahmad Saad */ -#ifndef WaspSensorSW_h -#define WaspSensorSW_h +#ifndef WASPSENSORSW_H +#define WASPSENSORSW_H /****************************************************************************** * Includes @@ -30,9 +30,9 @@ #include #include -/****************************************************************************** - * Definitions & Declarations - ******************************************************************************/ +//********************************************************************** +// Definitions & Declarations +// ********************************************************************* #define SENS_SW_DO 2 #define SENS_SW_COND 3 @@ -40,8 +40,9 @@ #define SENS_SW_ORP 5 #define SENS_SW_DI 6 - +//********************************************************************** // Calibration values of the conductivity sensor +//********************************************************************** #define SW_COND_CAL_01 0.0271 #define SW_COND_CAL_02 0.0365 #define SW_COND_CAL_03 0.0478 @@ -59,8 +60,9 @@ #define SW_COND_CAL_15 0.9076 #define SW_COND_CAL_16 0.9931 -#define FILTER_SAMPLES 7 - +//********************************************************************** +// ADC CHANNELS +//********************************************************************** #define TEMP_CHANNEL 0 #define DO_CHANNEL 2 #define PH_CHANNEL 3 @@ -68,9 +70,31 @@ #define DI_CHANNEL 5 #define COND_CHANNEL 7 -#define pH_SOCKET 3 -#define ORP_SOCKET 2 -#define DI_SOCKET 1 +//********************************************************************** +// SOCKET DEFINITIONS +//********************************************************************** +#define PT1000_SOCKET 6 +#define EC_SOCKET 5 +#define DO_SOCKET 4 +#define pH_SOCKET 3 +#define ORP_SOCKET 2 +#define DI_SOCKET 1 + +#define FILTER_SAMPLES 7 + +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_WATER 0 + +#define PRINT_WATER(str) USB.print(F("[WATER] ")); USB.print(str); +#define PRINT_WATER_VAL(val) USB.print(float(val)); + +#define PRINTLN_WATER(str) USB.print(F("[WATER] ")); USB.println(str); +#define PRINTLN_WATER_VAL(val) USB.println(float(val)); + //************************************************************************************************** // Smart Water Board Class @@ -94,23 +118,19 @@ class WaspSensorSW private: //! Read from the ADC - float getMeasure(uint8_t, uint8_t); - - - + float getMeasure(uint8_t, uint8_t); }; -extern WaspSensorSW SensorSW; +extern WaspSensorSW Water; #endif - //************************************************************************************************** // Temperature sensor class //************************************************************************************************** -#ifndef PT1000_h -#define PT1000_h +#ifndef PT1000CLASS_H +#define PT1000CLASS_H class pt1000Class { @@ -126,8 +146,8 @@ class pt1000Class //************************************************************************************************** // pH sensor class //************************************************************************************************** -#ifndef pHsensor_h -#define pHsensor_h +#ifndef PHSENSORCLASS_H +#define PHSENSORCLASS_H class pHClass { @@ -159,12 +179,11 @@ class pHClass #endif - //************************************************************************************************** // Conductivity sensor class //************************************************************************************************** -#ifndef Conductivity_h -#define Conductivity_h +#ifndef CONDUCTIVITYCLASS_h +#define CONDUCTIVITYCLASS_h class conductivityClass { @@ -194,8 +213,8 @@ class conductivityClass //************************************************************************************************** // ORP sensor class //************************************************************************************************** -#ifndef ORP_h -#define ORP_h +#ifndef ORPCLASS_h +#define ORPCLASS_h class ORPClass { @@ -218,8 +237,8 @@ class ORPClass //************************************************************************************************** // DO sensor class //************************************************************************************************** -#ifndef DO_h -#define DO_h +#ifndef DOCLASS_H +#define DOCLASS_H class DOClass { diff --git a/libraries/SensorSW/keywords.txt b/libraries/SensorSW/keywords.txt index 6daac6e..b60abb6 100644 --- a/libraries/SensorSW/keywords.txt +++ b/libraries/SensorSW/keywords.txt @@ -36,7 +36,8 @@ WaspSensorSW KEYWORD2 ON KEYWORD2 OFF KEYWORD2 -SensorSW KEYWORD3 +SensorSW KEYWORD1 +Water KEYWORD1 #Temperature# @@ -110,9 +111,13 @@ TEMP_25 LITERAL1 sensorAddress LITERAL1 DEBUG_MODE LITERAL1 filterSamples LITERAL1 +SENSOR_ADDRESS LITERAL1 +DEFAULT_ADDRESS LITERAL1 ON KEYWORD2 OFF KEYWORD2 readTurbidit KEYWORD2 getTurbidity KEYWORD2 TurbiditySensor KEYWORD2 +readTurbidity KEYWORD2 +turbidityClass KEYWORD2 diff --git a/libraries/SensorSW/utility/ADC.cpp b/libraries/SensorSW/utility/ADC.cpp index 4ad4318..0c0e3e8 100755 --- a/libraries/SensorSW/utility/ADC.cpp +++ b/libraries/SensorSW/utility/ADC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: Ahmad Saad */ diff --git a/libraries/SensorSW/utility/ADC.h b/libraries/SensorSW/utility/ADC.h index 2ea4287..4b0ce7b 100755 --- a/libraries/SensorSW/utility/ADC.h +++ b/libraries/SensorSW/utility/ADC.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: Ahmad Saad */ diff --git a/libraries/SensorSW/utility/filter.cpp b/libraries/SensorSW/utility/filter.cpp index 0a9e2b7..bf6656b 100755 --- a/libraries/SensorSW/utility/filter.cpp +++ b/libraries/SensorSW/utility/filter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: Ahmad Saad * */ diff --git a/libraries/SensorSW/utility/filter.h b/libraries/SensorSW/utility/filter.h index 0b988d4..0908c79 100755 --- a/libraries/SensorSW/utility/filter.h +++ b/libraries/SensorSW/utility/filter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: Ahmad Saad */ diff --git a/libraries/SensorSmart_v20/WaspSensorSmart_v20.cpp b/libraries/SensorSmart_v20/WaspSensorSmart_v20.cpp index 0f1b083..a486a1d 100755 --- a/libraries/SensorSmart_v20/WaspSensorSmart_v20.cpp +++ b/libraries/SensorSmart_v20/WaspSensorSmart_v20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.4 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, David Cuartielles */ @@ -56,7 +56,7 @@ WaspSensorSmart_v20::WaspSensorSmart_v20() PWR.setSensorPower(SENS_5V, SENS_OFF); // update Waspmote Control Register - WaspRegister |= REG_METERING; + WaspRegisterSensor |= REG_METERING; } // Public Methods ////////////////////////////////////////////////////////////// diff --git a/libraries/SensorSmart_v20/WaspSensorSmart_v20.h b/libraries/SensorSmart_v20/WaspSensorSmart_v20.h index f07e432..6d988e3 100755 --- a/libraries/SensorSmart_v20/WaspSensorSmart_v20.h +++ b/libraries/SensorSmart_v20/WaspSensorSmart_v20.h @@ -1,7 +1,7 @@ /*! \file WaspSensorSmart_v20.h \brief Library for managing the Smart Metering Sensor Board - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,10 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 - - Design: David Gascón - + Version: 3.0 + Design: David Gascón Implementation: Alberto Bielsa, Manuel Calahorra */ diff --git a/libraries/SensorSmart_v20/keywords.txt b/libraries/SensorSmart_v20/keywords.txt index dd3da23..70d553e 100644 --- a/libraries/SensorSmart_v20/keywords.txt +++ b/libraries/SensorSmart_v20/keywords.txt @@ -38,4 +38,4 @@ setSensorMode KEYWORD2 readValue KEYWORD2 readValue KEYWORD2 -SensorSmartv20 KEYWORD3 +SensorSmartv20 KEYWORD1 diff --git a/libraries/Sigfox/WaspSigfox.cpp b/libraries/Sigfox/WaspSigfox.cpp index 28c4e64..e8d5c8e 100755 --- a/libraries/Sigfox/WaspSigfox.cpp +++ b/libraries/Sigfox/WaspSigfox.cpp @@ -1,10 +1,10 @@ /*! * @file WaspSigfox.cpp * @author Libelium Comunicaciones Distribuidas S.L. - * @version 1.0 - * @brief Library for managing Sigfox modules TD1207 + * @version 3.1 + * @brief Library for managing Sigfox modules TD1207 & TD1508 * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -84,7 +84,7 @@ void WaspSigfox::generator(uint8_t type, int n, const char *cmdCode, ...) default: #if DEBUG_SIGFOX > 0 - USB.print(F("[debug] error type\n")); + PRINT_SIGFOX(F("error type\n")); #endif return (void)0; } @@ -166,7 +166,7 @@ void WaspSigfox::generator(uint8_t type, int n, const char *cmdCode, ...) { //error #if DEBUG_SIGFOX > 0 - USB.print(F("[debug] not enough buffer size\n")); + PRINT_SIGFOX(F("not enough buffer size\n")); #endif memset( _command, 0x00, sizeof(_command) ); return (void)0; @@ -186,8 +186,8 @@ void WaspSigfox::generator(uint8_t type, int n, const char *cmdCode, ...) // show command #if DEBUG_SIGFOX > 1 - USB.print(F("[debug] ")); - USB.println( _command ); + PRINT_SIGFOX(F("_command: ")); + USB.println( _command ); #endif } @@ -262,53 +262,19 @@ uint32_t WaspSigfox::parseUint32Value() */ uint8_t WaspSigfox::ON(uint8_t socket) { - _baudrate = UART_RATE; + _baudrate = SIGFOX_RATE; _uart = socket; - if (socket == SOCKET0) - { - _uart = SOCKET0; - - // Set multiplexer - Utils.setMuxSocket0(); - - // Open UART - beginUART(); - - // power up - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - } - else - { - // check RTC int pin to disable line in order to communicate - if (digitalRead(RTC_INT_PIN_MON) == HIGH) - { - if (RTC.isON == 0 ) - { - RTC.ON(); - RTC.clearAlarmFlag(); - RTC.OFF(); - } - else - { - RTC.clearAlarmFlag(); - } - } - - _uart = SOCKET1; - - // Set multiplexer - Utils.setMuxSocket1(); - - // Open UART - beginUART(); - - // power up - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,HIGH); - } + // select multiplexer + if (_uart == SOCKET0) Utils.setMuxSocket0(); + if (_uart == SOCKET1) Utils.setMuxSocket1(); + // Open UART + beginUART(); + + // power on the socket + PWR.powerSocket(_uart, HIGH); + delay(5000); // Check communication @@ -329,31 +295,15 @@ uint8_t WaspSigfox::ON(uint8_t socket) */ uint8_t WaspSigfox::OFF(uint8_t socket) { - if (socket == SOCKET0) - { - _uart = SOCKET0; - - // Set multiplexer - Utils.setMuxUSB(); - - // close UART0 - closeUART(); - - // power down - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW, LOW); - } - else - { - _uart = SOCKET1; - - // close UART1 - closeUART(); + // close uart + closeUART(); + + // unselect multiplexer + if (_uart == SOCKET0) Utils.setMuxUSB(); + if (_uart == SOCKET1) Utils.muxOFF1(); - // power down - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,LOW); - } + // switch module OFF + PWR.powerSocket(_uart, LOW); return SIGFOX_ANSWER_OK; } @@ -377,7 +327,8 @@ uint8_t WaspSigfox::check() if( status == 1 ) { - // ok + // ok -> get module region + getRegion(); return SIGFOX_ANSWER_OK; } else if(status == 2) @@ -676,8 +627,8 @@ uint8_t WaspSigfox::send(uint8_t* data, uint16_t length) Utils.hex2str(data, ascii_command, length); #if DEBUG_SIGFOX > 1 - USB.print(F("[debug] ")); - USB.println( ascii_command ); + PRINT_SIGFOX(F("ascii_command: ")); + USB.println( ascii_command ); #endif return send(ascii_command); @@ -778,8 +729,8 @@ uint8_t WaspSigfox::sendACK(uint8_t* data, uint16_t length) Utils.hex2str(data, ascii_command, length); #if DEBUG_SIGFOX > 1 - USB.print(F("[debug] ")); - USB.println( ascii_command ); + PRINT_SIGFOX(F("ascii_command: ")); + USB.println( ascii_command ); #endif return sendACK(ascii_command); @@ -944,22 +895,15 @@ uint8_t WaspSigfox::sendKeepAlive(uint8_t period) uint8_t WaspSigfox::continuosWave(uint32_t freq, bool enable) { char param1[20]; - - // create "AT$CW=" command - snprintf(_command, sizeof(_command),"ATS900=%lu\r", freq); - - // set frequency setting - if( sendCommand(_command, AT_OK, AT_ERROR, 500) != 1) - { - return SIGFOX_ANSWER_ERROR; - } - + char param2[20]; + // convert to string - utoa((uint16_t)enable, param1, 10); + ltoa((uint32_t)freq, param1, 10); + utoa((uint16_t)enable, param2, 10); // create "AT$CW=" command - GEN_ATCOMMAND_SET("CW", param1); - + GEN_ATCOMMAND_SET("CW", param1, param2); + // set CW mode: enabled or disabled if( sendCommand(_command, AT_OK, AT_ERROR, 500) != 1) { @@ -1549,6 +1493,308 @@ uint8_t WaspSigfox::getMultiPacket(uint32_t time) } + +/*! + * @brief get the actual region of the module + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::getRegion() +{ + uint8_t status; + + status = sendCommand("ATS304?\r", "\r\n", AT_ERROR, 1000); + + if (status != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + status = waitFor(AT_OK, AT_ERROR, 1000); + + if (status == 1 ) + { + // get value from received data + _region = parseUint8Value(); + + return 0; + } + else if (status == 2 ) + { + // error + return 1; + } + else + { + // time out + return 2; + } +} + + + +/*! + * @brief This function configures the SIGFOX FCC Macro Channel Bitmask to + * enable/disable the 192KHz macro channels authorized for transmission + * + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @param char* bitmask: "000000000000000000000000" to "FFFFFFFFFFFFFFFFFFFFFFFF" + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::setMacroChannelBitmask(char* bitmask) +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS306=%s\r", bitmask); + + // 1. send command + answer = sendCommand(_command, AT_OK, AT_ERROR, 1000); + + // check possible error answers + if (answer == 2) + { + // error + return SIGFOX_ANSWER_ERROR; + } + else if (answer == 0) + { + // timeout + return SIGFOX_NO_ANSWER; + } + + // 2. save config + answer = saveSettings(); + + return answer; +} + + +/*! + * @brief This function queries the SIGFOX FCC Macro Channel Bitmask to + * enable/disable the 192KHz macro channels authorized for transmission + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::getMacroChannelBitmask() +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS306?\r"); + + // enter command mode + if (sendCommand(_command, AT_EOL, AT_ERROR, 1000) != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + answer = waitFor(AT_EOL, 1000); + + // enter command mode + if (answer != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + // get value from received data + answer = parseString(_macroChannelBitmask, sizeof(_macroChannelBitmask), "\r\n", 1); + + if (answer != 0) + { + return SIGFOX_ANSWER_ERROR; + } + + return SIGFOX_ANSWER_OK; +} + + + + + +/*! + * @brief This function configures the SIGFOX Default FCC Macro Channel. + * + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @param uint8_t config: range from 1 to 82. + * The default FCC channel value must be between 1 and 82. At least 9 + * macro channels must be enabled to ensure the minimum of 50 FCC + * channels. Parameter is 3 x 32bits words, with word 1 first. + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::setMacroChannel(uint8_t config) +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS307=%u\r", config); + + // 1. send command + answer = sendCommand(_command, AT_OK, AT_ERROR, 1000); + + // check possible error answers + if (answer == 2) + { + // error + return SIGFOX_ANSWER_ERROR; + } + else if (answer == 0) + { + // timeout + return SIGFOX_NO_ANSWER; + } + + // 2. save config + answer = saveSettings(); + + return answer; +} + + +/*! + * @brief This function queries the SIGFOX Default FCC Macro Channel. + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::getMacroChannel() +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS307?\r"); + + // enter command mode + if (sendCommand(_command, AT_EOL, AT_ERROR, 1000) != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + answer = waitFor(AT_EOL, 1000); + + // enter command mode + if (answer != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + // get value from received data + answer = parseUint8(&_macroChannel, "\r\n", 1); + + if (answer != 0) + { + return SIGFOX_ANSWER_ERROR; + } + + return SIGFOX_ANSWER_OK; +} + + + + + +/*! + * @brief This function configures the SIGFOX Downlink frequency offset. + * + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @param uint8_t config: range from -30000000 to 30000000 Hz + * The default value in FCC mode is 3000000 Hz + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::setDownFreqOffset(int32_t offset) +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS308=%li\r", offset); + + // 1. send command + answer = sendCommand(_command, AT_OK, AT_ERROR, 1000); + + // check possible error answers + if (answer == 2) + { + // error + return SIGFOX_ANSWER_ERROR; + } + else if (answer == 0) + { + // timeout + return SIGFOX_NO_ANSWER; + } + + // 2. save config + answer = saveSettings(); + + return answer; +} + + +/*! + * @brief This function queries the SIGFOX Downlink frequency offset. + * @remarks This parameter is used only in FCC region, there is no effect in + * ETSI. To change this parameter, an AT&W command and ATZ command are + * required + * @return + * @arg 'SIGFOX_ANSWER_OK' if OK + * @arg 'SIGFOX_ANSWER_ERROR' if error + * @arg 'SIGFOX_NO_ANSWER' if no answer + */ +uint8_t WaspSigfox::getDownFreqOffset() +{ + uint8_t answer; + + snprintf(_command, sizeof(_command), "ATS308?\r"); + + // enter command mode + if (sendCommand(_command, AT_EOL, AT_ERROR, 1000) != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + answer = waitFor(AT_EOL, 1000); + + // enter command mode + if (answer != 1) + { + return SIGFOX_ANSWER_ERROR; + } + + // get value from received data + answer = parseInt32(&_downFreqOffset, "\r\n"); + + if (answer != 0) + { + return SIGFOX_ANSWER_ERROR; + } + + return SIGFOX_ANSWER_OK; +} + + + + // Preinstantiate Objects ///////////////////////////////////////////////////// WaspSigfox Sigfox = WaspSigfox(); diff --git a/libraries/Sigfox/WaspSigfox.h b/libraries/Sigfox/WaspSigfox.h index 7bbd4a2..1ab9f52 100755 --- a/libraries/Sigfox/WaspSigfox.h +++ b/libraries/Sigfox/WaspSigfox.h @@ -1,10 +1,10 @@ /*! * @file WaspSigfox.h * @author Libelium Comunicaciones Distribuidas S.L. - * @version 1.0 - * @brief Library for managing Sigfox modules TD1207 + * @version 3.1 + * @brief Library for managing Sigfox modules TD1207 & TD1508 * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -37,8 +37,21 @@ * Definitions & Declarations *****************************************************************************/ +//! DEBUG_SIGFOX +/*! Possible values: + * 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_SIGFOX 0 + + +// define print message +#define PRINT_SIGFOX(str) USB.print(F("[Sigfox] ")); USB.print(str); + + //! UART baudrate -#define UART_RATE 9600 +#define SIGFOX_RATE 9600 //! ATcommands responses static char AT_OK[] = "OK"; @@ -72,7 +85,15 @@ enum CommandTypes SIGFOX_CMD_DISPLAY = 3, // AT/? }; - +/*! @enum RegionTypes + */ +enum RegionTypes +{ + SIGFOX_REGION_UNKNOWN = 0, + SIGFOX_REGION_ETSI = 1, + SIGFOX_REGION_FCC = 2, + SIGFOX_REGION_ARIB = 3, +}; /****************************************************************************** * Class @@ -96,14 +117,18 @@ class WaspSigfox : public WaspUART uint32_t parseUint32Value(); public: - uint8_t _power; /*!< Sigfox tx power (in dBm) */ - uint32_t _id; /*!< Sigfox module id */ - char _firmware[10]; /*!< Module firmware version */ - uint32_t _address; /*!< LAN address */ - uint32_t _mask; /*!< Mask address */ - uint32_t _frequency; /*!< Frequency */ - int _powerLAN; /*!< LAN tx power (in dBm) */ - char _packet[35]; /*!< LAN packet structure */ + uint8_t _power; /*!< Sigfox tx power (in dBm) */ + uint32_t _id; /*!< Sigfox module id */ + char _firmware[10]; /*!< Module firmware version */ + uint32_t _address; /*!< LAN address */ + uint32_t _mask; /*!< Mask address */ + uint32_t _frequency; /*!< Frequency */ + int _powerLAN; /*!< LAN tx power (in dBm) */ + char _packet[35]; /*!< LAN packet structure */ + uint8_t _region; /*!< actual region of the module*/ + char _macroChannelBitmask[25]; /*!< Macro channel bitmask */ + uint8_t _macroChannel; /*!< Macro channel */ + int32_t _downFreqOffset; /*!< Downlink Frequency Offset */ //! class constructor WaspSigfox() @@ -151,6 +176,15 @@ class WaspSigfox : public WaspUART uint8_t disableRX(); uint8_t setMultiPacket(); uint8_t getMultiPacket(uint32_t time); + uint8_t getRegion(); + + // FCC functions + uint8_t setMacroChannelBitmask(char* bitmask); + uint8_t getMacroChannelBitmask(); + uint8_t setMacroChannel(uint8_t config); + uint8_t getMacroChannel(); + uint8_t setDownFreqOffset(int32_t offset); + uint8_t getDownFreqOffset(); }; //! Define the object diff --git a/libraries/Sigfox/keywords.txt b/libraries/Sigfox/keywords.txt index 1e87b38..01d5005 100644 --- a/libraries/Sigfox/keywords.txt +++ b/libraries/Sigfox/keywords.txt @@ -21,6 +21,18 @@ setMultiPacket KEYWORD2 getMultiPacket KEYWORD2 sendLAN KEYWORD2 receive KEYWORD2 +saveSettings KEYWORD2 +defaultConfiguration KEYWORD2 +parsePacketLAN KEYWORD2 +disableRX KEYWORD2 +getRegion KEYWORD2 +setMacroChannelBitmask KEYWORD2 +getMacroChannelBitmask KEYWORD2 +setMacroChannel KEYWORD2 +getMacroChannel KEYWORD2 +setDownFreqOffset KEYWORD2 +getDownFreqOffset KEYWORD2 + _buffer KEYWORD2 _length KEYWORD2 _id KEYWORD2 @@ -30,6 +42,32 @@ _mask KEYWORD2 _frequency KEYWORD2 _powerLAN KEYWORD2 _packet KEYWORD2 +_firmware KEYWORD2 +_version KEYWORD2 +_region KEYWORD2 +_macroChannelBitmask KEYWORD2 +_macroChannel KEYWORD2 +_downFreqOffset KEYWORD2 WaspSigfox KEYWORD2 -Sigfox KEYWORD3 + +Sigfox KEYWORD1 +SIGFOX_RATE KEYWORD1 +AT_OK KEYWORD1 +AT_ERROR KEYWORD1 +AT_EOL KEYWORD1 +AT_HEADER KEYWORD1 +AT_HEADER_SLASH KEYWORD1 +SIGFOX_LAN_MAX_PAYLOAD KEYWORD1 + +SIGFOX_ANSWER_OK LITERAL1 +SIGFOX_ANSWER_ERROR LITERAL1 +SIGFOX_NO_ANSWER LITERAL1 +SIGFOX_CMD_SET LITERAL1 +SIGFOX_CMD_READ LITERAL1 +SIGFOX_CMD_DISPLAY LITERAL1 + +SIGFOX_REGION_UNKNOWN LITERAL1 +SIGFOX_REGION_ETSI LITERAL1 +SIGFOX_REGION_FCC LITERAL1 +SIGFOX_REGION_ARIB LITERAL1 diff --git a/libraries/SmartWaterIons/keywords.txt b/libraries/SmartWaterIons/keywords.txt index d2a3cf7..62c040c 100644 --- a/libraries/SmartWaterIons/keywords.txt +++ b/libraries/SmartWaterIons/keywords.txt @@ -8,6 +8,7 @@ SOCKET1 LITERAL1 SOCKET2 LITERAL1 SOCKET3 LITERAL1 SOCKET4 LITERAL1 +MAX_POINTS LITERAL1 WaspSensorSWIons KEYWORD2 ON KEYWORD2 @@ -21,7 +22,9 @@ read KEYWORD2 setCalibrationPoints KEYWORD2 pHConversion KEYWORD2 setpHCalibrationPoints KEYWORD2 - +pointToPointCalibration KEYWORD2 +calculateConcentrationP2P KEYWORD2 +SWIonsBoard KEYWORD1 #Temperature# diff --git a/libraries/SmartWaterIons/smartWaterIons.cpp b/libraries/SmartWaterIons/smartWaterIons.cpp index 7e3d98b..5acc05a 100755 --- a/libraries/SmartWaterIons/smartWaterIons.cpp +++ b/libraries/SmartWaterIons/smartWaterIons.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: Ahmad Saad */ @@ -41,7 +41,7 @@ WaspSensorSWIons::WaspSensorSWIons() { // Update Waspmote Control Register - WaspRegister |= REG_WATER_IONS; + WaspRegisterSensor |= REG_WATER_IONS; PWR.setSensorPower(SENS_5V, SENS_OFF); PWR.setSensorPower(SENS_3V3, SENS_OFF); @@ -139,22 +139,22 @@ float ionSensorClass::read(void) digitalWrite(DIGITAL3, LOW); // Select the channel to be read from the multiplexer - if (_mySocket == SOCKETA) { + if (_mySocket == SOCKET_A) { digitalWrite(DIGITAL5, LOW); digitalWrite(DIGITAL4, LOW); - } else if (_mySocket == SOCKETB){ + } else if (_mySocket == SOCKET_B){ digitalWrite(DIGITAL5, HIGH); digitalWrite(DIGITAL4, LOW); - } else if (_mySocket == SOCKETC) { + } else if (_mySocket == SOCKET_C) { digitalWrite(DIGITAL5, LOW); digitalWrite(DIGITAL4, HIGH); - } else if (_mySocket == SOCKETD) { + } else if (_mySocket == SOCKET_D) { digitalWrite(DIGITAL5, HIGH); digitalWrite(DIGITAL4, HIGH); @@ -218,6 +218,19 @@ void ionSensorClass::setCalibrationPoints(const float calVoltages[],const float } + +//!************************************************************************************* +//! Name: setCalibrationPoints() +//! Description: Calculate the slope and the intersection of the logarithmic function +//! Param : void +//! Returns: void +//!************************************************************************************* +void ionSensorClass::setCalibrationPoints() +{ + setCalibrationPoints(voltages, concentrations, numPoints); +} + + //!************************************************************************************* //! Name: pointToPointCalibration() //! Description: Calibration using point to point method @@ -256,7 +269,17 @@ float ionSensorClass::calculateConcentration(float input) // The ions sensors have a logarithmic response (Nernst Equation) // The calibration process in a non-linear regression // y = a * log10(x) + b => x = 10 ^ ((y - b) / a) - return pow(10, ((input - intersection) / slope)); + + float concentration = pow(10, ((input - intersection) / slope)); + + if (concentration > 999999.9) + { + return -1; + } + else + { + return concentration; + } } //!************************************************************************************* @@ -272,8 +295,8 @@ float ionSensorClass::calculateConcentrationP2P(float input) int i = 0; // This loop is to find the range where the input is located - while ((!inRange) && (i < (numPoints-1))) { - + while ((!inRange) && (i < (numPoints-1))) + { if ((input > voltages[i]) && (input <= voltages[i + 1])) inRange = true; else if ((input <= voltages[i]) && (input > voltages[i+1])) @@ -287,32 +310,45 @@ float ionSensorClass::calculateConcentrationP2P(float input) // If the voltage input is in a range, we calculate in the slope // and the intersection of the logaritmic function - if (inRange ) { + if (inRange ) + { // Slope of the logarithmic function temp_slope = (voltages[i] - voltages[i+1]) / (log10(concentrations[i]) - log10(concentrations[i+1])); // Intersection of the logarithmic function - temp_intersection = voltages[i] - temp_slope * log10(concentrations[i]); - // Return the value of teh concetration - return pow(10, ((input - temp_intersection) / temp_slope)); + temp_intersection = voltages[i] - temp_slope * log10(concentrations[i]); + // Else, we calculate the logarithmic function with the nearest point - } else { - - if (fabs(input - voltages[0]) < fabs(input - voltages[numPoints-1])) { + } + else + { + if (fabs(input - voltages[0]) < fabs(input - voltages[numPoints-1])) + { // Slope of the logarithmic function temp_slope = (voltages[1] - voltages[0]) / (log10(concentrations[1]) - log10(concentrations[0])); // Intersection of the logarithmic function temp_intersection = voltages[0] - temp_slope * log10(concentrations[0]); - // Return the value of teh concetration - return pow(10, ((input - temp_intersection) / temp_slope)); - } else { + + } + else + { // Slope of the logarithmic function temp_slope = (voltages[numPoints-1] - voltages[numPoints-2]) / (log10(concentrations[numPoints-1]) - log10(concentrations[numPoints-2])); // Intersection of the logarithmic function temp_intersection = voltages[numPoints-1] - temp_slope * log10(concentrations[numPoints-1]); - // Return the value of the concetration - return pow(10, ((input - temp_intersection) / temp_slope)); } - } + } + + float concentration = pow(10, ((input - temp_intersection) / temp_slope)); + + // Return the value of the concetration + if (concentration > 999999.9) + { + return -1; + } + else + { + return concentration; + } } //!************************************************************************************* @@ -329,15 +365,17 @@ float ionSensorClass::pHConversion(float input, float temp) float sensitivity; // The temperature of the water must be between 0 and 100 ºC - if( (temp < 0)||(temp > 100)) + if( (temp < 0.0)||(temp > 100.0)) return -1.0; // The calibration temperature must be between 0 and 100 ºC if((calibration_temperature < 0)||(calibration_temperature > 100)) return -2.0; - // TWo ranges calibration - if (input > calibration_point_7 ) { + + // Two ranges calibration + if (input > calibration_point_7 ) + { // The sensitivity is calculated using the other two calibration values // Asumme that the pH sensor is lineal in the range. // sensitivity = pHVariation / volts @@ -351,7 +389,9 @@ float ionSensorClass::pHConversion(float input, float temp) return 7.0 + (calibration_point_7-input) / sensitivity; // | | // (pH 7 voltage - Measured volts) = Variation from the reference - } else { + } + else + { // The sensitivity is calculated using the other two calibration values sensitivity = (calibration_point_7-calibration_point_10) / 3; // Add the change in the pH owed to the change in temperature @@ -361,6 +401,21 @@ float ionSensorClass::pHConversion(float input, float temp) } } + +//!************************************************************************************* +//! Name: pHConversion() +//! Description: Returns the pH value +//! Param: float input: voltage measured at the sensor output +//! float temp: temperature of the test solution +//! Returns: float value : the pH of the solution +//! -1 : wrong temperature introduced +//! -2 : wrong calibration temperature introduced +//!************************************************************************************* +float ionSensorClass::pHConversion(float input) +{ + return pHConversion(input, 25.0); +} + //!************************************************************************************* //! Name: setCalibrationPoints() //! Description: Configures the calibration points of the pH sensor @@ -417,7 +472,15 @@ float pt1000Class::read(void) float temp = 0.26048 * value - 260.83; delay(100); - return temp; + if ((temp > 100.0) || (temp < 0.0)) + { + return -1.0; + } + else + { + return temp; + } + } diff --git a/libraries/SmartWaterIons/smartWaterIons.h b/libraries/SmartWaterIons/smartWaterIons.h index 5ba702e..b4af11d 100755 --- a/libraries/SmartWaterIons/smartWaterIons.h +++ b/libraries/SmartWaterIons/smartWaterIons.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: Ahmad Saad */ @@ -33,16 +33,23 @@ * Definitions & Declarations ******************************************************************************/ -#define SOCKETA 1 -#define SOCKETB 2 -#define SOCKETC 3 -#define SOCKETD 4 - -#define SOCKET1 1 -#define SOCKET2 2 -#define SOCKET3 3 -#define SOCKET4 4 #define MAX_POINTS 20 + +#define POINT_1 0x00 +#define POINT_2 0x01 +#define POINT_3 0x02 +#define POINT_4 0x03 +#define POINT_5 0x04 +#define POINT_6 0x05 +#define POINT_7 0x06 +#define POINT_8 0x07 +#define POINT_9 0x08 +#define POINT_10 0x09 + +#define SOCKETA SOCKET_A +#define SOCKETB SOCKET_B +#define SOCKETC SOCKET_C +#define SOCKETD SOCKET_D //************************************************************************************************** // Smart Water Board Class @@ -86,35 +93,40 @@ class ionSensorClass // Void class constructor ionSensorClass(); // Class constructor with socket specification - ionSensorClass(uint8_t socket); + ionSensorClass(uint8_t); // Read ADC function float read(); // These are specific functions for ions sensors // The ions sensors can be connected in any SOCKET - void setCalibrationPoints ( const float calVoltages[], - const float calConcentrations[], - uint8_t numPoints ); + void setCalibrationPoints ( const float calVoltages[], const float calConcentrations[], uint8_t numPoints); + void setCalibrationPoints(); + // Returns the ion concentration in ppm's float calculateConcentration(float input); - - int pointToPointCalibration(float calVoltages[], - float calConcentrations[], - uint8_t numPoints_); - + int pointToPointCalibration(float calVoltages[], float calConcentrations[], uint8_t numPoints_); float calculateConcentrationP2P(float input); // These are specific functions for pH sensor // The pH sensor can be connected in any SOCKET - float pHConversion(float input, float temp); - void setpHCalibrationPoints(float _calibration_point_10, - float _calibration_point_7, - float _calibration_point_4, - float _calibration_temperature); + float pHConversion(float, float); + float pHConversion(float); + + void setpHCalibrationPoints(float , float , float , float ); + // Arrays for point to point calibration + float voltages[MAX_POINTS]; + float concentrations[MAX_POINTS]; + uint8_t numPoints; + + // Calibration points for pH sensor + float calibration_point_10; + float calibration_point_7; + float calibration_point_4; + float calibration_temperature; private: @@ -122,19 +134,12 @@ class ionSensorClass float slope; float intersection; - // Calibration points for pH sensor - float calibration_point_10; - float calibration_point_7; - float calibration_point_4; - float calibration_temperature; + // Socket used by the class uint8_t _mySocket; - // Arrays for point to point calibration - float voltages[MAX_POINTS]; - float concentrations[MAX_POINTS]; - uint8_t numPoints; + }; #endif @@ -144,8 +149,8 @@ class ionSensorClass //************************************************************************************************** // Temperature Sensor class //************************************************************************************************** -#ifndef PT1000_h -#define PT1000_h +#ifndef PT1000CLASS_H +#define PT1000CLASS_H class pt1000Class { @@ -161,8 +166,8 @@ class pt1000Class //************************************************************************************************** // SOCKET1 Class //************************************************************************************************** -#ifndef SOCKET1_H -#define SOCKET1_H +#ifndef SOCKET1CLASS_H +#define SOCKET1CLASS_H // This class derivate from ionSensorClass class socket1Class : public ionSensorClass @@ -181,8 +186,8 @@ class socket1Class : public ionSensorClass //************************************************************************************************** // SOCKET2 Class //************************************************************************************************** -#ifndef SOCKET2_H -#define SOCKET2_H +#ifndef SOCKET2CLASS_H +#define SOCKET2CLASS_H // This class derivate from ionSensorClass class socket2Class : public ionSensorClass @@ -199,8 +204,8 @@ class socket2Class : public ionSensorClass //************************************************************************************************** // SOCKET3 Class //************************************************************************************************** -#ifndef SOCKET3_H -#define SOCKET3_H +#ifndef SOCKET3CLASS_H +#define SOCKET3CLASS_H // This class derivate from ionSensorClass class socket3Class : public ionSensorClass @@ -216,8 +221,8 @@ class socket3Class : public ionSensorClass //************************************************************************************************** // SOCKET4 Class //************************************************************************************************** -#ifndef SOCKET4_H -#define SOCKET4_H +#ifndef SOCKET4CLASS_H +#define SOCKET4CLASS_H // This class derivate from ionSensorClass class socket4Class : public ionSensorClass diff --git a/libraries/SmartWaterIons/utility/ADC7705.cpp b/libraries/SmartWaterIons/utility/ADC7705.cpp index f71a3fe..d08b447 100755 --- a/libraries/SmartWaterIons/utility/ADC7705.cpp +++ b/libraries/SmartWaterIons/utility/ADC7705.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: Ahmad Saad */ diff --git a/libraries/SmartWaterIons/utility/ADC7705.h b/libraries/SmartWaterIons/utility/ADC7705.h index 74fe69a..ce0c4cb 100755 --- a/libraries/SmartWaterIons/utility/ADC7705.h +++ b/libraries/SmartWaterIons/utility/ADC7705.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: Ahmad Saad */ diff --git a/libraries/TSL2561/TSL2561.cpp b/libraries/TSL2561/TSL2561.cpp new file mode 100755 index 0000000..0be6cc7 --- /dev/null +++ b/libraries/TSL2561/TSL2561.cpp @@ -0,0 +1,380 @@ +/* + * Library for managing the TSL2561 sensor (luxes accuray) + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Alejandro Gállego + */ + +#ifndef __WPROGRAM_H__ + #include "WaspClasses.h" +#endif + +#include + + +// Constructors //////////////////////////////////////////////////////////////// +TSL2561::TSL2561() +{ + _initialized = false; + _integration = TSL2561_INTEGRATIONTIME_402MS; + _gain = TSL2561_GAIN_0X; +} + +/// PRIVATE FUNCTIONS + + + +boolean TSL2561::checkID() +{ + uint8_t valueID; + + + #if TSL2561_DEBUG>0 + USB.print(F("TSL2561.Checking ID...")); + #endif + Wire.readByte(I2C_ADDRESS_TSL2561, TSL2561_CHIP_ID_REG, &valueID); + if (valueID == TSL2561_CHIP_ID_REG_CHIP_ID) + { + #if TSL2561_DEBUG>0 + USB.println(F("OK")); + #endif + return 1; + } + + #if TSL2561_DEBUG>0 + USB.println(F("error")); + #endif + return 0; + + +} + + +/* + Function: + Returns: + Parameters: + Values: +*/ +void TSL2561::enable(void) +{ + #if TSL2561_DEBUG>0 + USB.println(F("TSL2561.Enabling lux sensor")); + #endif + Wire.writeByte( I2C_ADDRESS_TSL2561, + TSL2561_COMMAND_BIT | TSL2561_CONTROL_REG, + TSL2561_CONTROL_POWERON); + + delay(100); +} + +/* + Function: + Returns: + Parameters: + Values: +*/ +void TSL2561::disable(void) +{ + #if TSL2561_DEBUG>0 + USB.println(F("TSL2561.Disabling lux sensor")); + #endif + Wire.writeByte( I2C_ADDRESS_TSL2561, + TSL2561_COMMAND_BIT | TSL2561_CONTROL_REG, + TSL2561_CONTROL_POWEROFF); + + delay(100); +} + +/* + Function: + Returns: + Parameters: + Values: +*/ +void TSL2561::setGain(tsl2561Gain_t gain) +{ + enable(); + + #if TSL2561_DEBUG>0 + USB.print(F("TSL2561.Setting gain to ")); + USB.println(gain, DEC); + #endif + + _gain = gain; + + Wire.writeByte( I2C_ADDRESS_TSL2561, + TSL2561_COMMAND_BIT | TSL2561_TIMING_REG, + _integration | _gain); + + disable(); +} + +/* + Function: + Returns: + Parameters: + Values: +*/ +void TSL2561::setTiming(tsl2561IntegrationTime_t integration) +{ + + enable(); + + #if TSL2561_DEBUG>0 + USB.print(F("TSL2561.Setting integration time to ")); + USB.println(integration, DEC); + #endif + + _integration = integration; + + Wire.writeByte( I2C_ADDRESS_TSL2561, + TSL2561_COMMAND_BIT | TSL2561_TIMING_REG, + _integration | _gain); + + disable(); +} + + +/* + Function: + Returns: + Parameters: + Values: +*/ +void TSL2561::calculateLux() +{ + unsigned long chScale; + unsigned long channel1; + unsigned long channel0; + + switch (_integration) + { + case TSL2561_INTEGRATIONTIME_13MS: + chScale = TSL2561_LUX_CHSCALE_TINT0; + break; + + case TSL2561_INTEGRATIONTIME_101MS: + chScale = TSL2561_LUX_CHSCALE_TINT1; + break; + + default: // No scaling ... integration time = 402ms + chScale = (1 << TSL2561_LUX_CHSCALE); + break; + } + + // Scale for gain (1x or 16x) + if (!_gain) + { + chScale = chScale << 4; + } + + // scale the channel values + channel0 = (full * chScale) >> TSL2561_LUX_CHSCALE; + channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE; + + // find the ratio of the channel values (Channel1/Channel0) + unsigned long ratio1 = 0; + if (channel0 != 0) + { + ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; + } + + // round the ratio value + unsigned long ratio = (ratio1 + 1) >> 1; + + unsigned int b, m; + + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) + { + b = TSL2561_LUX_B1T; + m = TSL2561_LUX_M1T; + } + else if (ratio <= TSL2561_LUX_K2T) + { + b = TSL2561_LUX_B2T; + m = TSL2561_LUX_M2T; + } + else if (ratio <= TSL2561_LUX_K3T) + { + b = TSL2561_LUX_B3T; + m = TSL2561_LUX_M3T; + } + else if (ratio <= TSL2561_LUX_K4T) + { + b = TSL2561_LUX_B4T; + m = TSL2561_LUX_M4T; + } + else if (ratio <= TSL2561_LUX_K5T) + { + b = TSL2561_LUX_B5T; + m = TSL2561_LUX_M5T; + } + else if (ratio <= TSL2561_LUX_K6T) + { + b = TSL2561_LUX_B6T; + m = TSL2561_LUX_M6T; + } + else if (ratio <= TSL2561_LUX_K7T) + { + b = TSL2561_LUX_B7T; + m = TSL2561_LUX_M7T; + } + else if (ratio > TSL2561_LUX_K8T) + { + b = TSL2561_LUX_B8T; + m = TSL2561_LUX_M8T; + } + + unsigned long temp; + temp = ((channel0 * b) - (channel1 * m)); + + // do not allow negative lux value + if (temp < 0) + { + temp = 0; + } + + // round lsb (2^(LUX_SCALE-1)) + temp += (1 << (TSL2561_LUX_LUXSCALE-1)); + + // strip off fractional portion + lux = temp >> TSL2561_LUX_LUXSCALE; + +} + +/* + Function: + Returns: + Parameters: + Values: +*/ +int8_t TSL2561::getFullLuminosity () +{ + int8_t error; + uint8_t aux_buffer[4]; + + // Enable the device by setting the control bit to 0x03 + enable(); + + // Wait x ms for ADC to complete + switch (_integration) + { + case TSL2561_INTEGRATIONTIME_13MS: + delay(14); + break; + + case TSL2561_INTEGRATIONTIME_101MS: + delay(105); + break; + + default: + delay(420); + break; + } + + error = Wire.readBytes( I2C_ADDRESS_TSL2561, + TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_CHAN0_LOW_REG, + aux_buffer, + 4); + + full = ((uint16_t) aux_buffer[1] << 8) | (uint16_t) aux_buffer[0]; + ir = ((uint16_t) aux_buffer[3] << 8) | (uint16_t) aux_buffer[2]; + + disable(); + + return error; +} + +/// PUBLIC FUNCTIONS +/// POWER AND CONFIGURATION FUNCTIONS + +/* + Function: + Returns: + Parameters: + Values: +*/ +boolean TSL2561::ON(void) +{ + + delay(100); + + if (checkID() == 0) + { + return 1; + } + + _initialized = true; + + // Set default integration time and gain + setTiming(_integration); + setGain(_gain); + + delay(400); + + return 0; +} + +int8_t TSL2561::getLuminosity() +{ + return getLuminosity( TSL2561_HIGH_RES, TSL2561_GAIN_1); +} + +int8_t TSL2561::getLuminosity(uint8_t res) +{ + return getLuminosity( res, TSL2561_GAIN_1); + +} + +int8_t TSL2561::getLuminosity(uint8_t res, bool gain) +{ + int8_t error; + + + if (gain == 0) + { + setGain(TSL2561_GAIN_0X); + } + else + { + setGain(TSL2561_GAIN_16X); + } + setTiming((tsl2561IntegrationTime_t)res); + + // Reads both channels of the sensor + error = getFullLuminosity(); + if ( error != 0) + { + return error; + } + + visible = full - ir; + + // Calculta the luxes value + calculateLux(); + + return 0; + +} + + +// Preinstantiate Objects ////////////////////////////////////////////////////// +TSL2561 TSL = TSL2561(); diff --git a/libraries/TSL2561/TSL2561.h b/libraries/TSL2561/TSL2561.h new file mode 100755 index 0000000..050b998 --- /dev/null +++ b/libraries/TSL2561/TSL2561.h @@ -0,0 +1,255 @@ +/*! \file TSL2561.h + \brief Library for managing the TSL2561 sensor (luxes accuracy) + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: Alejandro Gállego + +*/ + +/*! \def TSL2561_h + \brief The library flag + +*/ +#ifndef TSL2561_h +#define TSL2561_h + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include + +/*! Possible values: + * 0: No debug mode enabled + * 1: debug 1 + * 2: debug 2 + */ +#define TSL2561_DEBUG 0 +// #define TSL2561_DEBUG 1 +// #define TSL2561_DEBUG 2 + + +//! Sensor Specific constants +// LUX auxiliary definitions +#define TSL2561_FULLSPECTRUM 0 // channel 0 +#define TSL2561_INFRARED 1 // channel 1 +#define TSL2561_VISIBLE 2 // channel 0 - channel 1 + +#define TSL2561_LOW_RES 0 +#define TSL2561_MED_RES 1 +#define TSL2561_HIGH_RES 2 + +#define TSL2561_GAIN_1 0 +#define TSL2561_GAIN_16 1 + + +/// Register address +#define TSL2561_CONTROL_REG 0x00 +#define TSL2561_TIMING_REG 0x01 +#define TSL2561_THRESHHOLDL_LOW_REG 0x02 +#define TSL2561_THRESHHOLDL_HIGH_REG 0x03 +#define TSL2561_THRESHHOLDH_LOW_REG 0x04 +#define TSL2561_THRESHHOLDH_HIGH_REG 0x05 +#define TSL2561_INTERRUPT_REG 0x06 +#define TSL2561_CRC_REG 0x08 +#define TSL2561_CHIP_ID_REG 0x0A +#define TSL2561_CHAN0_LOW_REG 0x0C +#define TSL2561_CHAN0_HIGH_REG 0x0D +#define TSL2561_CHAN1_LOW_REG 0x0E +#define TSL2561_CHAN1_HIGH_REG 0x0F + +/// ID Register +#define TSL2561_CHIP_ID_REG_CHIP_ID 0x0A + + + + + +// Lux calculations +#define TSL2561_READBIT (0x01) +#define TSL2561_COMMAND_BIT (0x80) // Must be 1 +#define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) +#define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) +#define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write +#define TSL2561_CONTROL_POWERON (0x03) +#define TSL2561_CONTROL_POWEROFF (0x00) +#define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 +#define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 +#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 +#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE +#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE + +//Values +#define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE +#define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE +#define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE +#define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE +#define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE +#define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE +#define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE +#define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE +#define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE +#define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE +#define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE +#define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE +#define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE +#define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE +#define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE +#define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE +#define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE +#define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE +#define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE +#define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE + +#define OUTDOOR 0x01 +#define INDOOR 0x02 + +// Lux auxiliary data +typedef enum +{ + TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms, fast but low resolution + TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms, medium resolution and speed + TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms, 16-bit data but slowest conversions +} +tsl2561IntegrationTime_t; + +// Lux auxiliary data +typedef enum +{ + TSL2561_GAIN_0X = 0x00, // No gain, use in bright light to avoid sensor saturation + TSL2561_GAIN_16X = 0x10, // 16x gain, use in low light to boost sensitivity +} +tsl2561Gain_t; + +/****************************************************************************** + * Class + ******************************************************************************/ + +//! TSL2561 Class +/*! + TSL2561 Class defines all the variables and functions used to manage TSL2561 sensor + */ +class TSL2561 +{ + private: + + //! Variable : aux variable for Lux sensor + /*! + */ + tsl2561IntegrationTime_t _integration; + + //! Variable : Gain for the Lux sensor + /*! + */ + tsl2561Gain_t _gain; + + //! Variable : stores lux sensor state + /*! + */ + boolean _initialized; + + //! Enables lux sensor + /*! + \param void + + \return void + */ + void enable(void); + + //! Disables lux sensor + /*! + \param void + + \return void + */ + void disable(void); + + //! Calculate luxes measured by lux sensor + /*! + \param ch0: channel 0 + \param ch1: channel 1 + \return nothing + */ + void calculateLux(); + + //! Configures luxes sensor + /*! + \param integration: + + \return void + */ + void setTiming(tsl2561IntegrationTime_t integration); + + //! Sets Lux sensor gain + /*! + \param gain: gain to be set + + \return + */ + void setGain(tsl2561Gain_t gain); + + //! Reads lux sensor + /*! + \param + + \return lux + */ + int8_t getFullLuminosity (); + + + + boolean checkID(); + + public: + + // Constructors + TSL2561(); + + + //! Variable : value measured in luxes + /*! + */ + uint32_t lux; + + + uint16_t ir, full, visible; + + + //! Turn on the sensor and preconfigurates it + /*! + \param void + \return luxes + */ + boolean ON(void); + + int8_t getLuminosity(); + int8_t getLuminosity(uint8_t res); + int8_t getLuminosity(uint8_t res, bool gain); + +}; + + +extern TSL2561 TSL; + +#endif diff --git a/libraries/TSL2561/keywords.txt b/libraries/TSL2561/keywords.txt new file mode 100644 index 0000000..e90c4a8 --- /dev/null +++ b/libraries/TSL2561/keywords.txt @@ -0,0 +1,79 @@ +# TSL2561 # + +TSL2561_VISIBLE LITERAL1 +TSL2561_INFRARED LITERAL1 +TSL2561_FULLSPECTRUM LITERAL1 +TSL2561_ADDR_FLOAT LITERAL1 +TSL2561_PACKAGE_T_FN_CL LITERAL1 +TSL2561_READBIT LITERAL1 +TSL2561_COMMAND_BIT LITERAL1 +TSL2561_CLEAR_BIT LITERAL1 +TSL2561_WORD_BIT LITERAL1 +TSL2561_BLOCK_BIT LITERAL1 +TSL2561_CONTROL_POWERON LITERAL1 +TSL2561_CONTROL_POWEROFF LITERAL1 +TSL2561_LUX_LUXSCALE LITERAL1 +TSL2561_LUX_RATIOSCALE LITERAL1 +TSL2561_LUX_CHSCALE LITERAL1 +TSL2561_LUX_CHSCALE_TINT0 LITERAL1 +TSL2561_LUX_CHSCALE_TINT1 LITERAL1 +TSL2561_LUX_K1T LITERAL1 +TSL2561_LUX_B1T LITERAL1 +TSL2561_LUX_M1T LITERAL1 +TSL2561_LUX_K2T LITERAL1 +TSL2561_LUX_B2T LITERAL1 +TSL2561_LUX_M2T LITERAL1 +TSL2561_LUX_K3T LITERAL1 +TSL2561_LUX_B3T LITERAL1 +TSL2561_LUX_M3T LITERAL1 +TSL2561_LUX_K4T LITERAL1 +TSL2561_LUX_B4T LITERAL1 +TSL2561_LUX_M4T LITERAL1 +TSL2561_LUX_K5T LITERAL1 +TSL2561_LUX_B5T LITERAL1 +TSL2561_LUX_M5T LITERAL1 +TSL2561_LUX_K6T LITERAL1 +TSL2561_LUX_B6T LITERAL1 +TSL2561_LUX_M6T LITERAL1 +TSL2561_LUX_K7T LITERAL1 +TSL2561_LUX_B7T LITERAL1 +TSL2561_LUX_M7T LITERAL1 +TSL2561_LUX_K8T LITERAL1 +TSL2561_LUX_B8T LITERAL1 +TSL2561_LUX_M8T LITERAL1 + +TSL2561_CONTROL_REG LITERAL1 +TSL2561_TIMING_REG LITERAL1 +TSL2561_THRESHHOLDL_LOW_REG LITERAL1 +TSL2561_THRESHHOLDL_HIGH_REG LITERAL1 +TSL2561_THRESHHOLDH_LOW_REG LITERAL1 +TSL2561_THRESHHOLDH_HIGH_REG LITERAL1 +TSL2561_INTERRUPT_REG LITERAL1 +TSL2561_CRC_REG LITERAL1 +TSL2561_CHIP_ID_REG LITERAL1 +TSL2561_CHAN0_LOW_REG LITERAL1 +TSL2561_CHAN0_HIGH_REG LITERAL1 +TSL2561_CHAN1_LOW_REG LITERAL1 +TSL2561_CHAN1_HIGH_REG LITERAL1 + + +TSL2561_INTEGRATIONTIME_13MS LITERAL1 +TSL2561_INTEGRATIONTIME_101MS LITERAL1 +TSL2561_INTEGRATIONTIME_402MS LITERAL1 + +TSL2561_GAIN_0X LITERAL1 +TSL2561_GAIN_16X LITERAL1 + + +TSL2561_CHIP_ID_REG_CHIP_ID LITERAL1 + +INDOOR LITERAL1 +OUTDOOR LITERAL1 + +TSL2561 KEYWORD2 +ON KEYWORD2 +getLuminosity KEYWORD2 + +TSL KEYWORD1 + + diff --git a/libraries/UltrasoundSensor/UltrasoundSensor.cpp b/libraries/UltrasoundSensor/UltrasoundSensor.cpp new file mode 100755 index 0000000..672ebbd --- /dev/null +++ b/libraries/UltrasoundSensor/UltrasoundSensor.cpp @@ -0,0 +1,88 @@ +/* + * Library for managing the MB7040 and MB1202 sensors + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Alejandro Gállego + */ + +#ifndef __WPROGRAM_H__ + #include "WaspClasses.h" +#endif + + +#include + + +/* Function: This function performs a distance measurement + * Return: distance in cm. + * 9000 if error reading the distance + * 10000 if error reading the sensor + */ +uint16_t UltrasoundSensor::getDistance() +{ + + uint8_t HByte, LByte; + uint16_t range; + uint32_t tempo; + + delay(200); + + if( !Wire.isON ) Wire.begin(); + + Wire.beginTransmission(I2C_ADDRESS_MB7040_MB1202); + Wire.send(MB7040_MB1202_RANGE_READING); + Wire.endTransmission(); + + delay(100); //It is best to allow 100ms between readings to allow for proper acoustic dissipation. + + // Reads the measured distance + Wire.requestFrom(I2C_ADDRESS_MB7040_MB1202,0x02); + tempo = millis(); + while((Wire.available() < 2) && ((millis() - tempo) < MB7040_MB1202_I2C_READ_TIMEOUT)) + { + if (millis() < tempo) tempo = millis(); //to avoid millis overflow + } + + if (Wire.available() == 2) + { + HByte = Wire.receive(); + LByte = Wire.receive(); + Wire.endTransmission(); + + range = ((uint16_t)HByte * 256) + LByte; + if (range >= 800) + { + range = 9000; + } + + } + else + { + range = 10000; + } + + + return range; +} + + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +UltrasoundSensor Ultrasound = UltrasoundSensor(); diff --git a/libraries/UltrasoundSensor/UltrasoundSensor.h b/libraries/UltrasoundSensor/UltrasoundSensor.h new file mode 100755 index 0000000..10da383 --- /dev/null +++ b/libraries/UltrasoundSensor/UltrasoundSensor.h @@ -0,0 +1,75 @@ +/*! \file UltrasoundSensor.h + \brief Library for managing the MB7040 and MB1202 sensors + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: Alejandro Gállego + +*/ + +/*! \def UltrasoundSensor_h + \brief The library flag + + */ +#ifndef UltrasoundSensor_h +#define UltrasoundSensor_h + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include + + + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define MB7040_MB1202_I2C_READ_TIMEOUT 100 + +// Command to take a single reading +#define MB7040_MB1202_RANGE_READING 0x51 + + +/****************************************************************************** + * Class + ******************************************************************************/ + +//! UltrasoundSensor Class +/*! + UltrasoundSensor Class defines all the variables and functions used to manage MB7040 and MB1202 sensors + */ +class UltrasoundSensor +{ + public: + + //! This function performs a distance measurement + /*! + \return 0 to 735: distance in cm. + 9000 if error reading the distance + 10000 if error reading the sensor + */ + uint16_t getDistance(); + +}; + +extern UltrasoundSensor Ultrasound; + +#endif diff --git a/libraries/UltrasoundSensor/keywords.txt b/libraries/UltrasoundSensor/keywords.txt new file mode 100644 index 0000000..be3d281 --- /dev/null +++ b/libraries/UltrasoundSensor/keywords.txt @@ -0,0 +1,9 @@ +# UltrasoundSensor Keywords # + +MB7040_MB1202_I2C_READ_TIMEOUT LITERAL1 +MB7040_MB1202_RANGE_READING LITERAL1 + +getDistance KEYWORD2 + +UltrasoundSensor KEYWORD2 +Ultrasound KEYWORD1 diff --git a/libraries/WIFI/WaspWIFI.cpp b/libraries/WIFI/WaspWIFI.cpp index 0f76ef9..a689d34 100755 --- a/libraries/WIFI/WaspWIFI.cpp +++ b/libraries/WIFI/WaspWIFI.cpp @@ -1,7 +1,7 @@ /*! \file WaspWIFI.cpp * \brief Library for managing WIFI modules * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.12 + * Version: 3.0 * Design: David Gascón * Implementation: Joaquin Ruiz, Yuri Carmona */ @@ -326,29 +326,14 @@ uint8_t WaspWIFI::commandMode() OFF(); baud_rate = 9600; - // power up depending on the chosen SOCKET - if( _uartWIFI == SOCKET0 ) - { - // set multiplexer on UART0 to SOCKET0 - Utils.setMuxSocket0(); - - // set microcontroller pins as output - pinMode(XBEE_PW,OUTPUT); - - // power on the module - digitalWrite(XBEE_PW, HIGH); - } - else if( _uartWIFI == SOCKET1 ) - { - // set multiplexer on UART1 to SOCKET1 - Utils.setMuxSocket1(); - - // power on the module - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,HIGH); - } + // select multiplexer + if (_uartWIFI == SOCKET0) Utils.setMuxSocket0(); + if (_uartWIFI == SOCKET1) Utils.setMuxSocket1(); - // wait for RN171 uart port stabilization + // power up depending on the chosen SOCKET + PWR.powerSocket(_uartWIFI, HIGH); + + // wait for RN171 uart port stabilization delay(3000); closeSerial(_uartWIFI); @@ -1164,43 +1149,20 @@ WaspWIFI::WaspWIFI() //! Powers on the module and enters in command mode. bool WaspWIFI::ON(uint8_t sock) -{ - +{ + // set the uart + if (sock == SOCKET0) _uartWIFI = SOCKET0; + if (sock == SOCKET1) _uartWIFI = SOCKET1; + // previous power down prior to power up - if(sock==SOCKET0) - { - // set the uart - _uartWIFI=SOCKET0; - - } - else if(sock==SOCKET1) - { - // set the uart - _uartWIFI=SOCKET1; - } OFF(); - + + // select multiplexer + if (_uartWIFI == SOCKET0) Utils.setMuxSocket0(); + if (_uartWIFI == SOCKET1) Utils.setMuxSocket1(); + // power up depending on the chosen SOCKET - if(_uartWIFI==SOCKET0) - { - // set multiplexer on UART0 to SOCKET0 - Utils.setMuxSocket0(); - - // set microcontroller pins as output - pinMode(XBEE_PW,OUTPUT); - - // power on the module - digitalWrite(XBEE_PW, HIGH); - } - else if(_uartWIFI==SOCKET1) - { - // set multiplexer on UART1 to SOCKET1 - Utils.setMuxSocket1(); - - // power on the module - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,HIGH); - } + PWR.powerSocket(_uartWIFI, HIGH); // enter in command mode at 115200bps if( commandMode() == 1 ) @@ -1227,28 +1189,15 @@ void WaspWIFI::OFF() USB.println(F("*OFF")); #endif - // Switches OFF the module depending on the UART - if(_uartWIFI==SOCKET0) - { - // close UART0 - closeSerial(SOCKET0); - - // power down - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW, LOW); - } - else if(_uartWIFI==SOCKET1) - { - // set multiplexer on UART1 to other socket - Utils.setMuxGPS(); - - // close UART1 - closeSerial(SOCKET1); - - // power down - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,LOW); - } + // close UART + closeSerial(_uartWIFI); + + // unselect multiplexer + if (_uartWIFI == SOCKET0) Utils.setMuxUSB(); + if (_uartWIFI == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uartWIFI, LOW); // update Waspmote Register if(_uartWIFI == SOCKET0) WaspRegister &= ~(REG_SOCKET0); @@ -1281,7 +1230,7 @@ uint8_t WaspWIFI::setAutojoinAuth(uint8_t val) // Copy "set w a " strcpy_P(buffer, (char*)pgm_read_word(&(table_WIFI[8]))); snprintf(question, sizeof(question), "%s%d\r",buffer,val); - return sendCommand(question, "AOK", 5000); + return sendCommand(question, (char*)"AOK", 5000); } //! Sets the policy for automatically joining/associating with network @@ -1290,15 +1239,13 @@ uint8_t WaspWIFI::setJoinMode(uint8_t val) { char question[50]; char buffer[20]; - int retries=0; - const int MAX_RETRIES=3; // Copy "set w j " strcpy_P(buffer, (char*)pgm_read_word(&(table_WIFI[9]))); snprintf(question, sizeof(question), "%s%d\r", buffer, val); // Send command to join wlan - if( sendCommand(question, "AOK", 5000)==1 ) + if( sendCommand(question, (char*)"AOK", 5000)==1 ) { return 1; } @@ -1342,7 +1289,7 @@ uint8_t WaspWIFI::setAuthKey(uint8_t secMode, char* pass) snprintf(question, sizeof(question), "%s%s\r", buffer, pass); } // Sends the command over the UART. - return sendCommand(question, "AOK", 5000); + return sendCommand(question, (char*)"AOK", 5000); } //! Sets the link monitor timeout threshold. @@ -1487,7 +1434,7 @@ uint8_t WaspWIFI::join(char* ssid) while( retries>0 ) { // "join ??" command - if( sendCommand( question, "Associated!", Disconn_pattern, 10000, true) == 1) + if( sendCommand( question, (char*)"Associated!", Disconn_pattern, 10000, true) == 1) { // Copy "get ip\r" strcpy_P(question, (char*)pgm_read_word(&(table_WIFI[72]))); @@ -1776,7 +1723,7 @@ uint8_t WaspWIFI::setDHCPoptions(uint8_t val) // Copy "set i d " strcpy_P(buffer, (char*)pgm_read_word(&(table_WIFI[36]))); snprintf(question, sizeof(question), "%s%d\r", buffer, val); - return sendCommand(question, "AOK", 5000); + return sendCommand(question, (char*)"AOK", 5000); } //! Sets the IP options. @@ -1801,7 +1748,7 @@ uint8_t WaspWIFI::setConnectionOptions(uint8_t val) // Copy "set i p " strcpy_P(buffer, (char*)pgm_read_word(&(table_WIFI[38]))); snprintf(question, sizeof(question), "%s%d\r", buffer, val); - return sendCommand(question, "AOK", 5000); + return sendCommand(question, (char*)"AOK", 5000); } //! Sets the TCP connection password. Provides minimal authentication by @@ -1923,12 +1870,11 @@ uint8_t WaspWIFI::getFile( char* filename, { char question[128]; char buffer[20]; - uint16_t plong=0; int maxBuffer=256; int i=0; int readRet=0; unsigned long previous; - bool stop, end, timeout; + bool end, timeout; unsigned long total=0; // get statistics @@ -4025,10 +3971,8 @@ bool WaspWIFI::isConnected() bool WaspWIFI::isConnected(unsigned long timeout) { char question[20]; - char buffer[20]; - uint16_t i=0; - bool result = false; - unsigned long aux_previous; + char buffer[20]; + bool result = false; #ifdef DEBUG_WIFI USB.println(F("get ip\r")); @@ -5533,11 +5477,11 @@ uint8_t WaspWIFI::setRTCfromWiFi() answer[i]='\0'; retries--; // Check if module did set the time - if ( findPattern((uint8_t*)answer, "NOT SET",i) == -1 ) + if ( findPattern((uint8_t*)answer, (char*)"NOT SET",i) == -1 ) { retries = 0; } - else if ((findPattern((uint8_t*)answer, "NOT SET",i)!=-1) && retries == 0) + else if ((findPattern((uint8_t*)answer, (char*)"NOT SET",i)!=-1) && retries == 0) { return 1; } diff --git a/libraries/WIFI/WaspWIFI.h b/libraries/WIFI/WaspWIFI.h index f80df1a..6441c94 100755 --- a/libraries/WIFI/WaspWIFI.h +++ b/libraries/WIFI/WaspWIFI.h @@ -1,7 +1,7 @@ /*! \file WaspWIFI.h \brief Library for managing WIFI modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.8 + Version: 3.0 Design: David Gascón Implementation: Joaquín Ruiz, Yuri Carmona diff --git a/libraries/WIFI/keywords.txt b/libraries/WIFI/keywords.txt index f03a66e..abf3e64 100644 --- a/libraries/WIFI/keywords.txt +++ b/libraries/WIFI/keywords.txt @@ -42,8 +42,9 @@ IP_STATUS LITERAL1 BLO LITERAL1 NOBLO LITERAL1 CHECK_VERSION LITERAL1 +OTA_ver_file LITERAL1 +NO_OTA LITERAL1 -answer KEYWORD2 WaspWIFI KEYWORD2 ON KEYWORD2 OFF KEYWORD2 @@ -123,4 +124,4 @@ findPattern KEYWORD2 requestOTA KEYWORD2 setRTCfromWiFi KEYWORD2 -WIFI KEYWORD3 +WIFI KEYWORD1 diff --git a/libraries/WIFI_PRO/WaspWIFI_PRO.cpp b/libraries/WIFI_PRO/WaspWIFI_PRO.cpp new file mode 100755 index 0000000..55c4c69 --- /dev/null +++ b/libraries/WIFI_PRO/WaspWIFI_PRO.cpp @@ -0,0 +1,6530 @@ +/*! \file WaspWIFI_PRO.cpp + * \brief Library for managing WIFI_PRO modules + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Yuri Carmona + */ + +#ifndef __WPROGRAM_H__ +#include "WaspClasses.h" +#endif + +#include "WaspWIFI_PRO.h" + +//! MACROS +#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,N,...) N +#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) +#define GEN_ATCOMMAND1(...) generator(1, NARGS(__VA_ARGS__) - 1, __VA_ARGS__) +#define GEN_ATCOMMAND2(...) generator(2, NARGS(__VA_ARGS__) - 1, __VA_ARGS__) +#define GEN_ATCOMMAND3(...) generator(3, NARGS(__VA_ARGS__) - 1, __VA_ARGS__) +#define GEN_ATQUERY(...) generator(4, NARGS(__VA_ARGS__) - 1, __VA_ARGS__) +#define GEN_ATQUERY2(...) generator(5, NARGS(__VA_ARGS__) - 1, __VA_ARGS__) + + +/// PRIVATE METHODS //////////////////////////////////////////////////////////// + + +void WaspWIFI_PRO::generator(uint8_t type, int n, const char *cmdCode, ...) +{ + // define pointer + char* pointer; + + // clear buffer + memset( _command, 0x00, sizeof(_command) ); + + // add "at+i" + strncat(_command, AT_I, strlen(AT_I) ); + // add command code + strncat(_command, cmdCode, strlen(cmdCode) ); + + // if number of arguments is greater than zero + // then add the corresponding delimiter + if (n > 0) + { + // Add delimiter type + switch (type) + { + case TYPE_SET_EQ: strncat(_command, "=", 1 ); break; + case TYPE_SET_DOT: strncat(_command, ":", 1 ); break; + case TYPE_ASSIGN: strncat(_command, "~", 1 ); break; + default: + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error type\n")); + #endif + return (void)0; + } + } + else if (n == 0) + { + // Add delimiter type + switch (type) + { + case TYPE_READ: strncat(_command, "?", 1 ); break; + case TYPE_ALLOWED: strncat(_command, "=?", 2 ); break; + default: break; + } + } + + // if it is a set command type add argument in list adding ',' in between + if( (type == TYPE_SET_EQ) + || (type == TYPE_SET_DOT) ) + { + // initialize variable argument list + va_list args; + va_start(args, cmdCode); + + // iterate through all arguments to add to the buffer + for (int i = 0; i < n; i++) + { + // get the new argument + pointer = va_arg( args, char* ); + + // continue if the argument is NULL + if (pointer == NULL) + { + continue; + } + + // add ',' except for the first argument + if (i != 0) + { + strncat(_command, ",", 1 ); + } + + // calculate size after adding the new argument to check if + // the new arguments fits inside the buffer or not + size_t next_size = strlen(pointer) + strlen( _command ) + strlen("\r"); + + if (next_size < sizeof( _command)-1) + { + // add the new argument to buffer + strncat( _command, pointer, strlen(pointer)); + } + else + { + //error + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("not enough buffer size\n")); + #endif + memset( _command, 0x00, sizeof(_command) ); + return (void)0; + } + } + + // end using variable argument list + va_end(args); + } + else + { + + } + + // add CR at the end of the command + strncat(_command, "\r", strlen("\r") ); + + // show command + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("_command: ")); + USB.println( _command ); + #endif +} + + + +void WaspWIFI_PRO::printErrorCode() +{ + printErrorCode( _errorCode); +} + +#if DEBUG_WIFI_PRO > 0 +void WaspWIFI_PRO::printErrorCode( uint16_t error ) +{ + PRINT_WIFI_PRO(F("==> ERROR CODE: ")); + switch (error) + { + case ERROR_CODE_0000: USB.println(F("Timeout")); break; + case ERROR_CODE_0010: USB.println(F("SD not present")); break; + case ERROR_CODE_0011: USB.println(F("file not created")); break; + case ERROR_CODE_0012: USB.println(F("SD error open file")); break; + case ERROR_CODE_0013: USB.println(F("SD error set file offset")); break; + case ERROR_CODE_0014: USB.println(F("SD error writing")); break; + case ERROR_CODE_0020: USB.println(F("rx buffer full")); break; + case ERROR_CODE_0021: USB.println(F("error downloading UPGRADE.TXT")); break; + case ERROR_CODE_0022: USB.println(F("filename in UPGRADE.TXT is not a 7-byte name")); break; + case ERROR_CODE_0023: USB.println(F("no FILE label is found in UPGRADE.TXT")); break; + case ERROR_CODE_0024: USB.println(F("NO_FILE is defined as FILE in UPGRADE.TXT")); break; + case ERROR_CODE_0025: USB.println(F("no PATH label is found in UPGRADE.TXT")); break; + case ERROR_CODE_0026: USB.println(F("no SIZE label is found in UPGRADE.TXT")); break; + case ERROR_CODE_0027: USB.println(F("no VERSION label is found in UPGRADE.TXT")); break; + case ERROR_CODE_0028: USB.println(F("version indicated in UPGRADE.TXT is lower/equal to Waspmote's version")); break; + case ERROR_CODE_0029: USB.println(F("file size does not match the indicated in UPGRADE.TXT")); break; + case ERROR_CODE_0030: USB.println(F("error downloading binary file")); break; + case ERROR_CODE_0031: USB.println(F("invalid data length")); break; + case ERROR_CODE_0041: USB.println(F("Illegal delimiter")); break; + case ERROR_CODE_0042: USB.println(F("Illegal value")); break; + case ERROR_CODE_0043: USB.println(F("CR expected ")); break; + case ERROR_CODE_0044: USB.println(F("Number expected")); break; + case ERROR_CODE_0045: USB.println(F("CR or ‘,’ expected")); break; + case ERROR_CODE_0046: USB.println(F("DNS expected")); break; + case ERROR_CODE_0047: USB.println(F("‘:’ or ‘~’ expected")); break; + case ERROR_CODE_0048: USB.println(F("String expected")); break; + case ERROR_CODE_0049: USB.println(F("‘:’ or ‘=’ expected")); break; + case ERROR_CODE_0050: USB.println(F("Text expected")); break; + case ERROR_CODE_0051: USB.println(F("Syntax error")); break; + case ERROR_CODE_0052: USB.println(F("‘,’ expected")); break; + case ERROR_CODE_0053: USB.println(F("Illegal cmd code")); break; + case ERROR_CODE_0054: USB.println(F("Error when setting parameter")); break; + case ERROR_CODE_0055: USB.println(F("Error when getting parameter value")); break; + case ERROR_CODE_0056: USB.println(F("User abort")); break; + case ERROR_CODE_0057: USB.println(F("Error when trying to establish PPP")); break; + case ERROR_CODE_0058: USB.println(F("Error when trying to establish SMTP")); break; + case ERROR_CODE_0059: USB.println(F("Error when trying to establish POP3")); break; + case ERROR_CODE_0060: USB.println(F("Single session body for MIME exceeds the maximum allowed")); break; + case ERROR_CODE_0061: USB.println(F("Internal memory failure")); break; + case ERROR_CODE_0062: USB.println(F("User aborted the system")); break; + case ERROR_CODE_0063: USB.println(F("~CTSH needs to be LOW to change to hardware flow control")); break; + case ERROR_CODE_0064: USB.println(F("User aborted last cmd using ‘---’")); break; + case ERROR_CODE_0065: USB.println(F("iChip unique ID already exists")); break; + case ERROR_CODE_0066: USB.println(F("Error when setting the MIF parameter")); break; + case ERROR_CODE_0067: USB.println(F("Cmd ignored as irrelevant")); break; + case ERROR_CODE_0068: USB.println(F("iChip serial number already exists")); break; + case ERROR_CODE_0069: USB.println(F("Timeout on host communication")); break; + case ERROR_CODE_0070: USB.println(F("Modem failed to respond")); break; + case ERROR_CODE_0071: USB.println(F("No dial tone response")); break; + case ERROR_CODE_0072: USB.println(F("No carrier modem response")); break; + case ERROR_CODE_0073: USB.println(F("Dial failed")); break; + case ERROR_CODE_0074: USB.println(F("WLAN connection lost")); break; + case ERROR_CODE_0075: USB.println(F("Access denied to ISP server")); break; + case ERROR_CODE_0076: USB.println(F("Unable to locate POP3 server")); break; + case ERROR_CODE_0077: USB.println(F("POP3 server timed out")); break; + case ERROR_CODE_0078: USB.println(F("Access denied to POP3 server")); break; + case ERROR_CODE_0079: USB.println(F("POP3 failed ")); break; + case ERROR_CODE_0080: USB.println(F("No suitable message in mailbox")); break; + case ERROR_CODE_0081: USB.println(F("Unable to locate SMTP server")); break; + case ERROR_CODE_0082: USB.println(F("SMTP server timed out")); break; + case ERROR_CODE_0083: USB.println(F("SMTP failed")); break; + case ERROR_CODE_0086: USB.println(F("Writing to internal non-volatile parameters database failed")); break; + case ERROR_CODE_0087: USB.println(F("Web server IP registration failed")); break; + case ERROR_CODE_0088: USB.println(F("Socket IP registration failed")); break; + case ERROR_CODE_0089: USB.println(F("E-mail IP registration failed")); break; + case ERROR_CODE_0090: USB.println(F("IP registration failed for all methods specified")); break; + case ERROR_CODE_0094: USB.println(F("In Always Online mode, connection was lost and re-established")); break; + case ERROR_CODE_0096: USB.println(F("A remote host, which had taken over iChip through the LATI port, was disconnected")); break; + case ERROR_CODE_0100: USB.println(F("Error restoring default parameters")); break; + case ERROR_CODE_0101: USB.println(F("No ISP access numbers defined")); break; + case ERROR_CODE_0102: USB.println(F("No USRN defined")); break; + case ERROR_CODE_0103: USB.println(F("No PWD entered")); break; + case ERROR_CODE_0104: USB.println(F("No DNS defined")); break; + case ERROR_CODE_0105: USB.println(F("POP3 server not defined")); break; + case ERROR_CODE_0106: USB.println(F("MBX (mailbox) not defined")); break; + case ERROR_CODE_0107: USB.println(F("MPWD (mailbox password) not defined")); break; + case ERROR_CODE_0108: USB.println(F("TOA (addressee) not defined")); break; + case ERROR_CODE_0109: USB.println(F("REA (return e-mail address) not defined")); break; + case ERROR_CODE_0110: USB.println(F("SMTP server not defined")); break; + case ERROR_CODE_0111: USB.println(F("Serial data overflow")); break; + case ERROR_CODE_0112: USB.println(F("Illegal cmd when modem online")); break; + case ERROR_CODE_0113: USB.println(F("Remote firmware update attempted but not completed. The original firmware remained intact.")); break; + case ERROR_CODE_0114: USB.println(F("E-mail parameters update rejected")); break; + case ERROR_CODE_0115: USB.println(F("SerialNET could not be started due to missing parameters")); break; + case ERROR_CODE_0116: USB.println(F("Error parsing a new trusted CA certificate")); break; + case ERROR_CODE_0117: USB.println(F("Error parsing a new Private Key")); break; + case ERROR_CODE_0118: USB.println(F("Protocol specified in the USRV parameter does not exist or is unknown")); break; + case ERROR_CODE_0119: USB.println(F("WPA passphrase too short has to be 8-63 chars")); break; + case ERROR_CODE_0122: USB.println(F("SerialNET error: Host Interface undefined (HIF=0)")); break; + case ERROR_CODE_0123: USB.println(F("SerialNET mode error: Host baud rate cannot be determined")); break; + case ERROR_CODE_0124: USB.println(F("SerialNET over TELNET error: HIF parameter must be set to 1 or 2")); break; + case ERROR_CODE_0125: USB.println(F("Invalid WEP key")); break; + case ERROR_CODE_0126: USB.println(F("Invalid parameters’ profile number")); break; + case ERROR_CODE_0128: USB.println(F("Product ID already exists")); break; + case ERROR_CODE_0129: USB.println(F("HW pin can not be changed after Product-ID was set ")); break; + case ERROR_CODE_0200: USB.println(F("Socket does not exist")); break; + case ERROR_CODE_0201: USB.println(F("Socket empty on receive")); break; + case ERROR_CODE_0202: USB.println(F("Socket not in use")); break; + case ERROR_CODE_0203: USB.println(F("Socket down")); break; + case ERROR_CODE_0204: USB.println(F("No available sockets")); break; + case ERROR_CODE_0206: USB.println(F("PPP open failed for socket")); break; + case ERROR_CODE_0207: USB.println(F("Error creating socket")); break; + case ERROR_CODE_0208: USB.println(F("Socket send error")); break; + case ERROR_CODE_0209: USB.println(F("Socket receive error")); break; + case ERROR_CODE_0210: USB.println(F("PPP down for socket")); break; + case ERROR_CODE_0212: USB.println(F("Socket flush error ")); break; + case ERROR_CODE_0215: USB.println(F("No carrier error on socket operation")); break; + case ERROR_CODE_0216: USB.println(F("General exception")); break; + case ERROR_CODE_0217: USB.println(F("Out of memory")); break; + case ERROR_CODE_0218: USB.println(F("An STCP (Open Socket) cmd specified a local port number that is already in use")); break; + case ERROR_CODE_0219: USB.println(F("SSL initialization/internal CA certificate loading error")); break; + case ERROR_CODE_0220: USB.println(F("SSL3 negotiation error")); break; + case ERROR_CODE_0221: USB.println(F("Illegal SSL socket handle. Must be an open and active TCP socket.")); break; + case ERROR_CODE_0222: USB.println(F("Trusted CA certificate does not exist")); break; + case ERROR_CODE_0224: USB.println(F("Decoding error on incoming SSL data")); break; + case ERROR_CODE_0225: USB.println(F("No additional SSL sockets available")); break; + case ERROR_CODE_0226: USB.println(F("Maximum SSL packet size (2KB) exceeded")); break; + case ERROR_CODE_0227: USB.println(F("AT+iSSND cmd failed because size of stream sent exceeded 2048 bytes")); break; + case ERROR_CODE_0228: USB.println(F("AT+iSSND cmd failed because checksum calculated does not match checksum sent by host")); break; + case ERROR_CODE_0229: USB.println(F("SSL parameters are missing ")); break; + case ERROR_CODE_0230: USB.println(F("Maximum packet size (4GB) exceeded")); break; + case ERROR_CODE_0300: USB.println(F("HTTP server unknown")); break; + case ERROR_CODE_0301: USB.println(F("HTTP server timeout ")); break; + case ERROR_CODE_0303: USB.println(F("No URL specified ")); break; + case ERROR_CODE_0304: USB.println(F("Illegal HTTP host name")); break; + case ERROR_CODE_0305: USB.println(F("Illegal HTTP port number")); break; + case ERROR_CODE_0306: USB.println(F("Illegal URL address")); break; + case ERROR_CODE_0307: USB.println(F("URL address too long ")); break; + case ERROR_CODE_0308: USB.println(F("The AT+iWWW cmd failed because iChip does not contain a home page")); break; + case ERROR_CODE_0309: USB.println(F("WEB server is already active with a different backlog.")); break; + case ERROR_CODE_0400: USB.println(F("MAC address exists")); break; + case ERROR_CODE_0401: USB.println(F("No IP address")); break; + case ERROR_CODE_0402: USB.println(F("Wireless LAN power set failed")); break; + case ERROR_CODE_0403: USB.println(F("Wireless LAN radio control failed")); break; + case ERROR_CODE_0404: USB.println(F("Wireless LAN reset failed")); break; + case ERROR_CODE_0405: USB.println(F("Wireless LAN hardware setup failed")); break; + case ERROR_CODE_0406: USB.println(F("Cmd failed because WiFi module is currently busy")); break; + case ERROR_CODE_0407: USB.println(F("Illegal WiFi channel")); break; + case ERROR_CODE_0408: USB.println(F("Illegal SNR threshold")); break; + case ERROR_CODE_0409: USB.println(F("WPA connection process has not yet completed")); break; + case ERROR_CODE_0410: USB.println(F("The network connection is offline (modem)")); break; + case ERROR_CODE_0411: USB.println(F("Cmd is illegal when Bridge mode is active")); break; + case ERROR_CODE_0501: USB.println(F("Communications platform already active")); break; + case ERROR_CODE_0505: USB.println(F("Cannot open additional FTP session – all FTP handles in use")); break; + case ERROR_CODE_0506: USB.println(F("Not an FTP session handle")); break; + case ERROR_CODE_0507: USB.println(F("FTP server not found")); break; + case ERROR_CODE_0508: USB.println(F("Timeout when connecting to FTP server")); break; + case ERROR_CODE_0509: USB.println(F("Failed to login to FTP server (bad username or password or account)")); break; + case ERROR_CODE_0510: USB.println(F("FTP cmd could not be completed")); break; + case ERROR_CODE_0511: USB.println(F("FTP data socket could not be opened")); break; + case ERROR_CODE_0512: USB.println(F("Failed to send data on FTP data socket")); break; + case ERROR_CODE_0513: USB.println(F("FTP shutdown by remote server")); break; + case ERROR_CODE_0550: USB.println(F("Telnet server not found")); break; + case ERROR_CODE_0551: USB.println(F("Timeout when connecting to Telnet server")); break; + case ERROR_CODE_0552: USB.println(F("Telnet cmd could not be completed")); break; + case ERROR_CODE_0553: USB.println(F("Telnet session shutdown by remote server")); break; + case ERROR_CODE_0554: USB.println(F("A Telnet session is not currently active")); break; + case ERROR_CODE_0555: USB.println(F("A Telnet session is already open")); break; + case ERROR_CODE_0556: USB.println(F("Telnet server refused to switch to BINARY mode")); break; + case ERROR_CODE_0557: USB.println(F("Telnet server refused to switch to ASCII mode")); break; + case ERROR_CODE_0560: USB.println(F("Client could not retrieve a ring response e-mail")); break; + case ERROR_CODE_0561: USB.println(F("Remote peer closed the SerialNET socket")); break; + case ERROR_CODE_0570: USB.println(F("PING destination not found")); break; + case ERROR_CODE_0571: USB.println(F("No reply to PING request")); break; + case ERROR_CODE_0600: USB.println(F("Port Forwarding Rule will create ambiguous NAT entry")); break; + case ERROR_CODE_0084: + case ERROR_CODE_0085: + case ERROR_CODE_0091: + case ERROR_CODE_0092: + case ERROR_CODE_0093: + case ERROR_CODE_0098: + case ERROR_CODE_0099: + case ERROR_CODE_0120: + case ERROR_CODE_0121: + case ERROR_CODE_0223: + case ERROR_CODE_0302: + case ERROR_CODE_0500: + case ERROR_CODE_0502: + case ERROR_CODE_0503: + case ERROR_CODE_0504: + case ERROR_CODE_0514: + case ERROR_CODE_0558: + case ERROR_CODE_0559: USB.println(F("RESERVED")); break; + default: USB.println(F("UNKNOWN ***")); + } +} +#else +void WaspWIFI_PRO::printErrorCode( uint16_t error ) +{ + USB.print(F("==> ERROR CODE: ")); + USB.println( error, DEC); +} +#endif + + + +/* + * name: print all info in 'socket' structure + * + * @return '0' if ok; '1' error + * + */ +void WaspWIFI_PRO::printSockets() +{ + bool first = true; + for (int i = 0; i < 10; i++) + { + if (socket[i].status == 0) + { + if (first) + { + first = false; + USB.println(F("++++++++++++++")); + } + USB.print(F("handle:")); + USB.println(socket[i].handle); + USB.print(F("ip:")); + USB.println(socket[i].ip); + USB.print(F("port:")); + USB.println(socket[i].port); + USB.println(F("++++++++++++++")); + } + } +} + + + + +/* + * name: getErrorCode() + * This function waits until a ')' character is found in order to parse the + * complete " (%u)" string. This function must be called after receiving a + * "I/ERROR" response from the module because the complete "I/ERROR (%u)" is + * going to be received + * + * If error code is parsed succesfully then the attribute _errorCode stores + * this error information + * + * @return '0' error; '1' ok + */ +uint16_t WaspWIFI_PRO::getErrorCode() +{ + uint8_t status; + char format[20]; + + // " (%u)" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[0]))); + + + // wait for "(nnn)" last parenthesis character + status = waitFor((char*)")", 3000 ); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("I/ERROR\n")); + #endif + + if (status == 0) + { + return 0; + } + else + { + // get error code from response + sscanf( (char*)_buffer, format, &_errorCode ); + + #if WIFI_DEBUG > 0 + printErrorCode( _errorCode ); + #endif + return 1; + } + +} + + + +/* + * name: getResponse + * @brief Wait for "(nnn)" last parenthesis character + * @return '0' error; '1' ok; 'otherwise' see error code table + */ +uint16_t WaspWIFI_PRO::getResponse() +{ + uint8_t status; + + // wait for "(nnn)" last parenthesis character + status = waitFor((char*)")", 3000 ); + + if (status == 0) + { + return 0; + } + else + { + return 1; + } + +} + + + +/* + * name: getResponseValue + * @brief This function expects to receive a response with the following + * format: I/. So, this function tries to get this + * response and parse the field + * + * @return '0' error; '1' ok + */ +uint16_t WaspWIFI_PRO::getResponseValue() +{ + uint8_t status; + char format_error[20]; + char format_ok[20]; + int result; + + // "I/ERROR (%u)\r\n" + strcpy_P( format_error, (char*)pgm_read_word(&(table_WIFI_FORMAT[1]))); + // "I/%lu\r\n" + strcpy_P( format_ok, (char*)pgm_read_word(&(table_WIFI_FORMAT[2]))); + + // wait for "\r\n" + status = waitFor( EOL_CR_LF, 20000); + + if (status == 0) + { + // timeout + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[getResponseValue] No answer\n")); + #endif + _errorCode = ERROR_CODE_0000; + return 0; + } + else + { + // check: I/ERROR() + if (find( _buffer, _length, I_ERROR) == true) + { + result = sscanf( (char*)_buffer, format_error, &_errorCode ); + + if (result != 1) + { + _errorCode = 1; + } + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[getResponseValue] I/ERROR found: ")); + printErrorCode(); + #endif + return 0; + } + + // check: I/ + if (find( _buffer, _length, I_SLASH) == true) + { + result = sscanf( (char*)_buffer, format_ok, &_value ); + + if (result == 1) + { + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[getResponseValue] I/ found but no \n")); + #endif + return 0; + } + } + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[getResponseValue] No pattern found:")); + USB.println( _buffer, _length ); + #endif + return 0; + } + +} + + +/* + * name: getResponseValue2 + * @brief This function expects to receive a response with the following + * format: . So, this function tries to get this + * response and parse the field + * + * @return '0' error; '1' ok + */ +uint16_t WaspWIFI_PRO::getResponseValue2() +{ + uint8_t status; + char pattern[20]; + char format_ok[20]; + char format_error[20]; + int result; + + // "\r\n" + strcpy_P( pattern, (char*)pgm_read_word(&(table_WIFI_FORMAT[3]))); + // "ERROR (" + strcpy_P( format_error, (char*)pgm_read_word(&(table_WIFI_FORMAT[4]))); + // "%lu\r\n" + strcpy_P( format_ok, (char*)pgm_read_word(&(table_WIFI_FORMAT[5]))); + + // wait for "\r\n" + status = waitFor( pattern, format_error, 10000 ); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 0; + } + else if (status == 1) + { + // pattern found then parse: + result = sscanf( (char*)_buffer, format_ok, &_value ); + + if (result == 1) + { + return 1; + } + else + { + return 0; + } + + return 0; + } + else if (status == 2) + { + // error pattern found then parse: ")" + status = getErrorCode(); + if (status == 1) + { + printErrorCode(_errorCode); + } + return 0; + } + else + { + return 0; + } + +} + + + +/* + * name: getResponseValue3 + * @brief This function expects to receive a response with the following + * format: ",,...,)". So, this function tries to + * get these responses and parse the fields + * + * @return '0' error; '1' ok + */ +uint8_t WaspWIFI_PRO::getResponseValue3() +{ + uint8_t status; + char* pointer; + int i = 0; + char delimiters[20]; + + // " ,)" + strcpy_P( delimiters, (char*)pgm_read_word(&(table_WIFI_FORMAT[17]))); + + // wait for ")" + status = waitFor((char*)")", 1000 ); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 0; + } + else if (status == 1) + { + pointer = strtok((char*)_buffer, delimiters); + while ((pointer != NULL) && (i<_backlog)) + { + if (atoi(pointer) == -1) + { + socket[i].status = -1; + } + else + { + socket[i].status = 0; + socket[i].handle = atoi(pointer); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("socket[")); + USB.print(i,DEC); + USB.print(F("].handle=")); + USB.println(socket[i].handle,DEC); + #endif + } + pointer = strtok (NULL, delimiters); + i++; + } + + return 1; + } + else + { + return 0; + } +} + + + + +/* + * name: getResponseValue4 + * This function expects to receive a response with the following format: + * ":)" + * So, this function tries to get these responses and parse the fields + * + * @return '0' error; '1' ok + */ +uint8_t WaspWIFI_PRO::getResponseValue4(uint8_t index) +{ + uint8_t status; + char* pointer; + + // wait for ")" + status = waitFor((char*)")", 1000); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 0; + } + else if (status == 1) + { + // split string into pieces + pointer = strtok((char*)_buffer, " :)"); + if (pointer == NULL) return 0; + + // get first field: IP address + memset(socket[index].ip, 0x00, 16); + if (strlen(pointer) > 15) return 0; + strncpy(socket[index].ip, pointer, strlen(pointer) ); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("socket[")); + USB.print(index,DEC); + USB.print(F("].ip:")); + USB.println(socket[index].ip); + #endif + + // get second field: port + pointer = strtok (NULL, " :)"); + if (pointer == NULL) return 0; + socket[index].port = atoi(pointer); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("socket[")); + USB.print(index,DEC); + USB.print(F("].port:")); + USB.println(socket[index].port); + #endif + + return 1; + } + else + { + return 0; + } +} + + + +/* + * name: getResponseValue5 + * @brief This function expects to receive a response with the following + * format: ", , ... ,)" + * So, this function tries to get these responses and parse the + * fields. It is used by the AT+iRP4 function to parse info after + * finding "I/(" + * @return '0' error; '1' ok + */ +uint8_t WaspWIFI_PRO::getResponseValue5() +{ + uint8_t status; + char* pointer; + int i = 0; + char delimiters[20]; + + // " ,)" + strcpy_P( delimiters, (char*)pgm_read_word(&(table_WIFI_FORMAT[17]))); + + // wait for ")" + status = waitFor((char*)")", 1000 ); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 0; + } + else if (status == 1) + { + pointer = strtok((char*)_buffer, delimiters); + while ((pointer != NULL) && (i < _backlog)) + { + socket[i].size = atoi(pointer); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("socket[")); + USB.print(i,DEC); + USB.print(F("].size=")); + USB.println(socket[i].size,DEC); + #endif + + pointer = strtok (NULL, delimiters); + i++; + } + + return 1; + } + else + { + return 0; + } +} + + + + +/* + * name: parseResponse + * @brief When this function is called, the answer to be parsed must be in + * '_buffer'. Then the pattern "nnn)" is found and parsed. + * @param uint16_t* number: pointer to number to parse in "nnn)" + * @return '0' ok; '1' error + */ +uint8_t WaspWIFI_PRO::parseResponse( uint16_t* number ) +{ + int result; + char format[10]; + + // "%u)" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[12]))); + + // parse "nnn)" contents in _buffer + result = sscanf( (char*)_buffer, format, number ); + + if (result == 0) + { + *number = 0; + return 1; + } + + return 0; +} + + + +/* + * name: parseResponse2 + * @param uint16_t* number: pointer to number to parse in "nnn:" + * @return '0' ok; '1' error + */ +uint8_t WaspWIFI_PRO::parseResponse2(uint16_t* number) +{ + int result; + char format[10]; + + // "I/%u:" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[13]))); + + // parse "I/:" contents in _buffer + result = sscanf( (char*)_buffer, format, number ); + + if (result == 0) + { + *number = 0; + return 1; + } + + return 0; +} + + +/* + * name: parseResponse3 + * @param uint16_t* number: pointer to number to parse in "nnn:" + * @return '0' ok; '1' error + */ +uint8_t WaspWIFI_PRO::parseResponse3() +{ + int result; + uint8_t error; + char format[50]; + + // define time vars + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t date; + uint8_t month; + uint8_t year; + uint8_t yearH; + uint8_t gmt_hour; + uint8_t gmt_min; + + // "%02u%02u-%02u-%02uT%02u:%02u:%02u+%02u:%02u" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[14]))); + + /* At this point, _buffer is supposed to have a pattern like this: + * "AT+iRP8\r\nYYYY-MM-DDTHH:MM:SS+HH:MM\r\nI/OK" + * So, parse time settings + */ + + char* pointer = strstr( (char*) _buffer, EOL_CR_LF); + if (pointer == NULL) return 1; + + // go to correct index + pointer++; + pointer++; + + + // parse "YYYY-MM-DDTHH:MM:SS+HH:MM" contents in _buffer + result = sscanf(pointer, + format, + &yearH, + &year, + &month, + &date, + &hour, + &minute, + &second, + &gmt_hour, + &gmt_min); + + if (result != 9) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("parse failed\n")); + #endif + return 1; + } + + // check good contents + if ((year == 0) + || (month == 0) + || (date == 0)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("bad RP8 answer\n")); + #endif + return 1; + } + + // set time to RTC + RTC.ON(); + error = RTC.setTime(year, + month, + date, + RTC.dow(year, month, date), + hour, + minute, + second); + if (error == 0) + { + return 0; + } + else + { + return 1; + } +} + + + + + +/* + * name: parseResponse4 + * Parse the info stored in _buffer with the format: + * AT+i!rp10\r\n + * ,,,,,\r\n + * I/OK\r\n + * + * @return '0' ok; '1' error + */ +uint8_t WaspWIFI_PRO::parseResponse4() +{ + char* pointer; + int i = 0; + char delimiters[10]; + + // delimiter chars are: " ," + strcpy_P( delimiters, (char*)pgm_read_word(&(table_WIFI_FORMAT[23]))); + + // find first "\r\n" + pointer = strstr((char*) _buffer, EOL_CR_LF); + if (pointer == NULL) return 1; + + // move to start skipping "\r\n" chars + pointer++; + pointer++; + + // At this moment, pointer: ,,,,,\r\n + pointer = strtok( pointer, delimiters); + while ((pointer != NULL) && (i<6)) + { + if (i == 0) + { + strncpy( _essid, pointer, sizeof(_essid) ); + } + else if (i == 1) + { + strncpy( _bssid, pointer, sizeof(_bssid) ); + } + else if (i == 4) + { + _channel = atoi(pointer); + } + else if (i == 5) + { + _snr = atoi(pointer); + } + + pointer = strtok (NULL, delimiters); + i++; + } + + return 0; + +} + + +/* + * name: parseResponse + * @brief When this function is called, the answer to be parsed must be in + * '_buffer'. Then the pattern "nnn)" is found and parsed. + * @param uint16_t* number: pointer to number to parse in "nnn)" + * @return '0' ok; '1' error + */ +uint8_t WaspWIFI_PRO::parseResponse5( int* number ) +{ + int result; + char format[10]; + + // "%d)" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[25]))); + + // parse "nnn)" contents in _buffer + result = sscanf( (char*)_buffer, format, number ); + + if (result == 0) + { + *number = 0; + return 1; + } + + return 0; +} + + +/// PUBLIC METHODS ///////////////////////////////////////////////////////////// + + +/*! + * @brief It powers on the module and checks communication via UART + * @param socket: SOCKET0 or SOCKET1 + * @return '0' ok; '1' error + * + */ +uint8_t WaspWIFI_PRO::ON( uint8_t socket ) +{ + uint8_t status; + int retries; + int total_attempts = 2; + + // store the UART to be used + _uart = socket; + _baudrate = 115200; + _def_delay = 50; + + while (total_attempts > 0) + { + + // select multiplexer + if (_uart == SOCKET0) + { + Utils.setMuxSocket0(); + } + else if (_uart == SOCKET1) + { + Utils.setMuxSocket1(); + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("wrong socket selection\n")); + #endif + return 1; + } + + // open mcu uart + beginUART(); + + // power up depending on the chosen SOCKET + PWR.powerSocket(_uart, HIGH); + + // wait power-up time + delay(500); + + // flush uart + serialFlush(_uart); + + // try several attempts to communicate with the module + retries = 5; + do + { + // send AT+i, wait for I/OK + status = sendCommand(AT, I_OK, 1000); + + if (status == 1) + { + return 0; + } + else + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("no answer received\n")); + #endif + } + retries--; + delay(100); + } + while (retries > 0); + + /// if problems ==> switch off -> switch on -> and try again + OFF(socket); + delay(1000); + + // decrement + total_attempts--; + } + + return 1; +} + + + +/* + * + * name: OFF + * @param socket: socket where the module is plugged + * @return void + */ +void WaspWIFI_PRO::OFF( uint8_t socket ) +{ + // close UART0 + closeUART(); + + // unselect multiplexer + if (_uart == SOCKET0) Utils.setMuxUSB(); + if (_uart == SOCKET1) Utils.muxOFF1(); + + // switch module OFF + PWR.powerSocket(_uart, LOW); + + delay(100); +} + + + + + + +/* + * name: resetValues + * @param void + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::resetValues() +{ + char cmd_name[20]; + + // "FD" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[1]))); + + // generate "AT+iFD\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + uint8_t status = sendCommand( _command, I_OK, 500 ); + + if (status == 1) + { + return 0; + } + else + { + return 1; + } +} + + + +/*! + * + * @param char* ssid: string defines the ESSID + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::setESSID( char* ssid ) +{ + char cmd_name[20]; + + // "WLSI" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[2]))); + + // generate "AT+iWLSI=\r" + GEN_ATCOMMAND1(cmd_name, ssid); + + // if a password was set, setting ESSID can take a while + // it is recommended to wait for 20secs + uint8_t status = sendCommand( _command, I_OK, 20000 ); + + if (status == 1) + { + return 0; + } + else + { + return 1; + } +} + + + + +/* + * name: setESSID + * @param uint8_t n: index for the new ESSID profile + * @param char* ssid: name of the AP + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::setESSID(uint8_t n, char* ssid) +{ + char cmd_name[20]; + char gen_cmd_name[20]; + char format[20]; + + // "WSI" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[48]))); + + // "%s%01u" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[16]))); + + snprintf(gen_cmd_name, sizeof(gen_cmd_name), format, cmd_name, n); + + // generate "AT+iWSIn=\r" + GEN_ATCOMMAND1(gen_cmd_name, ssid); + + // if a password was set, setting ESSID can take a while + // it is recommended to wait for 20secs + uint8_t status = sendCommand( _command, I_OK, 20000 ); + + if (status == 1) + { + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: getESSID + * + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::getESSID() +{ + char cmd_name[20]; + char format[20]; + int result = 0; + + // "WLSI" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[2]))); + + // "AT+iWLSI?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[30]))); + + // generate "AT+iWLSI?\r" + GEN_ATQUERY(cmd_name); + + // send command + uint8_t status = sendCommand(_command, AT_OK, AT_ERROR, 500); + + if (status == 1) + { + result = sscanf( (char*)_buffer, format, _essid); + + if (result != 0) + { + return 0; + } + else + { + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/*! + * @param uint8_t securityMode: type of encryption + * @arg OPEN + * @arg WEP64 + * @arg WEP128 + * @arg WPA + * @arg WPA2 + * @param char* pass: string for the password + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::setPassword(uint8_t securityMode) +{ + return setPassword(0, securityMode, ""); +} + + +/*! + * @param uint8_t securityMode: type of encryption + * @arg OPEN + * @arg WEP64 + * @arg WEP128 + * @arg WPA + * @arg WPA2 + * @param char* pass: string for the password + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::setPassword( uint8_t securityMode, char* pass) +{ + return setPassword(0, securityMode, pass); +} + + + +/*! + * @param uint8_t n: index of profile (from 0 to 9) + * @param uint8_t securityMode: type of encryption + * @arg OPEN + * @arg WEP64 + * @arg WEP128 + * @arg WPA + * @arg WPA2 + * @param char* pass: string for the password + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::setPassword(uint8_t n, uint8_t securityMode, char* pass) +{ + uint8_t status; + char cmd_name[20]; + char gen_cmd_name[20]; + char param1[20]; + char format[20]; + + + /// 1. Set Security mode: WPA, WPA2... + + // "WST" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[4]))); + // "%s%01u" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[16]))); + + // create complete command name: "WSTn" + snprintf(gen_cmd_name, sizeof(gen_cmd_name), format, cmd_name, n); + + // convert to string + utoa( securityMode, param1, 10 ); + + // generate "AT+iWSTn=\r" + GEN_ATCOMMAND1(gen_cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, 300 ); + + if (status != 1) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } + + + /// 2. Set password key + switch( securityMode ) + { + case OPEN: + // No extra settings needed + break; + + case WEP64: + case WEP128: + // "WKY" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[5]))); + // generate command name "WKYn" + snprintf(gen_cmd_name, sizeof(gen_cmd_name), format, cmd_name, n); + // generate "AT+iWKYn=\r" + GEN_ATCOMMAND1(cmd_name, pass); + break; + + case WPA: + case WPA2: + // "WPP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[6]))); + // generate command name "WPPn" + snprintf(gen_cmd_name, sizeof(gen_cmd_name), format, cmd_name, n); + // generate "AT+iWPPn=\r" + GEN_ATCOMMAND1(gen_cmd_name, pass); + break; + default: + return 1; + } + + + // Setting password can take a while + // it is recommended to wait for 20secs + status = sendCommand( _command, I_OK, 20000 ); + + if (status == 1) + { + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/*! + * @brief It sets the working mode of the WiFi module: + * @arg MODE_STATION (0) + * @arg MODE_ACCESS_POINT (1) + * @return '0' if ok, '1' if error + * + */ +uint8_t WaspWIFI_PRO::setWorkingMode(uint8_t n) +{ + char cmd_name[20]; + char gen_cmd_name[20]; + char format[20]; + char param1[20]; + + // convert to string + utoa( n, param1, 10 ); + + // "STAP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[61]))); + + // generate "AT+iSTAP=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + uint8_t status = sendCommand( _command, I_OK, 1000 ); + + if (status == 1) + { + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/*! + * @brief Sets number of addresses to be allocated in the IP pool of iChip’s + * DHCP server + * @param uint8_t range: number of IP addresses in pool (1 to 255). + * Default: 0 DHCP server is inactive + * @return '0' if ok, '1' if error + * + */ +uint8_t WaspWIFI_PRO::setServerPoolSize(uint8_t range) +{ + char cmd_name[20]; + char gen_cmd_name[20]; + char format[20]; + char param1[20]; + + // convert to string + utoa( range, param1, 10 ); + + // "DPSZ" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[61]))); + + // generate "AT+iDPSZ=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + uint8_t status = sendCommand( _command, I_OK, 1000 ); + + if (status == 1) + { + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: softReset + * @param + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::softReset() +{ + uint8_t status; + char cmd_name[20]; + + // "DOWN" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[3]))); + + // gen "AT+iDOWN\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + status = sendCommand( _command, I_OK, I_ONLINE, I_ERROR, 5000 ); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } + else if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("softReset I/OK\n")); + #endif + } + else if (status == 2) + { + return 0; + } + else if (status == 3) + { + // check error code + getErrorCode(); + return 0; + } + + // wait for correct following response: I/ONLINE or I/ERROR (056) + status = waitFor( I_ONLINE, I_ERROR, 5000 ); + + if (status == 1) + { + // I/ONLINE + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("softReset I/ONLINE\n")); + #endif + return 0; + } + else if (status == 2) + { + // get error code + uint16_t error = getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("softReset I/ERROR:")); + USB.println(error, DEC); + #endif + } + else + { + // timeout + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("softReset timeout\n")); + #endif + _errorCode = ERROR_CODE_0000; + return 1; + } + + return 1; +} + + + + +/* + * name: reportStatus + * @param + * @return + * 0: Wireless LAN adapter not present + * 1: Wireless LAN adapter disabled + * 2: Searching for initial connection + * 4: Connected + * 5: Out of range + * 6: timeout + * 7: I/OK before connection report + * 8: error + * + */ +uint8_t WaspWIFI_PRO::reportStatus() +{ + uint8_t status; + char cmd_name[20]; + char pattern[30]; + char format_ok[20]; + + // "RP10" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[0]))); + // ")\r\n" + strcpy_P( format_ok, (char*)pgm_read_word(&(table_WIFI_FORMAT[6]))); + // "AT+iRP10\r\nI/(%u,%u,%u,%u)" + strcpy_P( pattern, (char*)pgm_read_word(&(table_WIFI_FORMAT[7]))); + + // gen "AT+iRP10\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + status = sendCommand( _command, format_ok, I_OK, I_ERROR, 300 ); + + if (status == 0) + { + // timeout + _errorCode = ERROR_CODE_0000; + return 6; + } + else if (status == 1) + { + // define a string buffer to copy the answer + char aux[100]={}; + + // check correct length to be copied + uint16_t size = _length; + if (size >= sizeof(aux)) + { + size = sizeof(aux)-1; + } + + // copy mem block + memcpy( aux, _buffer, size); + + // get all fields from answer + uint16_t port; + + sscanf( aux, pattern, &port, &_rate, &_level, &_quality ); + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("reportStatus:")); + USB.println( _buffer, _length ); + PRINT_WIFI_PRO(F("port:")); + USB.println( port, DEC ); + PRINT_WIFI_PRO(F("_rate:")); + USB.println( _rate, DEC ); + PRINT_WIFI_PRO(F("_level:")); + USB.println( _level, DEC ); + PRINT_WIFI_PRO(F("_quality:")); + USB.println( _quality, DEC ); + #endif + return port; + } + else if (status == 2) + { + return 7; + } + else + { + return 8; + } +} + + + +/*! + * @brief Gets a report of the current WLAN connection + * @return 0: ok; 1: error + * + */ +uint8_t WaspWIFI_PRO::reportStatusComplete() +{ + uint8_t status; + uint8_t error; + char cmd_name[20]; + char empty[30]; + + // "!RP10" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[47]))); + // "AT+i!rp10\r\nI/OK" + strcpy_P( empty, (char*)pgm_read_word(&(table_WIFI_FORMAT[15]))); + + // gen "AT+i!RP10\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + status = sendCommand( _command, I_OK_EOL, empty, I_ERROR, 500 ); + + if (status == 1) + { + error = parseResponse4(); + + if (error != 0) + { + return 1; + } + return 0; + } + else if (status == 2) + { + return 1; + } + else if (status == 3) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/* + * name: isConnected + * + * @return + * true: connected + * false: NOT connected + * + */ +bool WaspWIFI_PRO::isConnected() +{ + const uint32_t TOTAL_TIMEOUT = 30000; + const uint32_t PERIOD_TIMEOUT = 5000; + return isConnected(TOTAL_TIMEOUT, PERIOD_TIMEOUT); +} + + +/* + * name: isConnectedMultiple + * + * @return + * true: connected + * false: NOT connected + * + */ +bool WaspWIFI_PRO::isConnectedMultiple() +{ + const uint32_t TOTAL_TIMEOUT = 180000; + const uint32_t PERIOD_TIMEOUT = 90000; + return isConnected(TOTAL_TIMEOUT, PERIOD_TIMEOUT); +} + + +/* + * name: isConnected + * @param uint32_t total_time: time to wait until function answers error + * @param uint32_t period_time: time to wait until a SW reset id done to restart + * @return + * true: connected + * false: NOT connected + * + */ +bool WaspWIFI_PRO::isConnected(uint32_t total_time, uint32_t period_time) +{ + const uint32_t TOTAL_TIMEOUT = total_time; + const uint32_t PERIOD_TIMEOUT = period_time; + uint32_t total_start = millis(); + uint32_t period_start; + uint8_t error; + uint8_t status; + bool step1Done = false; + + while (millis()-total_start < TOTAL_TIMEOUT) + { + /// 1. Check report status for correct association + period_start = millis(); + + if (step1Done == false) + { + while (millis()-period_start < PERIOD_TIMEOUT) + { + // get status + status = reportStatus(); + + if (status == 4) + { + // WiFi connected + // Now go to step 2 (wait for IP address) + step1Done = true; + break; + } + else + { + // Not correct status + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("reportStatus:")); + USB.println(status,DEC); + #endif + } + // wait for new status request + delay(500); + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < period_start) period_start = millis(); + } + } + + + /// 2. Wait for getting IP for full functionality + period_start = millis(); + + if (step1Done == true) + { + while (millis()-period_start < PERIOD_TIMEOUT) + { + error = getIP(); + + if (error == 0) + { + return true; + } + else + { + delay(500); + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < period_start) period_start = millis(); + } + } + + + /// 3. After PERIOD_TIMEOUT: soft reset and start again + + // update flag to start again + step1Done = false; + + // to re-start connection request again + error = softReset(); + + if (error == 0) + { + // WiFi softReset OK + } + else + { + // WiFi softReset ERROR + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < total_start) total_start = millis(); + } + + return false; +} + + + + +/* + * name: ping + * Sends a two-byte ICMP PING request packet to the remote host defined by host. + * @param char* host: Logical name of the target host or a host IP address. + * The host name may be any legal Internet server name, which can be + * resolved by the iChip’s DNS (Domain Name Server) settings. The host + * name may also be specified as an absolute IP address given in DOT form. + + + * @return + * + */ +uint8_t WaspWIFI_PRO::ping( char* host ) +{ + char cmd_name[20]; + uint8_t error = 0; + + // "PING" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[7]))); + + // generate "AT+iPING:\r" + GEN_ATCOMMAND2(cmd_name, host); + + // send command + uint8_t status = sendCommand( _command, AT_OK2, AT_ERROR, 10000); + + if (status == 1) + { + getResponse(); + error = parseResponse( &_rtt ); + if (error == 0) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("rtt(ms)=")); + USB.println( _rtt, DEC ); + #endif + } + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: setIP + * Permanently sets iChip’s default IP address to IP address. The address will + * be stored in the DIP parameter. The DIP parameter’s value is copied into the + * IPA parameter after power-up and after the AT+iDOWN command. + * By default, this parameter is empty (0.0.0.0): No static IP address defined. + * IP address will be resolved through a DHCP server, if one is available (LAN) + * or PPP (Modem). + * + * @param char* ip: ip address to set + * @remarks "255.255.255.255" is reserved + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setIP(char* ip) +{ + char cmd_name[20]; + + // "DIP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[35]))); + + // generate "AT+iDIP=\r" + GEN_ATCOMMAND1(cmd_name, ip); + + // send command + uint8_t status = sendCommand( _command, I_OK, I_ERROR, 5000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/* + * name: getIP + * Report the current IP address + * + * @return + * + */ +uint8_t WaspWIFI_PRO::getIP() +{ + char cmd_name[20]; + char format[20]; + char no_ip[20]; + int result = 0; + + // "IPA" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[8]))); + + // "AT+iIPA?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[8]))); + // "0.0.0.0" + strcpy_P( no_ip, (char*)pgm_read_word(&(table_WIFI_FORMAT[9]))); + + // generate "AT+iIPA?\r" + GEN_ATQUERY(cmd_name); + + // send command + uint8_t status = sendCommand( _command, AT_OK, AT_ERROR, 500 ); + + if (status == 1) + { + result = sscanf( (char*)_buffer, format, _ip ); + + if (result != 0) + { + if (strstr((char*)_buffer, no_ip) != NULL) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: setDNS + * @brief Sets the Domain Name Server IP Address. + * Use n=1 to define the Primary IP address of the Domain Name Server associated + * with the ISP. + * Use n=2 to define the alternate IP address. + * IP::=... where, : [000..255] + * + * @param uint8_t n: primary(1) or secondary(2) DNS server + * @param char* ip: ip address to set + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setDNS(char* ip) +{ + return setDNS(1,ip); +} + +/* + * name: setDNS + * @brief Sets the Domain Name Server IP Address. + * Use n=1 to define the Primary IP address of the Domain Name Server associated + * with the ISP. + * Use n=2 to define the alternate IP address. + * IP::=... where, : [000..255] + * + * @param uint8_t n: primary(1) or secondary(2) DNS server + * @param char* ip: ip address to set + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setDNS(uint8_t n, char* ip) +{ + char cmd_name[20]; + uint8_t status; + + if (n == 1) + { + // "DNS1" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[36]))); + } + else if (n == 2) + { + // "DNS2" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[37]))); + } + else + { + return 1; + } + + // generate "AT+iDNSn=\r" + GEN_ATCOMMAND1(cmd_name, ip); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + +/* + * name: getDNS + * Report the current DNS address + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::getDNS(uint8_t n) +{ + char cmd_name[20]; + char format[20]; + char no_ip[20]; + int result = 0; + char* dns_pointer; + + if (n == 1) + { + // "DNS1" + strcpy_P(cmd_name, (char*)pgm_read_word(&(table_WiReach[36]))); + // "AT+iDNS1?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[28]))); + // set dns1 as pointer + dns_pointer = _dns1; + } + else if (n == 2) + { + // "DNS2" + strcpy_P(cmd_name, (char*)pgm_read_word(&(table_WiReach[37]))); + // "AT+iDNS2?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[29]))); + // set dns2 as pointer + dns_pointer = _dns2; + } + else + { + return 1; + } + + // "0.0.0.0" + strcpy_P(no_ip, (char*)pgm_read_word(&(table_WIFI_FORMAT[9]))); + + // generate "AT+iDNS?\r" + GEN_ATQUERY(cmd_name); + + // send command + uint8_t status = sendCommand(_command, AT_OK, AT_ERROR, 500); + + if (status == 1) + { + result = sscanf( (char*)_buffer, format, dns_pointer); + + if (result != 0) + { + if (strstr((char*)_buffer, no_ip) != NULL) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + +/* + * name: setGateway + * @brief Permanently sets the IP address of the gateway to be used by iChip. + * + * @param char* ip: ip address to set + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setGateway(char* ip) +{ + char cmd_name[20]; + uint8_t status; + + // "IPG" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[38]))); + + // generate "AT+iIPG=\r" + GEN_ATCOMMAND1(cmd_name, ip); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/* + * name: getGateway + * @brief Get the current gateway IP + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::getGateway() +{ + char cmd_name[20]; + char format[20]; + char no_ip[20]; + int result = 0; + + // "IPG" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[38]))); + + // "AT+iIPG?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[26]))); + // "0.0.0.0" + strcpy_P( no_ip, (char*)pgm_read_word(&(table_WIFI_FORMAT[9]))); + + // generate "AT+iIPG?\r" + GEN_ATQUERY(cmd_name); + + // send command + uint8_t status = sendCommand(_command, AT_OK, AT_ERROR, 500); + + if (status == 1) + { + result = sscanf( (char*)_buffer, format, _gw ); + + if (result != 0) + { + if (strstr((char*)_buffer, no_ip) != NULL) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: setNetmask + * @brief Sets the Sub Net to IP mask. + * + * @param char* ip: ip address to set + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setNetmask(char* ip) +{ + char cmd_name[20]; + uint8_t status; + + // "SNET" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[39]))); + + // generate "AT+iSNET=\r" + GEN_ATCOMMAND1(cmd_name, ip); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + +/* + * name: getNetmask + * @brief Gets the current subnet mask + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::getNetmask() +{ + char cmd_name[20]; + char format[20]; + char no_ip[20]; + int result = 0; + + // "SNET" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[39]))); + + // "AT+iSNET?\r\n%s\r\n" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[27]))); + // "0.0.0.0" + strcpy_P( no_ip, (char*)pgm_read_word(&(table_WIFI_FORMAT[9]))); + + // generate "AT+iSNET?\r" + GEN_ATQUERY(cmd_name); + + // send command + uint8_t status = sendCommand(_command, AT_OK, AT_ERROR, 500); + + if (status == 1) + { + result = sscanf((char*)_buffer, format, _netmask); + + if (result != 0) + { + if (strstr((char*)_buffer, no_ip) != NULL) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/* + * name: getURL + * Report the current IP address + * + * @return + * + * AT+iRLNK:"http://pruebas.libelium.com:80/getpost_frame_parser.php?counter=1" + * + */ +uint8_t WaspWIFI_PRO::getURL(char* protocol, + char* host, + char* port, + char* link ) +{ + // define buffer for url: Maximum 256 chars + char url[257]; + char cmd_name[20]; + char format[20]; + uint8_t status; + + // clear buffer + memset( url, 0x00, sizeof(url) ); + + // "\"%s://%s:%s/%s\"" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[10]))); + + int n = snprintf( url, sizeof(url), format, protocol, host, port, link ); + + if ((n>0) && (n<(int)sizeof(url))) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("URL:")); + USB.println( url ); + PRINT_WIFI_PRO(F("URL length:")); + USB.println( strlen(url), DEC); + #endif + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[getURL] url too large. n:")); + USB.println( n, DEC); + #endif + _errorCode = ERROR_CODE_0031; + return 1; + } + + // "RLNK" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[9]))); + + // generate "AT+iRLNK:\r" + GEN_ATCOMMAND1(cmd_name, url); + + // send command + status = sendCommand( _command, I_OK_EOL, AT_ERROR, 5000 ); + + if (status == 1) + { + // The module must answer: "I/\r\nI/ONLINE" + // Check this type of answer + status = getResponseValue(); + + if (status == 0) + { + status = waitFor( AT_ONLINE, 15000); + _errorCode = ERROR_CODE_0000; + return 1; + } + else + { + status = waitFor( AT_ONLINE, 15000); + + if (status == 1) + { + _length -= strlen(AT_ONLINE); + _buffer[_length] = '\0'; + return 0; + } + else + { + _errorCode = ERROR_CODE_0000; + return 1; + } + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + +/* + * name: setURL + * Sets the URL address string used for downloading web pages and files and + * uploading files to web servers. + * + * @return + * + * Example command: + * AT+iURL=“://[:]/[]” + * + */ +uint8_t WaspWIFI_PRO::setURL(char* protocol, + char* host, + char* port, + char* link ) +{ + char url[512]; + char url_template[50]; + char cmd_name[20]; + uint8_t status; + + // clear buffer + memset( url, 0x00, sizeof(url) ); + memset( url_template, 0x00, sizeof(url_template) ); + + // "\"%s://%s:%s/%s\"" + strcpy_P( url_template, (char*)pgm_read_word(&(table_WiReach[11]))); + + // Create "://:/" + snprintf( url, sizeof(url), url_template, protocol, host, port, link ); + + // "URL" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[13]))); + + // generate "AT+iURL=\r" + GEN_ATCOMMAND1(cmd_name, url); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 5000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + +/* + * name: post + * Submits a plain text POST request to a web server defined in the URL param + * + * @remarks The url address must be set with the setURL() function + * @remarks The “Content-type:” field of the POST request is defined by the + * CTT parameter. + * @return + * + * must be .... + * + */ +uint8_t WaspWIFI_PRO::post( char* text ) +{ + char cmd_name[20]; + uint8_t status; + uint16_t size; + char ending[20]; + + // "\r\n.\r\n" + strcpy_P( ending, (char*)pgm_read_word(&(table_WIFI_FORMAT[24]))); + + // claculate buffer size + size = strlen(text)+ strlen(ending) + 1; + + char aux[size]; + + // clear buffer + memset( aux, 0x00, sizeof(aux) ); + + // copy text and add ending + strncat( aux, text, strlen(text) ); + strncat( aux, ending, strlen(ending) ); + + // "SLNK" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[12]))); + + // generate "AT+iSLNK:\r\n.\r\n" + GEN_ATCOMMAND2(cmd_name, aux); + + // send command + status = sendCommand( _command, I_OK_EOL, AT_ERROR, 5000 ); + + if (status == 1) + { + // The module must answer: "I/\r\n" + // Check this type of answer + status = getResponseValue(); + + if (status == 0) + { + // wait the module to be ready again + status = waitFor( AT_ONLINE, 15000 ); + _errorCode = ERROR_CODE_0000; + return 1; + } + else + { + // wait the module to be ready again + status = waitFor( AT_ONLINE, 15000); + + if (status == 1) + { + _length -= strlen(AT_ONLINE); + _buffer[_length] = '\0'; + return 0; + } + else + { + _errorCode = ERROR_CODE_0000; + return 1; + } + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/** + * @brief Defines the contents of the “Content-type:” field that is sent in + * the POST request by the AT+iSLNK command. This field specifies the + * type of file being sent + * + * @param char* str: type of file being sent by the AT+iSLNK command + * @return + * '0' if ok + * '1' if error + */ +uint8_t WaspWIFI_PRO::setContentType(char* str) +{ + char cmd_name[20]; + + // "CTT" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[53]))); + + // generate "AT+iCTT=\r" + GEN_ATCOMMAND1(cmd_name, str); + + // send command + uint8_t status = sendCommand( _command, I_OK, I_ERROR, 5000); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/** + * @brief Send HTTTP request with Frame contents from Waspmote to Meshlium + * + * @param char* protocol: "http" or "https" + * @param char* host: Web Server Name (IP address or DNS server name) + * @param char* port: Port number on server. Default: 80 (http), 443 (https) + * @param uint8_t* data: pointer to be used with frame.buffer + * @param uint16_t length: length of buffer to be used with frame.length + * + * @return '0' if ok; '1' if error + * + */ +uint8_t WaspWIFI_PRO::sendFrameToMeshlium( char* protocol, + char* host, + char* port, + uint8_t* data, + uint16_t length ) +{ + char cmd_name[20]; + char host_header[50]; + char aux[3]; + uint8_t status; + uint16_t size = 0; + + // "\"%s://%s:%s/getpost_frame_parser.php?frame=" + strcpy_P( host_header, (char*)pgm_read_word(&(table_WiReach[10]))); + + // calculate total size of buffer + size = strlen(protocol) + + strlen(host) + + strlen(port) + + strlen(host_header) + + length*2; + + // define buffer + char url[size]; + + // clear buffer + memset( url, 0x00, sizeof(url) ); + memset( aux, 0x00, sizeof(aux) ); + + // compose "://:/getpost_frame_parser.php?frame=" + snprintf( url, sizeof(url), host_header, protocol, host, port ); + + // make conversion and concatenate to url + for (uint16_t i=0 ; i 256) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("ERROR. Max URL is 256. Current length: ")); + USB.println( strlen(url), DEC); + #endif + _errorCode = ERROR_CODE_0042; + return 1; + } + + + // "RLNK" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[9]))); + + // generate "AT+iRLNK:\r" + GEN_ATCOMMAND1(cmd_name, url); + + // send command + status = sendCommand( _command, I_OK_EOL, AT_ERROR, 5000); + + if (status == 1) + { + // The module must answer: "I/\r\n" + // Check this type of answer + status = getResponseValue(); + + if (status == 0) + { + // error + // wait for online message from module + status = waitFor( AT_ONLINE, 15000); + + _errorCode = ERROR_CODE_0000; + return 1; + } + else + { + // wait for online message from module + status = waitFor( AT_ONLINE, 15000); + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + + + +/*! + * @brief Opens an FTP link to an FTP server + * + * @param char* server: Logical name of the FTP or the server’s IP address + * @param char* port: Optional FTP port in the range 0..65535 (def:21) + * @param char* user: FTP user’s name + * @param char* pass: FTP user’s password + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpOpenSession(char* server, + char* port, + char* user, + char* pass) +{ + char cmd_name[20]; + uint8_t status; + + // "FOPN" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[14]))); + + // generate "AT+iFOPN:,:,\r" + GEN_ATCOMMAND2(cmd_name, server, port, user, pass); + + // change second comma ',' to ':' + char* pointer; + pointer = strchr( _command, ','); + if (pointer == NULL) return 1; + pointer = strchr( pointer+1, ','); + if (pointer == NULL) return 1; + *pointer = ':'; + + uint32_t previous = millis(); + // send command + status = sendCommand(_command, I_SLASH, AT_ERROR, 15000); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = ERROR_CODE_0000; + return 1; + } + else + { + // update FTP handler + _ftp_handle = (uint16_t)_value; + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("FTP handle: ")); + USB.println( _ftp_handle, DEC ); + PRINT_WIFI_PRO(F("_buffer:")); + USB.println( _buffer, _length ); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("FTP openSession ERROR\n")); + #endif + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("FTP openSession TIMEOUT\n")); + #endif + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + + +/*! + * @brief Opens a secure FTP link to a secure FTP server + * + * @param char* server: Logical name of the FTP or the server’s IP address + * @param char* port: Optional FTP port in the range 0..65535 (def:21) + * @param char* user: FTP user’s name + * @param char* pass: FTP user’s password + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpSecureOpenSession(char* server, + char* port, + char* user, + char* pass) +{ + char cmd_name[20]; + uint8_t status; + + // "FOPS" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[60]))); + + // generate "AT+iFOPS:,:,\r" + GEN_ATCOMMAND2(cmd_name, server, port, user, pass ); + + // change second comma ',' to ':' + char* pointer; + pointer = strchr( _command, ','); + if (pointer == NULL) return 1; + pointer = strchr( pointer+1, ','); + if (pointer == NULL) return 1; + *pointer = ':'; + + uint32_t previous = millis(); + // send command + status = sendCommand(_command, I_SLASH, AT_ERROR, 30000); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = ERROR_CODE_0000; + return 1; + } + else + { + // update FTP handler + _ftp_handle = (uint16_t)_value; + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("FTP handle: ")); + USB.println( _ftp_handle, DEC ); + PRINT_WIFI_PRO(F("_buffer:")); + USB.println( _buffer, _length ); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("FTP openSession ERROR\n")); + #endif + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("FTP openSession TIMEOUT\n")); + #endif + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + + + + +/*! + * @brief Reports an FTP file size + * + * @param char* path: File pathname in server + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpFileSize( uint16_t handle, char* path ) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // init attribute + _filesize = 0; + + // convert to string + utoa( handle, param1, 10 ); + + // "FSZ" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[15]))); + + // generate "AT+iFSZ:,\r" + GEN_ATCOMMAND2(cmd_name, param1, path ); + + // send command + status = sendCommand( _command, I_SLASH, AT_ERROR, 15000 ); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + _filesize = _value; + + // wait for online message from module + status = waitFor( I_OK_EOL, 5000); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("FTP file size: ")); + USB.println( _filesize, DEC ); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + + + + + +/*! + * @brief Downloads a file from an FTP server + * + * @param char* server_path: File pathname inside FTP server + * @param char* sd_path: File pathname in SD card + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpDownload( uint16_t handle, char* server_path, char* sd_path ) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + uint8_t error; + uint32_t server_filesize = 0; + uint32_t sd_filesize = 0; + uint16_t nBytes; + unsigned long previous; + + /// Prepare SD card for downloading + + // define file variable + SdFile file; + + // get current state of SD card power supply + bool sd_active = SPI.isSD; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("SD not present\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0010; + return 1; + } + + // Delete file in the case it exists + if (SD.isFile(sd_path) == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("delete file\n")); + #endif + SD.del(sd_path); + } + + // Creates a file in that folder + if (!SD.create(sd_path)) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("file not created\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0011; + return 1; + } + + // search file in current directory and open it in write mode + if (!SD.openFile(sd_path, &file, O_READ | O_WRITE | O_SYNC)) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("error opening file\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0012; + return 1; + } + + // jump over zero 'offset' + if (!file.seekSet(0)) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("setting file offset\n")); + #endif + file.close(); + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0013; + return 1; + } + + /// Change Baudrate to 9600 bps + error = changeBaudRate(9600); + + if (error == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Error changing baudrate\n")); + #endif + return 1; + } + + /// Get filesize (for backup) + error = ftpFileSize(handle, server_path); + if (error == 0) + { + server_filesize = _filesize; + } + else + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Error retrieving file size\n")); + #endif + return 1; + } + + + /// STEP1. Send command to retrieve file, wait for ok and size of data stream + + // convert to string + utoa(handle, param1, 10); + + // "FRCV" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[16]))); + + // generate "AT+iFRCV:,\r" + GEN_ATCOMMAND2(cmd_name, param1, server_path); + + status = sendCommand(_command, I_OK_EOL, AT_ERROR, 15000); + + if (status == 1) + { + // The module must answer: "I/\r\n" + // Check this type of answer + status = getResponseValue(); + + if (status == 0) + { + // check if there was error: "FTP data socket could not be opened" + // in this case it is possible to retry again after a few seconds + if (_errorCode == ERROR_CODE_0511) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("There was error 511 --> retry\n")); + #endif + delay(1000); + + status = sendCommand( _command, I_OK_EOL, AT_ERROR, 15000); + + if (status == 1) + { + // The module must answer: "I/\r\n" + // Check this type of answer + status = getResponseValue(); + } + } + + if (status == 0) + { + /// Change Baudrate to 115200 bps + changeBaudRate(115200); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No file size value from server\n")); + #endif + return 1; + } + } + + // proceed + if ((_value == 0) && (server_filesize > 0)) + { + _value = server_filesize; + } + else if ((_value > 0) && (server_filesize > 0)) + { + /* go down to step2 and proceed with the + * reading of the file and writing info + * to SD card */ + } + else + { + /// Change Baudrate to 115200 bps + changeBaudRate(115200); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("unknown file size\n")); + #endif + return 1; + } + + } + else if (status == 2) + { + getErrorCode(); + // Change Baudrate to 115200 bps + changeBaudRate(115200); + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("I/ERROR\n")); + #endif + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + // Change Baudrate to 115200 bps + changeBaudRate(115200); + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("timeout\n")); + #endif + return 1; + } + + /// STEP2. read incoming data and save it in Waspmote SD card + + server_filesize = _value; + + // get actual instant + previous = millis(); + + // write incoming data to file + while (server_filesize > 0) + { + + // check if buffer is full, means data lost almost 100% sure + if (serialAvailable(_uart) >= (sizeof(_buffer)-1)) + { + // abort tx + userAbort(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: rx buffer full while download\n")); + #endif + _errorCode = ERROR_CODE_0020; + return 1; + } + + // read "_buffer"-size data block + if (server_filesize > sizeof(_buffer)) + { + nBytes = readBuffer((int)(sizeof(_buffer)/2)); + } + else + { + nBytes = readBuffer(server_filesize); + } + + // decrement number of read bytes + server_filesize -= nBytes; + + // write data to file if there is something to be written + if (nBytes > 0) + { + if (file.write(_buffer, nBytes) != (int)nBytes) + { + // abort tx + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Writing SD error\n")); + #endif + file.close(); + + if (sd_active == false) + { + SD.OFF(); + } + + _errorCode = ERROR_CODE_0014; + return 1; + } + + // update time counter + previous = millis(); + } + + // check time since last reading + if ((millis() - previous) > 10000) + { + // abort tx + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No incoming data timeout\n")); + #endif + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + // Close file + file.close(); + + // wait for online message from module + status = waitFor( AT_ONLINE, 10000 ); + + // wait for I/ONLINE message + if (status == 0) + { + _errorCode = 1; + // Change Baudrate to 115200 bps + changeBaudRate(115200); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No I/ONLINE message\n")); + #endif + return 1; + } + + // update file size in SD card + sd_filesize = SD.getFileSize(sd_path); + + // save the actual server file size + server_filesize = _value; + + // check size mismatch + if (sd_filesize != server_filesize) + { + // Change Baudrate to 115200 bps + changeBaudRate(115200); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("File size mismatch\n")); + PRINT_WIFI_PRO(F("sd_filesize:")); + USB.println(sd_filesize); + PRINT_WIFI_PRO(F("server_filesize:")); + USB.println(server_filesize); + #endif + return 1; + } + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("DOWNLOAD OK\n")); + PRINT_WIFI_PRO(F("sd_filesize:")); + USB.println(sd_filesize,DEC); + PRINT_WIFI_PRO(F("server_filesize:")); + USB.println(server_filesize,DEC); + #endif + + // set SD card off + if (sd_active == false) + { + SD.OFF(); + } + + /// Change Baudrate to 115200 bps + error = changeBaudRate(115200); + + if (error == 1) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error changing baudrate")); + #endif + return 1; + } + + return 0; + + +} + + + +/*! + * @brief Creates a new directory on the FTP server’s file system + * + * @param char* path: Directory pathname + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpMakeDir(uint16_t handle, char* path) +{ + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( handle, param1, 10); + + // "FMKD" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[54]))); + + // generate "AT+iFMKD:,\r" + GEN_ATCOMMAND2( cmd_name, param1, path ); + + // send command + uint8_t status = sendCommand( _command, AT_OK, AT_ERROR, 15000 ); + + if (status == 1) + { + // ok + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + + +/*! + * @brief Changes the current FTP working directory + * + * @param uint16_t handle: An open FTP session handle + * @param char* path: New directory pathname + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpChangeCWD(uint16_t handle, char* path) +{ + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( handle, param1, 10); + + // "FMKD" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[55]))); + + // generate "AT+iFMKD:,\r" + GEN_ATCOMMAND2( cmd_name, param1, path ); + + // send command + uint8_t status = sendCommand(_command, AT_OK, AT_ERROR, 10000); + + if (status == 1) + { + // ok + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + + +/*! + * @brief Returns a full FTP directory listing via USB port + * + * @param uint16_t handle: An open FTP session handle + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpListing(uint16_t handle) +{ + return ftpListing(handle, NULL); +} + + +/*! + * @brief Returns a full FTP directory listing via USB port + * + * @param uint16_t handle: An open FTP session handle + * @param char* path: directory pathname to list + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpListing(uint16_t handle, char* path) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + uint8_t error; + uint32_t previous; + int nBytes; + + + /// Prepare SD card + + // define file variable + SdFile file; + + // get current state of SD card power supply + bool sd_active = SPI.isSD; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD not present\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0010; + return 1; + } + + // Delete file in the case it exists + if (SD.isFile(WIFI_PRO_LISTFILE) == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("delete file\n")); + #endif + SD.del(WIFI_PRO_LISTFILE); + } + + // Creates a file in that folder + if (!SD.create(WIFI_PRO_LISTFILE)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD file not created\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0011; + return 1; + } + + // search file in current directory and open it in write mode + if (!SD.openFile(WIFI_PRO_LISTFILE, &file, O_READ | O_WRITE | O_SYNC)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: opening file\n")); + #endif + + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0012; + return 1; + } + + // jump over zero 'offset' + if (!file.seekSet(0)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: setting file offset\n")); + #endif + file.close(); + + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0013; + return 1; + } + + + /// Change Baudrate to 9600 bps: + error = changeBaudRate(9600); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error baudrate1\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + + /// Scan and store info: + + // convert to string + utoa(handle, param1, 10); + + // "FDL" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[56]))); + + if (path == NULL) + { + // gen "AT+iFDL:\r" + GEN_ATCOMMAND2(cmd_name, param1); + } + else + { + // gen "AT+iFDL:,\r" + GEN_ATCOMMAND2(cmd_name, param1, path); + } + + // clear uart buffer before sending command + if (_flush_mode == true) + { + serialFlush(_uart); + } + + // send command manually + printString( _command, _uart); + + status = waitFor( I_OK_EOL, 5000 ); + + if (status != 1) + { + if (sd_active == false) + { + SD.OFF(); + } + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No I_OK_EOL timeout\n")); + #endif + + _errorCode = ERROR_CODE_0000; + return 1; + } + + delay(500); + + // update time counter + previous = millis(); + + nBytes = serialAvailable(_uart); + + while (nBytes > 0) + { + nBytes = readBuffer(sizeof(_buffer)); + + // write data to file if there is something to be written + if (nBytes > 0) + { + if (file.write( _buffer, nBytes) != nBytes) + { + // abort + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Writing SD error\n")); + #endif + file.close(); + + if (sd_active == false) + { + SD.OFF(); + } + + _errorCode = ERROR_CODE_0014; + return 1; + } + } + + // check elapsed time + if ((millis() - previous) > 10000) + { + // abort + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No incoming data timeout\n")); + #endif + + if (sd_active == false) + { + SD.OFF(); + } + _errorCode = ERROR_CODE_0000; + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + // Close file + file.close(); + + delay(1000); + + /// Change Baudrate to 115200 bps + error = changeBaudRate(115200); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error baudrate2\n")); + #endif + } + + if (sd_active == false) + { + SD.OFF(); + } + + return 0; +} + + + + + +/*! + * @brief Closes the FTP link + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpCloseSession(uint16_t handle) +{ + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( handle, param1, 10 ); + + // "FCLS" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[17]))); + + // generate "AT+iFCLS:\r" + GEN_ATCOMMAND2( cmd_name, param1 ); + + // send command + uint8_t status = sendCommand( _command, AT_OK, AT_ERROR, 5000 ); + + if (status == 1) + { + // wait for online message from module + status = waitFor( AT_ONLINE, 10000 ); + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + return 1; + } +} + + + + +/* + * name: changeBaudRate + * Change the baudrate of the module by entering into autodetection mode + * + * @param uint32_t rate: baudrate to set + * @return + * '0' if ok + * '1' see errors + * + */ +uint8_t WaspWIFI_PRO::changeBaudRate(uint32_t rate) +{ + char cmd_name[20]; + uint8_t status; + + /// STEP1: check actual comm + + status = sendCommand( AT, I_OK, 3000 ); + + if (status == 1) + { + //do nothing + } + else if (status == 2) + { + getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[changeBaudRate] I/ERROR\n")); + #endif + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[changeBaudRate] step1 no answer\n")); + #endif + return 1; + } + + /// STEP2: enter in auto baudrate mode + + // "BDRA" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[18]))); + + // generate "AT+iBDRA\r" + GEN_ATCOMMAND1( cmd_name ); + + // send command + status = sendCommand( _command, I_OK, 3000 ); + + if (status != 1) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[changeBaudRate] no answer1\n")); + #endif + return 1; + } + + /// STEP3: check new baudrate settings + + // close UART + closeSerial(_uart); + delay(1000); + + // update attribute + _baudrate = rate; + + // open UART + beginSerial( _baudrate, _uart ); + delay(1000); + serialFlush(_uart); + + // check new baudrate + status = sendCommand( AT, I_OK, 3000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[changeBaudRate] I/ERROR\n")); + #endif + _baudrate = 115200; + beginSerial( _baudrate, _uart ); + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("[changeBaudRate] no answer2\n")); + #endif + _baudrate = 115200; + beginSerial( _baudrate, _uart ); + return 1; + } +} + + + + + + + + +/*! + * name: uploadFTP + * Upload a file from SD card to an FTP server + * + * @param char* server_path: FTP server file path name + * If the file is in the root directory: "FILE1.TXT" or "/FILE1.TXT" + * If the file is inside a folder: "/FOLDER1/FILE1.TXT" + * @param char* sd_path: SD card file path name + * If the file is in the root directory: "FILE2.TXT" or "/FILE2.TXT" + * If the file is inside a folder: "/FOLDER2/FILE2.TXT" + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::ftpUpload( uint16_t handle, char* server_path, char* sd_path ) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + uint8_t error; + uint32_t sd_filesize; + + /// Prepare SD card for downloading + + // define file variable + SdFile file; + + // get current state of SD card power supply + bool sd_active = SPI.isSD; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD not present\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // Delete file in the case it exists + if (!SD.isFile(sd_path)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: file does not exist\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // search file in current working directory and open it + // exit if error and modify the general flag with FILE_OPEN_ERROR + if(!SD.openFile((char*)sd_path, &file, O_RDONLY)) + { + // SD error + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: opening file\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // set pointer to the beginning of the file + if(!file.seekSet(0)) + { + // SD error + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: setting initial offset in file\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + + /// STEP1. Send command to open a new file in server + + // convert to string + utoa( handle, param1, 10 ); + + // "FSTO" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[19]))); + + // generate "AT+iFSTO:,\r" + GEN_ATCOMMAND2(cmd_name, param1, server_path ); + + status = sendCommand( _command, I_OK, AT_ERROR, 15000 ); + + if (status == 1) + { + /* go down to step2 and proceed with the + * reading of the SD file and sending info + * to the server */ + } + else if (status == 2) + { + getErrorCode(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("I/ERROR\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No answer timeout1\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + + /// STEP2. send data from Waspmote to FTP server + + sd_filesize = SD.getFileSize(sd_path); + uint32_t aux = sd_filesize; + char cmd[100]; + char format[20]; + int nBytes = 0; + uint8_t flowByte = 0; + bool flowControlEnabled=false; + + // get actual instant + unsigned long previous = millis(); + + // "FSND" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[21]))); + // "%s%s:%s,%lu:" + strcpy_P( format, (char*)pgm_read_word(&(table_WIFI_FORMAT[11]))); + + // Create "AT+iFSND:,:" + snprintf( cmd, sizeof(cmd), format, AT_I, cmd_name, param1, sd_filesize ); + + // send command + sendCommand( (uint8_t*) cmd, strlen(cmd)); + serialFlush(_uart); + + // send data via WiFi + while (sd_filesize > 0) + { + // read "_buffer"-size data block + if(sd_filesize>sizeof(_buffer)) + { + nBytes = file.read( _buffer, sizeof(_buffer) ); + } + else + { + nBytes = file.read( _buffer, sd_filesize ); + } + + // decrement number of read bytes + if (nBytes != -1) + { + sd_filesize -= nBytes; + previous = millis(); + } + + // write data to file if there is something to be written + if (nBytes > 0) + { + for (int i = 0; i < nBytes; i++) + { + // check Flow Control from iChip + while ((serialAvailable(_uart)>0) || flowControlEnabled) + { + if (serialAvailable(_uart) > 0) + { + flowByte = serialRead(_uart); + } + + //check meaning + if (flowByte == 0x16) + { + flowControlEnabled = true; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Flow Control enabled. Wait...\n")); + #endif + } + else if (flowByte == 0x18) + { + flowControlEnabled = false; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Flow Control disabled. Continue!!\n")); + #endif + } + else if (flowByte == 0x05) + { + // wait for message from module + status = waitFor( I_ERROR, 10000 ); + + // wait for I/OK message + if (status == 1) + { + getErrorCode(); + } + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Flow Control ERROR. Stop.\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // check time since last reading + if ((millis() - previous) > 10000) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No data timeout\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + // if no Flow Control is active then + // print the byte into the UART + printByte( _buffer[i], _uart); + } + } + + // check time since last reading + if ((millis() - previous) > 10000) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No data timeout\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + // Close file + file.close(); + + // wait for online message from module + status = waitFor( I_OK, 10000 ); + + // wait for I/OK message + if (status == 0) + { + _errorCode = 1; + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No I/OK found\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + + /// STEP3. close FTP file + + // "FCLF" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[22]))); + + // generate "AT+iFCLF:\r" + GEN_ATCOMMAND2(cmd_name, param1 ); + + status = sendCommand( _command, I_OK, AT_ERROR, 15000 ); + + if (status == 1) + { + /* go down */ + } + else if (status == 2) + { + getErrorCode(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("I/ERROR\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No answer timeout2\n")); + #endif + if (sd_active == false) + { + SD.OFF(); + } + return 1; + } + + // set SD card off + if (sd_active == false) + { + SD.OFF(); + } + + + /// STEP4. check both file sizes (SD and server) + sd_filesize = aux; + error = ftpFileSize(handle, server_path); + + if (error == 1) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error getting server filesize\n")); + #endif + return 1; + } + + if (sd_filesize != _filesize) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("SD/Server files size mismatch\n")); + #endif + return 1; + } + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("UPLOAD OK\n")); + #endif + + return 0; + + +} + + + + + + + +/* + * name: setTCPclient + * Opens a Transmission Control Protocol (TCP) client socket and attempts to + * connect it to the specified on a server defined by + * + * @param char* host: Logical name of the target server or a host IP address + * @param char* remote_port: 0..65535, target port + * @remarks Module uses the port range [1025 to 2048] when assigning default local ports + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTCPclient( char* host, char* remote_port ) +{ + return setTCPclient(host, remote_port, NULL); +} + + + + +/* + * name: setTCPclient + * Opens a Transmission Control Protocol (TCP) client socket and attempts to + * connect it to the specified on a server defined by + * + * @param char* host: Logical name of the target server or a host IP address + * @param char* remote_port: 0..65535, target port + * @param char* local_port: Optional local port on iChip + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTCPclient( char* host, + char* remote_port, + char* local_port ) +{ + char cmd_name[20]; + uint8_t status; + + // "STCP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[23]))); + + // generate "AT+iSTCP:,[,]\r" + if (local_port == NULL) + { + GEN_ATCOMMAND2(cmd_name, host, remote_port); + } + else + { + GEN_ATCOMMAND2(cmd_name, host, remote_port, local_port); + } + + // send command + status = sendCommand( _command, (char*)"I/0", AT_ERROR, 15000 ); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + _socket_handle = _value; + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("TCP socket open\n")); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + + // manage socket abort + socketAbort(); + return 1; + } + +} + + + + + +/* + * name: setTCPserver + * Opens a TCP listening socket on the local IP address and the specified port + * . The parameter specifies the maximum number of remote + * concurrent connections allowed through the listening socket (from 1 to 10). + * + * @param char* local_port: Local port on iChip + * @param uint8_t backlog: Specifies the maximum number of active connections that + * may be concurrently established via the listening socket + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTCPserver( char* local_port, + uint8_t backlog) +{ + char cmd_name[20]; + uint8_t status; + char param1[20]; + uint8_t backlog_value = backlog; + + // check backlog number + if ((backlog_value > 10) || (backlog_value == 0)) + { + backlog_value = 10; + } + + // convert to string + utoa( (uint16_t) backlog, param1, 10 ); + + // init attributes + _backlog = 0; + for (int i = 0; i < 10; i++) + { + socket[i].status = -1; + } + + // "LTCP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[25]))); + + // generate "AT+iLTCP:,\r" + GEN_ATCOMMAND2(cmd_name, local_port, param1); + + // send command + status = sendCommand( _command, (char*)"I/0", AT_ERROR, 10000 ); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + _socket_handle = _value; + _backlog = _value; + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("TCP server open. backlog=")); + USB.println(_backlog,DEC); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + + // manage socket abort + socketAbort(); + return 1; + } +} + + + + + +/* + * name: getAllSocketStatus + * Retrieves handles of active socket connections established through the + * listening socket identified by . + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::getAllSocketStatus() +{ + char cmd_name[20]; + uint8_t status; + char param1[20]; + + // convert to string + utoa(_backlog, param1, 10 ); + + + /// 1. Get all Listening Socket’s Active Connection Status + + // "LSST" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[26]))); + + // generate "AT+iLSST:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // send command + status = sendCommand( _command, AT_OK2, AT_ERROR, 1000 ); + + if (status == 1) + { + // The module must answer: ",,...,)" + // Check this type of answer + status = getResponseValue3(); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + _socket_handle = _value; + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("TCP list ok\n")); + #endif + /* + * go down to step 2 + */ + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + + + /// 2. Get Peer Name for All Specified Sockets + + // "GPNM" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[31]))); + + for (int i = 0; i < _backlog; i++) + { + if (socket[i].status==0) + { + // convert to string + utoa( socket[i].handle, param1, 10 ); + + // generate "AT+iGPNM:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // send command + status = sendCommand(_command, AT_OK2, AT_ERROR, 1000); + + if (status == 1) + { + // The module must answer: ":)" + // Check this type of answer + status = getResponseValue4(i); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + continue; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + } + } + + + + /// 3. report status of the sockets and parse info + status = reportStatus4(); + + // check response + if (status != 0) + { + return 1; + } + + return 0; +} + + + + + +/* + * name: getSocketStatus + * Retrieves handles of active socket connections established through the + * listening socket identified by . + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::getSocketStatus(uint16_t handle) +{ + char cmd_name[20]; + uint8_t status; + uint8_t error; + char param1[20]; + int sockstat; + + // convert to string + utoa(handle, param1, 10 ); + + // "SCS" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[28]))); + + // generate "AT+iSCS:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // send command expecting "I/(" + status = sendCommand( _command, AT_OK2, AT_ERROR, 1000 ); + + if (status == 1) + { + getResponse(); + error = parseResponse5( &sockstat ); + if (error == 0) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Socket Status=")); + USB.println( sockstat, DEC ); + #endif + } + + if (sockstat >= 0) + { + return 0; + } + else + { + return 1; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + return 1; + } +} + + + + + + +/* + * name: setUDP + * @brief Opens a UDP (User Datagram Protocol) socket and sets the remote + * system’s : address + * @param char* host: Logical name of the target server or a host IP address + * @param char* remote_port: 0..65535, target port + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setUDP( char* host, char* remote_port ) +{ + return setUDP(host, remote_port, NULL); +} + + + + +/* + * name: setUDP + * @brief Opens a Transmission Control Protocol (TCP) client socket and + * attempts to connect it to the specified on a server defined + * by + * @param char* host: Logical name of the target server or a host IP address + * @param char* remote_port: 0..65535, target port + * @param char* local_port: Optional local port on iChip + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setUDP( char* host, + char* remote_port, + char* local_port ) +{ + char cmd_name[20]; + uint8_t status; + + // "SUDP" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[24]))); + + // generate "AT+iSUDP:,[,]\r" + if (local_port == NULL) + { + GEN_ATCOMMAND2(cmd_name, host, remote_port); + } + else + { + GEN_ATCOMMAND2(cmd_name, host, remote_port, local_port); + } + + // send command + status = sendCommand( _command, (char*)"I/0", AT_ERROR, 15000); + + if (status == 1) + { + // The module must answer: "\r\n" + // Check this type of answer + status = getResponseValue2(); + + if (status == 0) + { + _errorCode = 1; + return 1; + } + else + { + _socket_handle = _value; + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("UDP socket open\n")); + #endif + return 0; + } + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + + // manage socket abort + socketAbort(); + return 1; + } + +} + + + +/* + * name: send + * Sends a byte stream to the socket specified by the socket handle + * + * @param char* data: data to send + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::send(uint16_t handle, char* data) +{ + char cmd_name[20]; + char param1[20]; + char param2[20]; + uint8_t status; + + // convert to string + utoa(handle, param1, 10); + utoa(strlen(data), param2, 10); + + // "SSND%" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[29]))); + + // generate "AT+iSSND%:,\r" + GEN_ATCOMMAND2(cmd_name, param1, param2); + + // add data stream at the end to generate + // the final command: "AT+iSSND%:,:" + _command[strlen(_command)-1] = ':'; + strcat(_command, data); + + // send command + status = sendCommand(_command, I_OK, AT_ERROR, 15000); + + if (status == 1) + { + // ok + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + +/* + * name: send + * Sends a byte stream to the socket specified by the socket handle + * + * @param uint8_t* data: pointer to buffer of data to send + * @param uint16_t length: length of the buffer to send + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::send(uint16_t handle, uint8_t* data, uint16_t length) +{ + char cmd_name[20]; + char param1[20]; + char param2[20]; + uint8_t status; + uint8_t cmd[512]; + + // convert to string + utoa(handle, param1, 10 ); + utoa(length, param2, 10 ); + + // "SSND%" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[29]))); + + // generate "AT+iSSND%:,\r" + GEN_ATCOMMAND2(cmd_name, param1, param2); + + // add data stream at the end to generate + // the final command: "AT+iSSND%:,:" + _command[strlen(_command)-1] = ':'; + + uint16_t total_length = strlen(_command)+length; + + // check if invalid data length + if (total_length > sizeof(cmd)) + { + _errorCode = ERROR_CODE_0031; + return 1; + } + + // copy actual _command contents + memcpy(cmd, _command, strlen(_command)); + // copy stream of data + memcpy(&cmd[strlen(_command)], data, length); + + // send command + sendCommand(cmd, total_length); + // wait for responses + status = waitFor( I_OK, AT_ERROR, 15000); + + // check response + if (status == 1) + { + // ok + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/* + * name: receive + * Receive a byte stream from default stored socket handle + * + * @param uint32_t timeout: time to wait for data + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::receive(uint16_t handle) +{ + return receive(handle, 1000); +} + + +/* + * name: send + * Sends a byte stream to the socket specified by the socket handle + * + * @param uint32_t timeout: time to wait for data + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::receive(uint16_t handle, uint32_t timeout) +{ + char cmd_name[20]; + char format_empty[20]; + char param1[20]; + uint8_t error; + uint8_t status; + uint16_t length; + uint32_t previous; + + // convert to string + utoa( handle, param1, 10 ); + + // "SRCV" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[30]))); + + // "I/0\r\n" + strcpy_P( format_empty, (char*)pgm_read_word(&(table_WIFI_FORMAT[18]))); + + // generate "AT+iSRCV:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // get previous time instant + previous = millis(); + + while (millis()-previous < timeout) + { + // send command and wait for first "\r\n" occurrence + status = sendCommand( _command, EOL_CR_LF, 1000 ); + + if (status == 0) + { + return 1; + } + + // wait for EOL + status = waitFor( format_empty, (char*)":", AT_ERROR, 1000 ); + + if (status == 1) + { + // no data received yet. Wait 500ms and continue to ask for more + continue; + } + else if (status == 2) + { + // data received "I/xxx:"--> parse data + error = parseResponse2(&length); + if (error == 0) + { + readBuffer(length); + } + return 0; + } + else if (status == 3) + { + //getErrorCode(); + // no data received yet. Wait 500ms and continue to ask for more + delay(100); + //Insert dependencies on type of error?? + continue; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + return 1; + +} + + + + + +/* + * name: closeSocket + * Opens a Transmission Control Protocol (TCP) client socket and attempts to + * connect it to the specified on a server defined by . + * The attribute '_socket_handle' is used as socket handler + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::closeSocket() +{ + return closeSocket(_socket_handle); +} + + + +/* + * name: closeSocket + * Opens a Transmission Control Protocol (TCP) client socket and attempts to + * connect it to the specified on a server defined by + * + * @param uint16_t* handle: handler of the socket to be closed + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::closeSocket(uint16_t handle) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // convert to string + utoa( handle, param1, 10 ); + + // "SCLS" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[34]))); + + // generate "AT+iSCLS:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 15000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/* + * name: closeDownSockets + * Close all down status sockets + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::closeDownSockets() +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // "SCLS" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[34]))); + + for (int i = 0; i < _backlog; i++) + { + // check if socket is down and then close it + if (socket[i].size==-203) + { + // convert to string + utoa( socket[i].handle, param1, 10 ); + + // generate "AT+iSCLS:\r" + GEN_ATCOMMAND2(cmd_name, param1); + + // send command + status = sendCommand( _command, I_ONLINE, AT_ERROR, 10000 ); + + if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Socket closed with hn:")); + USB.println(socket[i].handle); + USB.println(F("-----------------------------------")); + #endif + continue; + } + else if (status == 2) + { + getErrorCode(); + //return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + } + } + + return 0; +} + + + + +/*! + * @brief Sets the network time server name or IP + * @param char* ip: Logical name of the target server or a host IP address + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTimeServer(char* ip) +{ + return setTimeServer(1, ip); +} + + +/*! + * @brief Sets the network time server name or IP + * @param uint8_t n: '1' to define the primary time server + * '2' to define an alternate time server + * @param char* ip: Logical name of the target server or a host IP address + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTimeServer(uint8_t n, char* ip) +{ + char cmd_name[20]; + uint8_t status; + + if (n == 1) + { + // "NTS1" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[40]))); + } + else if (n == 2) + { + // "NTS2" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[41]))); + } + else + { + return 1; + } + + + // generate "AT+iNTSx=\r" + GEN_ATCOMMAND1(cmd_name, ip); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + +/* + * name: timeActivationFlag + * Sets the network time-of-day activation flag to 'flag'. If this flag is + * enabled (1), iChip will retrieve an updated time reading the next time it + * goes online + * + * @param bool flag: '1' is enabled. '0' is disabled + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::timeActivationFlag(bool flag) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // convert to string + utoa( flag, param1, 10 ); + + // "NTOD" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[42]))); + + // generate "AT+iNTOD=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/*! + * @brief Permanently sets iChip location’s Greenwich mean time offset, in + * hours. Range: from -12 to 12 + * @param bool flag: '1' is enabled. '0' is disabled + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setGMT(int8_t gmt) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // convert to string + itoa( gmt, param1, 10 ); + + // "GMT0" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[43]))); + + // generate "AT+iGMT0=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand(_command, I_OK, AT_ERROR, 1000); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + +/* + * name: reportStatus4 + * + * + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::reportStatus4() +{ + char cmd_name[20]; + uint8_t status; + + // "RP4" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[46]))); + + // gen "AT+iRP4\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + status = sendCommand( _command, AT_OK2, AT_ERROR, 1000 ); + + if (status == 1) + { + status = getResponseValue5(); + + if (status == 0) + { + return 1; + } + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/* + * name: reportStatus8 + * + * + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::reportStatus8() +{ + char cmd_name[20]; + uint8_t status; + + // "RP8" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[44]))); + + // gen "AT+iRP8\r" + GEN_ATCOMMAND1(cmd_name); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/*! + * @brief Returns a list of all APs available in the surrounding area + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::scan() +{ + char cmd_name[20]; + uint8_t status; + uint8_t error; + uint32_t previous; + int nBytes; + + /// Prepare SD card + + // define file variable + SdFile file; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD not present")); + #endif + SD.OFF(); + _errorCode = ERROR_CODE_0010; + return 1; + } + + // Delete file in the case it exists + if (SD.isFile(WIFI_PRO_SCANFILE) == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("delete file\n")); + #endif + SD.del(WIFI_PRO_SCANFILE); + } + + // Creates a file in that folder + if (!SD.create(WIFI_PRO_SCANFILE)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD file not created\n")); + #endif + SD.OFF(); + _errorCode = ERROR_CODE_0011; + return 1; + } + + // search file in current directory and open it in write mode + if (!SD.openFile(WIFI_PRO_SCANFILE, &file, O_READ | O_WRITE | O_SYNC)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: opening file\n")); + #endif + SD.OFF(); + _errorCode = ERROR_CODE_0012; + return 1; + } + + // jump over zero 'offset' + if (!file.seekSet(0)) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: setting file offset\n")); + #endif + file.close(); + SD.OFF(); + _errorCode = ERROR_CODE_0013; + return 1; + } + + + /// Change Baudrate to 9600 bps: + error = changeBaudRate(9600); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error baudrate1\n")); + #endif + return 1; + } + + + /// Scan and store info: + // "RP20" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[49]))); + + // gen "AT+iRP20\r" + GEN_ATCOMMAND1(cmd_name); + + // clear uart buffer before sending command + if ( _flush_mode == true) + { + serialFlush(_uart); + } + // send command manually + printString( _command, _uart ); + + status = waitFor( cmd_name, 1000 ); + status = waitFor( EOL_CR_LF, 1000 ); + + if (status != 1) + { + return 1; + } + delay(500); + + // update time counter + previous = millis(); + + // clear buffer + memset( _buffer, 0x00, sizeof(_buffer) ); + _length = 0; + + nBytes = serialAvailable(_uart); + + while (nBytes > 0) + { + nBytes = readBuffer(sizeof(_buffer)); + + // write data to file if there is something to be written + if (nBytes > 0) + { + if (file.write( _buffer, nBytes) != nBytes) + { + // abort + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Writing SD error\n")); + #endif + file.close(); + SD.OFF(); + + _errorCode = ERROR_CODE_0014; + return 1; + } + } + + // check elapsed time + if ((millis() - previous) > 10000) + { + // abort + userAbort(); + + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No incoming data timeout\n")); + #endif + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } + + // Close file + file.close(); + + delay(1000); + + /// Change Baudrate to 115200 bps + error = changeBaudRate(115200); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error baudrate2\n")); + #endif + return 1; + } + + SD.OFF(); + + return 0; + +} + + + + + + + +/* + * name: setTimeFromWIFI + * + * + * + * @return + * '0' if ok + * 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setTimeFromWIFI() +{ + uint8_t error; + int retries = 10; + + do + { + error = reportStatus8(); + + if (error == 0) + { + // parse timestamp parse + error = parseResponse3(); + + if (error == 0) + { + return 0; + } + } + else + { + // error + return 1; + } + + // decrement retries counter + retries--; + + // wait + delay(1000); + + }while (retries > 0); + + return 1; +} + + + + + +/* + * name: userAbort + * While the iChip is in Internet mode attending to Internet communications, it + * is possible to break into the communications and abort the Internet mode in + * an orderly manner. This is achieved by sending the iChip a sequence of three + * (+) ASCII characters (+++) after a half second silence period. In response to + * this, the iChip: + * - Shuts down Internet communications. + * - Terminates data transmission to the host. + * - Performs a software reset. + * - Responds with an I/ERROR (056) message. + * - Returns to command mode. + * + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::userAbort() +{ + uint8_t status; + char cmd_name[20]; + + // "+++" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[45]))); + + // send command + status = sendCommand( cmd_name, I_ERROR, 10000 ); + + if (status == 0) + { + // check error code + getErrorCode(); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("userAbort OK\n")); + #endif + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } + +} + + + + +/* + * name: socketAbort + * While the iChip is in Internet mode, during a TCP or UDP socket operation, it + * is possible to override iChip’s normal timeout procedure and abort the current + * socket operation in an orderly manner. This is achieved by sending the iChip + * a sequence of three ASCII (-) characters (---) following a half second + * silence period. The socket commands to which this applies are: STCP, SUDP, + * SSND, and SFSH. When iChip detects the socket abort command, it aborts the + * last socket command and returns an I/ERROR following the STCP and SUDP + * commands, or I/OK during an SSND or SFSH command. + * + * @return '0' if ok, '1' if error + */ +uint8_t WaspWIFI_PRO::socketAbort() +{ + uint8_t status; + char cmd_name[20]; + + // "---" + strcpy_P(cmd_name, (char*)pgm_read_word(&(table_WiReach[63]))); + + // send command + status = sendCommand(cmd_name, I_ERROR, 10000); + + if (status == 0) + { + // check error code + getErrorCode(); + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("userAbort OK\n")); + #endif + return 0; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/*! + * @brief This function enables/disables the Roaming Mode + * @param uint8_t mode: ENABLED or DISABLED + * @return '0' if ok; '1' if error + */ +uint8_t WaspWIFI_PRO::roamingMode(uint8_t mode) +{ + uint8_t status; + char cmd_name[20]; + char param1[20]; + + if ((mode!=ENABLED) && (mode!=DISABLED)) + { + return 1; + } + + // convert to string + utoa( (uint16_t) mode, param1, 10 ); + + // "WROM" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[50]))); + + // generate "AT+iWROM=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000 ); + + if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("roamingMode OK\n")); + #endif + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/*! + * @brief Sets the time interval – n – between consecutive scans that + * iChip performs for APs in its vicinity + * @param uint8_t n: 1-3600 seconds (default: 5 seconds) + * @return '0' if ok; '1' if error + */ +uint8_t WaspWIFI_PRO::setScanInterval(uint8_t n) +{ + uint8_t status; + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( (uint16_t) n, param1, 10 ); + + // "WPSI" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[59]))); + + // generate "AT+iWPSI=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000); + + if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Set Low Threshold OK\n")); + #endif + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/*! + * @brief Sets a low SNR threshold for iChip in Roaming mode. If the SNR value + * of the signal from the AP that iChip is currently associated with + * drops below n, iChip is triggered by the SNR low event + * @param uint8_t n: 0-254 dB (default: 10 dB) + * @return '0' if ok; '1' if error + */ +uint8_t WaspWIFI_PRO::setLowThreshold(uint8_t n) +{ + uint8_t status; + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( (uint16_t) n, param1, 10 ); + + // "WSRL" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[57]))); + + // generate "AT+iWSRL=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000); + + if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Set Low Threshold OK\n")); + #endif + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/*! + * @brief Sets a high SNR threshold for iChip in Roaming mode. iChip will + * re-associate only with APs having SNR that is better than n + * @param uint8_t n: 10-254 dB (default: 30 dB) + * @return '0' if ok; '1' if error + */ +uint8_t WaspWIFI_PRO::setHighThreshold(uint8_t n) +{ + uint8_t status; + char cmd_name[20]; + char param1[20]; + + // convert to string + utoa( (uint16_t) n, param1, 10 ); + + // "WSRH" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[58]))); + + // generate "AT+iWSRH=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, I_ERROR, 1000 ); + + if (status == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Set High Threshold OK\n")); + #endif + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/*! + * @brief Sets the transmission power of WLAN chipset. Range: 0-14. Def: 14 + * + * Command formula: + * In any case the tranform formula is y = x*2 + 3. + * at+iwlpw=14 is transformed to 14 * 2 + 3 = 31. + * So 31 should be transformed (31 - 3)/2 = 14. + * The value 31 is in 0,5dbm. + * + * @remarks After a HW or SW reset, WLPW returns to its default value + * @param char* host: Logical name of the target server or a host IP address + * @return '0' if ok; '1' if error + * + */ +uint8_t WaspWIFI_PRO::setPower(uint8_t power) +{ + char cmd_name[20]; + char param1[20]; + uint8_t status; + + // convert to string + utoa( (uint16_t) power, param1, 10 ); + + // "WLPW" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[51]))); + + // generate "AT+iWLPW=\r" + GEN_ATCOMMAND1(cmd_name, param1); + + // send command + status = sendCommand( _command, I_OK, AT_ERROR, 1000 ); + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + + +/*! + * @brief Gets the transmission power of WLAN chipset. Range: 0-14. Def: 14 + * + * Command formula: + * In any case the tranform formula is y = x*2 + 3. + * at+iwlpw=14 is transformed to 14 * 2 + 3 = 31. + * So 31 should be transformed (31 - 3)/2 = 14. + * The value 31 is in 0,5dbm. + * + * @remarks After a HW or SW reset, WLPW returns to its default valuepl + * + * @return '0' if ok; '1' if error + * + */ +uint8_t WaspWIFI_PRO::getPower() +{ + char cmd_name[20]; + uint8_t status; + + // "WLPW" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[51]))); + + // generate "AT+iWLPW?\r" + GEN_ATQUERY(cmd_name); + + // send command + status = sendCommand(_command, I_OK, AT_ERROR, 1000); + + if (status == 1) + { + char delimiters[100]; + strcat(delimiters, _command); + strcat(delimiters, I_OK); + strcat(delimiters, EOL_CR_LF); + if (parseUint8(&_power, delimiters) != 0) + { + return 1; + } + + // make conversion _power = (_power - 3)/2 + _power = (uint8_t)((_power-3)/2); + return 0; + } + else if (status == 2) + { + getErrorCode(); + return 1; + } + else + { + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } + + return 1; +} + + + + + +/*! + * @brief Sets the certificates of the trusted certificate authorities. iChip + * accepts a server’s identity only if its certificate is signed by one + * of these authorities + * + * @param char* ca: it is referenced as the trusted certificate authority’s + * certificate during SSL3/TLS1 socket connection establishment + * (handshake). iChip establishes an SSL3/TLS1 socket connection only + * to servers having a certificate authenticated by this certificate + * authority. iChip expects cert to be multiple lines separated by + * , beginning with:-----BEGIN CERTIFICATE----- and terminating + * with: -----END CERTIFICATE-----. cert should include an RSA + * encryption public key of 1024 or 2048 bit. The signature algorithm + * may be MD2, MD5 or SHA1. Maximum size of cert is 1500 characters. + * + * @return '0' if ok; 'x' see errors + * + */ +uint8_t WaspWIFI_PRO::setCA(char* ca) +{ + char cmd_name[20]; + uint8_t status; + uint8_t error; + + /// Change Baudrate to 9600 bps: + error = changeBaudRate(9600); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error changing baudrate\n")); + #endif + return 1; + } + + // "CA" + strcpy_P( cmd_name, (char*)pgm_read_word(&(table_WiReach[52]))); + + serialFlush(_uart); + + // print "AT+iCA=\r" + printString(AT_I, _uart); + printString(cmd_name, _uart); + printByte(0x3D, _uart); + printString(ca, _uart); + printByte(0x0D, _uart); + + /* + * Wait for different lines until a good o bad answer is received + */ + status = 3; + + while (status == 3) + { + status = waitFor( I_OK, AT_ERROR, EOL_CR_LF,1000); + } + + /// Change Baudrate to 115200 bps + error = changeBaudRate(115200); + + if (error != 0) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("error changing baudrate\n")); + #endif + return 1; + } + + if (status == 1) + { + return 0; + } + else if (status == 2) + { + getErrorCode(); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error code found\n")); + #endif + return 1; + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No answer\n")); + #endif + // timeout error + _errorCode = ERROR_CODE_0000; + return 1; + } +} + + + +/* requestOTA() - It downloads a new OTA file if OTA is necessary + * + * This function downloads a new OTA file if OTA is necessary + * + * Returns + * '1' if error (see error code) +*/ +uint8_t WaspWIFI_PRO::requestOTA(char* server, + char* port, + char* user, + char* pass) +{ + uint8_t error; + char* str_pointer; + char aux_name[8]; + char path[100]; + char aux_str[10]; + long int aux_size; + uint8_t aux_version; + int length; + char format_file[10]; + char format_path[10]; + char format_size[10]; + char format_version[10]; + uint16_t handle; + + // set to zero the buffer 'path' + memset(path, 0x00, sizeof(path)); + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error: SD not present\n")); + #endif + SD.OFF(); + _errorCode = ERROR_CODE_0010; + return 1; + } + + // Delete file in the case it exists + if (SD.isFile(OTA_ver_file) == 1) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("delete file\n")); + #endif + SD.del(OTA_ver_file); + } + + // switch off the SD card + SD.OFF(); + + //////////////////////////////////////////////////////////////////////////// + // 1. Download config file + //////////////////////////////////////////////////////////////////////////// + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Downloading OTA config file...\n")); + #endif + + // Open FTP session + error = ftpOpenSession( server, port, user, pass ); + + // check response + if (error == 0) + { + handle = _ftp_handle; + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Open FTP session OK\n")); + #endif + } + else + { + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error opening FTP session\n")); + #endif + return 1; + } + + // get OTA_ver_file + error = ftpDownload(handle, OTA_ver_file, OTA_ver_file); + + // check if file was downloaded correctly + if (error == 0) + { + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("OTA_ver_file downloaded OK\n")); + #endif + } + else + { + _errorCode = ERROR_CODE_0021; + ftpCloseSession(handle); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("ERROR downloading OTA_ver_file\n")); + #endif + return 1; + } + + + //////////////////////////////////////////////////////////////////////////// + // 2. Analyze OTA_ver_file + //////////////////////////////////////////////////////////////////////////// + + // "FILE:" + strcpy_P( format_file, (char*)pgm_read_word(&(table_WIFI_FORMAT[19]))); + // "PATH:" + strcpy_P( format_path, (char*)pgm_read_word(&(table_WIFI_FORMAT[20]))); + // "SIZE:" + strcpy_P( format_size, (char*)pgm_read_word(&(table_WIFI_FORMAT[21]))); + // "VERSION:" + strcpy_P( format_version, (char*)pgm_read_word(&(table_WIFI_FORMAT[22]))); + + + SD.ON(); + SD.goRoot(); + + // clear buffer + memset(_buffer, 0x00, sizeof(_buffer)); + + // Reads the file and copy to '_buffer' + SD.cat(OTA_ver_file, 0, sizeof(_buffer)); + strcpy((char*)_buffer, SD.buffer ); + + /// 1. Search the file name + str_pointer = strstr((char*) _buffer, format_file); + if (str_pointer != NULL) + { + // Copy the FILE contents: + // get string length and check it is equal to 7 + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + if (length != 7) + { + _errorCode = ERROR_CODE_0022; + ftpCloseSession(handle); + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("length:")); + USB.println(length); + #endif + return 1; + } + // copy string + strncpy(aux_name, strchr(str_pointer, ':')+1, 7); + aux_name[7] = '\0'; + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("FILE:")); + USB.println(aux_name); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0023; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No FILE label\n")); + #endif + return 1; + } + + /// 2. Check if NO_FILE is the filename + if (strcmp(aux_name,NO_OTA) == 0) + { + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0024; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(NO_OTA); + USB.println(NO_OTA); + #endif + return 1; + } + + /// 3. Search the path + str_pointer = strstr((char*) _buffer, format_path); + if (str_pointer != NULL) + { + // copy the PATH contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + strncpy(path, strchr(str_pointer, ':') + 1, length ); + path[length] = '\0'; + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("PATH:")); + USB.println(path); + #endif + + // delete actual program + SD.del(aux_name); + } + else + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0025; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No PATH label\n")); + #endif + return 1; + } + + /// 4. Search file size + str_pointer = strstr((char*) _buffer, format_size); + if (str_pointer != NULL) + { + // copy the SIZE contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + // check length does not overflow + if (length >= (int)sizeof(aux_str)) + { + length = sizeof(aux_str)-1; + } + strncpy(aux_str, strchr(str_pointer, ':')+1, length); + aux_str[length] = '\0'; + + // converto from string to int + aux_size = atol(aux_str); + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("SIZE:")); + USB.println(aux_size); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0026; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No SIZE label\n")); + #endif + return 1; + } + + /// 5. Search Version + str_pointer = strstr((char*) _buffer, format_version); + if (str_pointer != NULL) + { + // copy the SIZE contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + // check length does not overflow + if (length >= (int)sizeof(aux_str)) + { + length = sizeof(aux_str)-1; + } + strncpy(aux_str, strchr(str_pointer, ':')+1, length); + aux_str[length] = '\0'; + + // convert from string to uint8_t + aux_version=(uint8_t)atoi(aux_str); + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("VERSION:")); + USB.println(aux_version,DEC); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0027; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("No VERSION label\n")); + #endif + return 1; + } + + // get actual program version + uint8_t prog_version = Utils.getProgramVersion(); + // get actual program name (PID) + char prog_name[8]; + Utils.getProgramID(prog_name); + + // check if version number + #ifdef CHECK_VERSION + if (strcmp(prog_name,aux_name) == 0) + { + if (prog_version >= aux_version) + { + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0028; + + // if we have specified the same program id and lower/same version + // number, then do not proceed with OTA + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Invalid version: actual=")); + USB.print(prog_version,DEC); + USB.print(F("; new=")); + USB.println(aux_version,DEC); + #endif + return 1; + } + } + #endif + + + //////////////////////////////////////////////////////////////////////////// + // 3. Download binary file + //////////////////////////////////////////////////////////////////////////// + + #if DEBUG_WIFI_PRO > 1 + PRINT_WIFI_PRO(F("Downloading OTA FILE\n")); + #endif + + // get binary file + error = ftpDownload(handle, (char*)aux_name, aux_name); + + if (error == 0) + { + // check if size matches + SD.ON(); + // get file size + int32_t sd_file_size = SD.getFileSize(aux_name); + if (sd_file_size != aux_size) + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0029; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Size does not match\n")); + PRINT_WIFI_PRO(F("sd_file_size:")); + USB.println(sd_file_size); + PRINT_WIFI_PRO(F("UPGRADE.TXT size field:")); + USB.println(aux_size); + #endif + return 1; + } + #if DEBUG_WIFI_PRO > 1 + SD.ls(); + #endif + ftpCloseSession(handle); + Utils.loadOTA(aux_name,aux_version); + return 0; + } + else + { + SD.OFF(); + ftpCloseSession(handle); + _errorCode = ERROR_CODE_0030; + #if DEBUG_WIFI_PRO > 0 + PRINT_WIFI_PRO(F("Error getting binary\n")); + #endif + return 1; + } + + return 1; +} + + + + + +// Preinstantiate Objects ///////////////////////////////////////////////////// + +WaspWIFI_PRO WIFI_PRO = WaspWIFI_PRO(); + +/////////////////////////////////////////////////////////////////////////////// diff --git a/libraries/WIFI_PRO/WaspWIFI_PRO.h b/libraries/WIFI_PRO/WaspWIFI_PRO.h new file mode 100755 index 0000000..1dfa1bb --- /dev/null +++ b/libraries/WIFI_PRO/WaspWIFI_PRO.h @@ -0,0 +1,314 @@ +/*! \file WaspWIFI_PRO.h + \brief Library for managing WIFI modules + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: Yuri Carmona + */ + +#ifndef WaspWIFI_PRO_h +#define WaspWIFI_PRO_h + +/****************************************************************************** + * Includes + *****************************************************************************/ + +#include +#include +#include +#include "./utility/ati_generator.h" + + +/****************************************************************************** + * Definitions & Declarations + *****************************************************************************/ + +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + * \Remarks do not enable mode 2 unless SOCKET1 is used + */ +#define DEBUG_WIFI_PRO 0 + +// define print message +#define PRINT_WIFI_PRO(str) USB.print(F("[WIFI] ")); USB.print(str); + + + +//! Command types +const uint8_t TYPE_SET_EQ = 1; // =value +const uint8_t TYPE_SET_DOT = 2; // :value +const uint8_t TYPE_ASSIGN = 3; // ~value +const uint8_t TYPE_READ = 4; // ? +const uint8_t TYPE_ALLOWED = 5; // =? + + + +//! AUTHENTICATION MODES // +enum authentication_modes +{ + OPEN = 0, // no security + WEP64 = 1, // WEP 64 + WEP128 = 2, // WEP 128 + WPA = 3, // WPA-PSK with TKIP encryption + WPA2 = 4, // WPA2-PSK with TKIP or AES encryption +}; + + +//! OTA CONSTANTS // +#define CHECK_VERSION // when defined it enables the version cheking + + + +//! Profile definition for multiple SSIDs +enum ProfileClientEnum +{ + PROFILE_0 = 0, + PROFILE_1 = 1, + PROFILE_2 = 2, + PROFILE_3 = 3, + PROFILE_4 = 4, + PROFILE_5 = 5, + PROFILE_6 = 6, + PROFILE_7 = 7, + PROFILE_8 = 8, + PROFILE_9 = 9 +}; + + +//! Profile definition for different connections (SSID, TCP sockets, etc...) +enum WiFiWorkingMode +{ + MODE_STATION = 0, + MODE_ACCESS_POINT = 1, +}; + +struct listen_socket_t +{ + uint16_t handle; // socket handle + int8_t status; // 0: active; -1: non-active + char ip[16]; // xxx.xxx.xxx.xxx + uint16_t port; // remote connection port + int size; // size of pending bytes +}; + +/****************************************************************************** + * Class + *****************************************************************************/ +//! WaspWIFI_PRO Class +/*! + WaspWIFI_PRO Class defines all the variables and functions used to manage + WIFI modules. + */ + +class WaspWIFI_PRO : public WaspUART +{ + +private: + + //! Private Methods + uint16_t getErrorCode(); + uint16_t getResponse(); + + + //! buffer for command generation + char _command[300]; + void generator(uint8_t type, int n, const char *cmd_name, ...); + + +public: + + //! class constructor + WaspWIFI_PRO() + { + //do nothing + }; + + + // Attributes + uint16_t _errorCode; + uint16_t _rtt; + uint32_t _value; + char _ip[16]; // aaa.bbb.ccc.ddd + char _gw[16]; // aaa.bbb.ccc.ddd + char _netmask[16]; // aaa.bbb.ccc.ddd + char _dns1[16]; // aaa.bbb.ccc.ddd + char _dns2[16]; // aaa.bbb.ccc.ddd + uint16_t _socket_handle; + uint16_t _ftp_handle; + uint8_t _backlog; + uint32_t _filesize; + uint16_t _rate; + uint16_t _level; + uint16_t _quality; + char _essid[50]; + char _bssid[18]; + uint8_t _channel; + uint8_t _snr; + uint8_t _power; + listen_socket_t socket[10]; + + // Public Methods + uint8_t ON(uint8_t socket); + void OFF(uint8_t socket); + uint8_t resetValues(); + + // AP settings + uint8_t setESSID(char* ssid); + uint8_t setESSID(uint8_t n, char* ssid); + uint8_t getESSID(); + uint8_t setPassword(uint8_t securityMode); + uint8_t setPassword(uint8_t securityMode, char* pass); + uint8_t setPassword(uint8_t n, uint8_t securityMode, char* pass); + uint8_t setWorkingMode(uint8_t n); + uint8_t setServerPoolSize(uint8_t range); + uint8_t softReset(); + uint8_t reportStatus(); + uint8_t reportStatus4(); + uint8_t reportStatusComplete(); + bool isConnected(); + bool isConnectedMultiple(); + bool isConnected(uint32_t total_time,uint32_t period_time); + uint8_t ping( char* host ); + + // Print functions + void printErrorCode(); + void printErrorCode(uint16_t error); + void printSockets(); + uint8_t scan(); + + // Common API functions + uint8_t parseResponse(uint16_t* number); + uint8_t parseResponse2(uint16_t* number); + uint8_t parseResponse3(); + uint8_t parseResponse4(); + uint8_t parseResponse5(int* number); + + uint16_t getResponseValue(); + uint16_t getResponseValue2(); + uint8_t getResponseValue3(); + uint8_t getResponseValue4(uint8_t index); + uint8_t getResponseValue5(); + + uint8_t changeBaudRate(uint32_t rate); + uint8_t userAbort(); + uint8_t socketAbort(); + + // IP address + uint8_t setIP(char* ip); + uint8_t getIP(); + uint8_t setDNS(char* ip); + uint8_t setDNS(uint8_t n, char* ip); + uint8_t getDNS(uint8_t n); + uint8_t setGateway(char* ip); + uint8_t getGateway(); + uint8_t setNetmask(char* ip); + uint8_t getNetmask(); + + // HTTP functions + uint8_t setURL( char* protocol, + char* host, + char* port, + char* link ); + + uint8_t getURL( char* protocol, + char* host, + char* port, + char* link ); + + uint8_t post( char* text ); + uint8_t setContentType(char* str); + + uint8_t sendFrameToMeshlium(char* protocol, + char* host, + char* port, + uint8_t* buffer, + uint16_t length); + + + // FTP functions + uint8_t ftpOpenSession( char* server, + char* port, + char* user, + char* pass); + + uint8_t ftpSecureOpenSession(char* server, + char* port, + char* user, + char* pass); + + uint8_t ftpCloseSession(uint16_t handle); + + uint8_t ftpFileSize(uint16_t handle, char* path); + uint8_t ftpUpload(uint16_t handle, char* server_path, char* sd_path ); + uint8_t ftpDownload(uint16_t handle, char* server_path, char* sd_path); + uint8_t ftpMakeDir(uint16_t handle, char* path); + uint8_t ftpChangeCWD(uint16_t handle, char* path); + uint8_t ftpListing(uint16_t handle); + uint8_t ftpListing(uint16_t handle, char* path); + + // TCP/UDP functions + uint8_t setTCPclient(char* host, char* remote_port ); + uint8_t setTCPclient(char* host, char* remote_port, char* local_port); + uint8_t setUDP(char* host, char* remote_port ); + uint8_t setUDP(char* host, char* remote_port, char* local_port); + uint8_t send(uint16_t handle, char* data); + uint8_t send(uint16_t handle, uint8_t* data, uint16_t length); + uint8_t receive(uint16_t handle); + uint8_t receive(uint16_t handle, uint32_t timeout); + uint8_t closeSocket(); + uint8_t closeSocket(uint16_t handle); + uint8_t closeDownSockets(); + uint8_t setTCPserver(char* local_port, uint8_t backlog); + uint8_t getAllSocketStatus(); + uint8_t getSocketStatus(uint16_t handle); + + + // Time Server settings + uint8_t setTimeServer(char* ip); + uint8_t setTimeServer(uint8_t n, char* ip); + uint8_t timeActivationFlag(bool flag); + uint8_t setGMT(int8_t gmt); + uint8_t reportStatus8(); + uint8_t setTimeFromWIFI(); + + // OTA programming + uint8_t requestOTA( char* server, + char* port, + char* user, + char* pass); + + // Roaming mode + uint8_t roamingMode(uint8_t mode); + uint8_t setScanInterval(uint8_t n); + uint8_t setLowThreshold(uint8_t n); + uint8_t setHighThreshold(uint8_t n); + + // Power settings + uint8_t setPower(uint8_t power); + uint8_t getPower(); + + // SSL/TLS + uint8_t setCA(char* ca); +}; + +extern WaspWIFI_PRO WIFI_PRO; + +#endif diff --git a/libraries/WIFI_PRO/keywords.txt b/libraries/WIFI_PRO/keywords.txt new file mode 100644 index 0000000..572eb79 --- /dev/null +++ b/libraries/WIFI_PRO/keywords.txt @@ -0,0 +1,125 @@ +# WiReach keywords # + +WIFI_PRO KEYWORD1 + +WaspWIFI_PRO KEYWORD2 +_errorCode KEYWORD2 +_rtt KEYWORD2 +_value KEYWORD2 +_ip KEYWORD2 +_gw KEYWORD2 +_ftp_handle KEYWORD2 +_socket_handle KEYWORD2 +_backlog KEYWORD2 +_filesize KEYWORD2 +_rate KEYWORD2 +_level KEYWORD2 +_quality KEYWORD2 +_bssid KEYWORD2 +_channel KEYWORD2 +_snr KEYWORD2 +_buffer KEYWORD2 +_length KEYWORD2 +_netmask KEYWORD2 +_dns1 KEYWORD2 +_dns2 KEYWORD2 +_essid KEYWORD2 +resetValues KEYWORD2 +setESSID KEYWORD2 +setPassword KEYWORD2 +softReset KEYWORD2 +isConnected KEYWORD2 +isConnectedMultiple KEYWORD2 +ping KEYWORD2 +printErrorCode KEYWORD2 +printSockets KEYWORD2 +scan KEYWORD2 +setIP KEYWORD2 +getIP KEYWORD2 +setDNS KEYWORD2 +setGateway KEYWORD2 +setNetmask KEYWORD2 +setURL KEYWORD2 +getURL KEYWORD2 +post KEYWORD2 +sendFrameToMeshlium KEYWORD2 +ftpOpenSession KEYWORD2 +ftpFileSize KEYWORD2 +ftpCloseSession KEYWORD2 +ftpUpload KEYWORD2 +ftpDownload KEYWORD2 +ftpMakeDir KEYWORD2 +ftpChangeCWD KEYWORD2 +ftpListing KEYWORD2 +ftpSecureOpenSession KEYWORD2 +setTCPclient KEYWORD2 +setUDP KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +receiveTimeout KEYWORD2 +closeSocket KEYWORD2 +closeDownSockets KEYWORD2 +setTCPserver KEYWORD2 +getAllSocketStatus KEYWORD2 +getSocketStatus KEYWORD2 +setTimeServer KEYWORD2 +timeActivationFlag KEYWORD2 +setGMT KEYWORD2 +setTimeFromWIFI KEYWORD2 +requestOTA KEYWORD2 +roamingMode KEYWORD2 +getGateway KEYWORD2 +getNetmask KEYWORD2 +getDNS KEYWORD2 +getESSID KEYWORD2 +setCA KEYWORD2 +reportStatusComplete KEYWORD2 +setScanInterval KEYWORD2 +setLowThreshold KEYWORD2 +setHighThreshold KEYWORD2 +setWorkingMode KEYWORD2 +setServerPoolSize KEYWORD2 +socket KEYWORD2 +reportStatus KEYWORD2 +reportStatus4 KEYWORD2 +parseResponse KEYWORD2 +parseResponse2 KEYWORD2 +parseResponse3 KEYWORD2 +parseResponse4 KEYWORD2 +parseResponse5 KEYWORD2 +getResponseValue KEYWORD2 +getResponseValue2 KEYWORD2 +getResponseValue3 KEYWORD2 +getResponseValue4 KEYWORD2 +getResponseValue5 KEYWORD2 +changeBaudRate KEYWORD2 +userAbort KEYWORD2 +socketAbort KEYWORD2 +setContentType KEYWORD2 +reportStatus8 KEYWORD2 + + +OPEN LITERAL1 +WEP64 LITERAL1 +WEP128 LITERAL1 +WPA LITERAL1 +WPA2 LITERAL1 +PROFILE_0 LITERAL1 +PROFILE_1 LITERAL1 +PROFILE_2 LITERAL1 +PROFILE_3 LITERAL1 +PROFILE_4 LITERAL1 +PROFILE_5 LITERAL1 +PROFILE_6 LITERAL1 +PROFILE_7 LITERAL1 +PROFILE_8 LITERAL1 +PROFILE_9 LITERAL1 +MODE_STATION LITERAL1 +MODE_ACCESS_POINT LITERAL1 +WIFI_PRO_SCANFILE LITERAL1 +WIFI_PRO_LISTFILE LITERAL1 +TYPE_SET_EQ LITERAL1 +TYPE_SET_DOT LITERAL1 +TYPE_ASSIGN LITERAL1 +TYPE_READ LITERAL1 +TYPE_ALLOWED LITERAL1 diff --git a/libraries/WIFI_PRO/utility/ati_error_codes.h b/libraries/WIFI_PRO/utility/ati_error_codes.h new file mode 100644 index 0000000..8fa49bf --- /dev/null +++ b/libraries/WIFI_PRO/utility/ati_error_codes.h @@ -0,0 +1,221 @@ +/*! \file ati_error_codes.h + \brief Definition of the possible error codes + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http:// www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascon + Implementation: Yuri Carmona + + */ + +#ifndef ATI_ERRORCODE_H_ +#define ATI_ERRORCODE_H_ + +//! ERROR CODES for the AT+i library +#define ERROR_CODE_0000 0 // Common Waspmote API timeout error +#define ERROR_CODE_0010 10 // Waspmote API: SD not present +#define ERROR_CODE_0011 11 // Waspmote API: SD file not created +#define ERROR_CODE_0012 12 // Waspmote API: SD error opening file +#define ERROR_CODE_0013 13 // Waspmote API: SD error setting file offset +#define ERROR_CODE_0014 14 // Waspmote API: SD error writing +#define ERROR_CODE_0020 20 // Waspmote API: rx buffer full +#define ERROR_CODE_0021 21 // Waspmote API: error downloading UPGRADE.TXT +#define ERROR_CODE_0022 22 // Waspmote API: filename in UPGRADE.TXT is not a 7-byte name +#define ERROR_CODE_0023 23 // Waspmote API: no FILE label is found in UPGRADE.TXT +#define ERROR_CODE_0024 24 // Waspmote API: NO_FILE is defined as FILE in UPGRADE.TXT +#define ERROR_CODE_0025 25 // Waspmote API: no PATH label is found in UPGRADE.TXT +#define ERROR_CODE_0026 26 // Waspmote API: no SIZE label is found in UPGRADE.TXT +#define ERROR_CODE_0027 27 // Waspmote API: no VERSION label is found in UPGRADE.TXT +#define ERROR_CODE_0028 28 // Waspmote API: version indicated in UPGRADE.TXT is lower/equal to Waspmote's version +#define ERROR_CODE_0029 29 // Waspmote API: file size does not match the indicated in UPGRADE.TXT +#define ERROR_CODE_0030 30 // Waspmote API: error downloading binary file +#define ERROR_CODE_0031 31 // Waspmote API: invalid data length +#define ERROR_CODE_0041 41 // Illegal delimiter +#define ERROR_CODE_0042 42 // Illegal value +#define ERROR_CODE_0043 43 // CR expected +#define ERROR_CODE_0044 44 // Number expected +#define ERROR_CODE_0045 45 // CR or ‘,’ expected +#define ERROR_CODE_0046 46 // DNS expected +#define ERROR_CODE_0047 47 // ‘:’ or ‘~’ expected +#define ERROR_CODE_0048 48 // String expected +#define ERROR_CODE_0049 49 // ‘:’ or ‘=’ expected +#define ERROR_CODE_0050 50 // Text expected +#define ERROR_CODE_0051 51 // Syntax error +#define ERROR_CODE_0052 52 // ‘,’ expected +#define ERROR_CODE_0053 53 // Illegal command code +#define ERROR_CODE_0054 54 // Error when setting parameter +#define ERROR_CODE_0055 55 // Error when getting parameter value +#define ERROR_CODE_0056 56 // User abort +#define ERROR_CODE_0057 57 // Error when trying to establish PPP +#define ERROR_CODE_0058 58 // Error when trying to establish SMTP +#define ERROR_CODE_0059 59 // Error when trying to establish POP3 +#define ERROR_CODE_0060 60 // Single session body for MIME exceeds the maximum allowed +#define ERROR_CODE_0061 61 // Internal memory failure +#define ERROR_CODE_0062 62 // User aborted the system +#define ERROR_CODE_0063 63 // ~CTSH needs to be LOW to change to hardware flow control. +#define ERROR_CODE_0064 64 // User aborted last command using ‘---’ +#define ERROR_CODE_0065 65 // iChip unique ID already exists +#define ERROR_CODE_0066 66 // Error when setting the MIF parameter +#define ERROR_CODE_0067 67 // Command ignored as irrelevant +#define ERROR_CODE_0068 68 // iChip serial number already exists +#define ERROR_CODE_0069 69 // Timeout on host communication +#define ERROR_CODE_0070 70 // Modem failed to respond +#define ERROR_CODE_0071 71 // No dial tone response +#define ERROR_CODE_0072 72 // No carrier modem response +#define ERROR_CODE_0073 73 // Dial failed +#define ERROR_CODE_0074 74 // Modem connection with ISP lost -or- LAN connection lost -or- WLAN connection lost +#define ERROR_CODE_0075 75 // Access denied to ISP server +#define ERROR_CODE_0076 76 // Unable to locate POP3 server +#define ERROR_CODE_0077 77 // POP3 server timed out +#define ERROR_CODE_0078 78 // Access denied to POP3 server +#define ERROR_CODE_0079 79 // POP3 failed +#define ERROR_CODE_0080 80 // No suitable message in mailbox +#define ERROR_CODE_0081 81 // Unable to locate SMTP server +#define ERROR_CODE_0082 82 // SMTP server timed out +#define ERROR_CODE_0083 83 // SMTP failed +#define ERROR_CODE_0084 84 // RESERVED +#define ERROR_CODE_0085 85 // RESERVED +#define ERROR_CODE_0086 86 // Writing to internal non-volatile parameters database failed +#define ERROR_CODE_0087 87 // Web server IP registration failed +#define ERROR_CODE_0088 88 // Socket IP registration failed +#define ERROR_CODE_0089 89 // E-mail IP registration failed +#define ERROR_CODE_0090 90 // IP registration failed for all methods specified +#define ERROR_CODE_0091 91 // RESERVED +#define ERROR_CODE_0092 92 // RESERVED +#define ERROR_CODE_0093 93 // RESERVED +#define ERROR_CODE_0094 94 // In Always Online mode, connection was lost and re-established +#define ERROR_CODE_0096 96 // A remote host, which had taken over iChip through the LATI port, was disconnected +#define ERROR_CODE_0098 98 // RESERVED +#define ERROR_CODE_0099 99 // RESERVED +#define ERROR_CODE_0100 100 // Error restoring default parameters +#define ERROR_CODE_0101 101 // No ISP access numbers defined +#define ERROR_CODE_0102 102 // No USRN defined +#define ERROR_CODE_0103 103 // No PWD entered +#define ERROR_CODE_0104 104 // No DNS defined +#define ERROR_CODE_0105 105 // POP3 server not defined +#define ERROR_CODE_0106 106 // MBX (mailbox) not defined +#define ERROR_CODE_0107 107 // MPWD (mailbox password) not defined +#define ERROR_CODE_0108 108 // TOA (addressee) not defined +#define ERROR_CODE_0109 109 // REA (return e-mail address) not defined +#define ERROR_CODE_0110 110 // SMTP server not defined +#define ERROR_CODE_0111 111 // Serial data overflow +#define ERROR_CODE_0112 112 // Illegal command when modem online +#define ERROR_CODE_0113 113 // Remote firmware update attempted but not completed. The original firmware remained intact. +#define ERROR_CODE_0114 114 // E-mail parameters update rejected +#define ERROR_CODE_0115 115 // SerialNET could not be started due to missing parameters +#define ERROR_CODE_0116 116 // Error parsing a new trusted CA certificate +#define ERROR_CODE_0117 117 // Error parsing a new Private Key +#define ERROR_CODE_0118 118 // Protocol specified in the USRV parameter does not exist or is unknown +#define ERROR_CODE_0119 119 // WPA passphrase too short has to be 8-63 chars +#define ERROR_CODE_0120 120 // RESERVED +#define ERROR_CODE_0121 121 // RESERVED +#define ERROR_CODE_0122 122 // SerialNET error: Host Interface undefined (HIF=0) +#define ERROR_CODE_0123 123 // SerialNET mode error: Host baud rate cannot be determined +#define ERROR_CODE_0124 124 // SerialNET over TELNET error: HIF parameter must be set to 1 or 2 +#define ERROR_CODE_0125 125 // Invalid WEP key +#define ERROR_CODE_0126 126 // Invalid parameters’ profile number +#define ERROR_CODE_0128 128 // Product ID already exists +#define ERROR_CODE_0129 129 // HW pin can not be changed after Product-ID was set + +#define ERROR_CODE_0200 200 // Socket does not exist +#define ERROR_CODE_0201 201 // Socket empty on receive +#define ERROR_CODE_0202 202 // Socket not in use +#define ERROR_CODE_0203 203 // Socket down +#define ERROR_CODE_0204 204 // No available sockets +#define ERROR_CODE_0206 206 // PPP open failed for socket +#define ERROR_CODE_0207 207 // Error creating socket +#define ERROR_CODE_0208 208 // Socket send error +#define ERROR_CODE_0209 209 // Socket receive error +#define ERROR_CODE_0210 210 // PPP down for socket +#define ERROR_CODE_0212 212 // Socket flush error +#define ERROR_CODE_0215 215 // No carrier error on socket operation +#define ERROR_CODE_0216 216 // General exception +#define ERROR_CODE_0217 217 // Out of memory +#define ERROR_CODE_0218 218 // An STCP (Open Socket) command specified a local port number that is already in use +#define ERROR_CODE_0219 219 // SSL initialization/internal CA certificate loading error +#define ERROR_CODE_0220 220 // SSL3 negotiation error +#define ERROR_CODE_0221 221 // Illegal SSL socket handle. Must be an open and active TCP socket. +#define ERROR_CODE_0222 222 // Trusted CA certificate does not exist +#define ERROR_CODE_0223 223 // RESERVED +#define ERROR_CODE_0224 224 // Decoding error on incoming SSL data +#define ERROR_CODE_0225 225 // No additional SSL sockets available +#define ERROR_CODE_0226 226 // Maximum SSL packet size (2KB) exceeded +#define ERROR_CODE_0227 227 // AT+iSSND command failed because size of stream sent exceeded 2048 bytes +#define ERROR_CODE_0228 228 // AT+iSSND command failed because checksum calculated does not match checksum sent by host +#define ERROR_CODE_0229 229 // SSL parameters are missing +#define ERROR_CODE_0230 230 // Maximum packet size (4GB) exceeded + +#define ERROR_CODE_0300 300 // HTTP server unknown +#define ERROR_CODE_0301 301 // HTTP server timeout +#define ERROR_CODE_0302 302 // RESERVED +#define ERROR_CODE_0303 303 // No URL specified +#define ERROR_CODE_0304 304 // Illegal HTTP host name +#define ERROR_CODE_0305 305 // Illegal HTTP port number +#define ERROR_CODE_0306 306 // Illegal URL address +#define ERROR_CODE_0307 307 // URL address too long +#define ERROR_CODE_0308 308 // The AT+iWWW command failed because iChip does not contain a home page +#define ERROR_CODE_0309 309 // WEB server is already active with a different backlog. + +#define ERROR_CODE_0400 400 // MAC address exists +#define ERROR_CODE_0401 401 // No IP address +#define ERROR_CODE_0402 402 // Wireless LAN power set failed +#define ERROR_CODE_0403 403 // Wireless LAN radio control failed +#define ERROR_CODE_0404 404 // Wireless LAN reset failed +#define ERROR_CODE_0405 405 // Wireless LAN hardware setup failed +#define ERROR_CODE_0406 406 // Command failed because WiFi module is currently busy +#define ERROR_CODE_0407 407 // Illegal WiFi channel +#define ERROR_CODE_0408 408 // Illegal SNR threshold +#define ERROR_CODE_0409 409 // WPA connection process has not yet completed +#define ERROR_CODE_0410 410 // The network connection is offline (modem) +#define ERROR_CODE_0411 411 // Command is illegal when Bridge mode is active + +#define ERROR_CODE_0500 500 // RESERVED +#define ERROR_CODE_0501 501 // Communications platform already active +#define ERROR_CODE_0502 502 // RESERVED +#define ERROR_CODE_0503 503 // RESERVED +#define ERROR_CODE_0504 504 // RESERVED +#define ERROR_CODE_0505 505 // Cannot open additional FTP session – all FTP handles in use +#define ERROR_CODE_0506 506 // Not an FTP session handle +#define ERROR_CODE_0507 507 // FTP server not found +#define ERROR_CODE_0508 508 // Timeout when connecting to FTP server +#define ERROR_CODE_0509 509 // Failed to login to FTP server (bad username or password or account) +#define ERROR_CODE_0510 510 // FTP command could not be completed +#define ERROR_CODE_0511 511 // FTP data socket could not be opened +#define ERROR_CODE_0512 512 // Failed to send data on FTP data socket +#define ERROR_CODE_0513 513 // FTP shutdown by remote server +#define ERROR_CODE_0514 514 // RESERVED + +#define ERROR_CODE_0550 550 // Telnet server not found +#define ERROR_CODE_0551 551 // Timeout when connecting to Telnet server +#define ERROR_CODE_0552 552 // Telnet command could not be completed +#define ERROR_CODE_0553 553 // Telnet session shutdown by remote server +#define ERROR_CODE_0554 554 // A Telnet session is not currently active +#define ERROR_CODE_0555 555 // A Telnet session is already open +#define ERROR_CODE_0556 556 // Telnet server refused to switch to BINARY mode +#define ERROR_CODE_0557 557 // Telnet server refused to switch to ASCII mode +#define ERROR_CODE_0558 558 // RESERVED +#define ERROR_CODE_0559 559 // RESERVED +#define ERROR_CODE_0560 560 // Client could not retrieve a ring response e-mail +#define ERROR_CODE_0561 561 // Remote peer closed the SerialNET socket + +#define ERROR_CODE_0570 570 // PING destination not found +#define ERROR_CODE_0571 571 // No reply to PING request + +#define ERROR_CODE_0600 600 // Port Forwarding Rule will create ambiguous NAT entry + +#endif /* ATI_ERRORCODE_H_ */ diff --git a/libraries/WIFI_PRO/utility/ati_generator.h b/libraries/WIFI_PRO/utility/ati_generator.h new file mode 100755 index 0000000..0ca1a90 --- /dev/null +++ b/libraries/WIFI_PRO/utility/ati_generator.h @@ -0,0 +1,283 @@ +/*! \file ati_generator.h + \brief Library for generating AT+I commands + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascon + Implementation: Yuri Carmona + + */ + +/*! \def ati_generator + \brief The library flag + + */ + +#ifndef ati_generator_h +#define ati_generator_h + +/****************************************************************************** + * Includes + *****************************************************************************/ + +#include +#include "ati_error_codes.h" + + + +/****************************************************************************** + * Definitions & Declarations + *****************************************************************************/ + +//! GLOBAL commands + +static char I_OK[] = "I/OK"; +static char I_ERROR[] = "I/ERROR"; +static char I_ONLINE[] = "I/ONLINE"; +static char AT[] = "AT+i\r"; +static char AT_I[] = "AT+i"; // at commands header +static char AT_OK[] = "OK"; // OK response +static char AT_OK2[] = "I/("; // OK with contents +static char AT_ERROR[] = "ERROR"; // ERROR response +static char AT_ONLINE[] = "I/ONLINE"; // +static char I_OK_EOL[] = "I/OK\r\n"; +static char OTA_ver_file[] = "UPGRADE.TXT"; // Server's file +static char NO_OTA[] = "NO_FILE"; // No file in server pattern indicator +static char WIFI_PRO_SCANFILE[] = "SCANFILE.TXT"; // file to store scaning results +static char WIFI_PRO_LISTFILE[] = "LISTFILE.TXT"; // file to store listing results +static char I_SLASH[] = "I/"; +static char EOL_CR_LF[] = "\r\n"; + +/****************************************************************************** + * COMMANDS (FLASH Definitions) + ******************************************************************************/ + +/// table_WiReach ////////////////////////////////////////////////////////////// + +const char str_wireach_00[] PROGMEM = "RP10"; // 0 +const char str_wireach_01[] PROGMEM = "FD"; // 1 +const char str_wireach_02[] PROGMEM = "WLSI"; // 2 +const char str_wireach_03[] PROGMEM = "DOWN"; // 3 +const char str_wireach_04[] PROGMEM = "WST"; // 4 +const char str_wireach_05[] PROGMEM = "WKY"; // 5 +const char str_wireach_06[] PROGMEM = "WPP"; // 6 +const char str_wireach_07[] PROGMEM = "PING"; // 7 +const char str_wireach_08[] PROGMEM = "IPA"; // 8 +const char str_wireach_09[] PROGMEM = "RLNK"; // 9 +const char str_wireach_10[] PROGMEM = "\"%s://%s:%s/getpost_frame_parser.php?frame="; // 10 +const char str_wireach_11[] PROGMEM = "\"%s://%s:%s/%s\""; // 11 +const char str_wireach_12[] PROGMEM = "SLNK"; // 12 +const char str_wireach_13[] PROGMEM = "URL"; // 13 +const char str_wireach_14[] PROGMEM = "FOPN"; // 14 +const char str_wireach_15[] PROGMEM = "FSZ"; // 15 +const char str_wireach_16[] PROGMEM = "FRCV"; // 16 +const char str_wireach_17[] PROGMEM = "FCLS"; // 17 +const char str_wireach_18[] PROGMEM = "BDRA"; // 18 +const char str_wireach_19[] PROGMEM = "FSTO"; // 19 +const char str_wireach_20[] PROGMEM = "FAPN"; // 20 +const char str_wireach_21[] PROGMEM = "FSND"; // 21 +const char str_wireach_22[] PROGMEM = "FCLF"; // 22 +const char str_wireach_23[] PROGMEM = "STCP"; // 23 +const char str_wireach_24[] PROGMEM = "SUDP"; // 24 +const char str_wireach_25[] PROGMEM = "LTCP"; // 25 +const char str_wireach_26[] PROGMEM = "LSST"; // 26 +const char str_wireach_27[] PROGMEM = "SST"; // 27 +const char str_wireach_28[] PROGMEM = "SCS"; // 28 +const char str_wireach_29[] PROGMEM = "SSND%"; // 29 +const char str_wireach_30[] PROGMEM = "SRCV"; // 30 +const char str_wireach_31[] PROGMEM = "GPNM"; // 31 +const char str_wireach_32[] PROGMEM = "SDMP"; // 32 +const char str_wireach_33[] PROGMEM = "SFSH"; // 33 +const char str_wireach_34[] PROGMEM = "SCLS"; // 34 +const char str_wireach_35[] PROGMEM = "DIP"; // 35 +const char str_wireach_36[] PROGMEM = "DNS1"; // 36 +const char str_wireach_37[] PROGMEM = "DNS2"; // 37 +const char str_wireach_38[] PROGMEM = "IPG"; // 38 +const char str_wireach_39[] PROGMEM = "SNET"; // 39 +const char str_wireach_40[] PROGMEM = "NTS1"; // 40 +const char str_wireach_41[] PROGMEM = "NTS2"; // 41 +const char str_wireach_42[] PROGMEM = "NTOD"; // 42 +const char str_wireach_43[] PROGMEM = "GMTO"; // 43 +const char str_wireach_44[] PROGMEM = "RP8"; // 44 +const char str_wireach_45[] PROGMEM = "+++"; // 45 +const char str_wireach_46[] PROGMEM = "RP4"; // 46 +const char str_wireach_47[] PROGMEM = "!RP10"; // 47 +const char str_wireach_48[] PROGMEM = "WSI"; // 48 +const char str_wireach_49[] PROGMEM = "RP20"; // 49 +const char str_wireach_50[] PROGMEM = "WROM"; // 50 +const char str_wireach_51[] PROGMEM = "WLPW"; // 51 +const char str_wireach_52[] PROGMEM = "CA"; // 52 +const char str_wireach_53[] PROGMEM = "CTT"; // 53 +const char str_wireach_54[] PROGMEM = "FMKD"; // 54 +const char str_wireach_55[] PROGMEM = "FCWD"; // 55 +const char str_wireach_56[] PROGMEM = "FDL"; // 56 +const char str_wireach_57[] PROGMEM = "WSRL"; // 57 +const char str_wireach_58[] PROGMEM = "WSRH"; // 58 +const char str_wireach_59[] PROGMEM = "WPSI"; // 59 +const char str_wireach_60[] PROGMEM = "FOPS"; // 60 +const char str_wireach_61[] PROGMEM = "STAP"; // 61 +const char str_wireach_62[] PROGMEM = "DPSZ"; // 62 +const char str_wireach_63[] PROGMEM = "---"; // 63 + + +const char* const table_WiReach[] PROGMEM= +{ + str_wireach_00, + str_wireach_01, + str_wireach_02, + str_wireach_03, + str_wireach_04, + str_wireach_05, + str_wireach_06, + str_wireach_07, + str_wireach_08, + str_wireach_09, + str_wireach_10, + str_wireach_11, + str_wireach_12, + str_wireach_13, + str_wireach_14, + str_wireach_15, + str_wireach_16, + str_wireach_17, + str_wireach_18, + str_wireach_19, + str_wireach_20, + str_wireach_21, + str_wireach_22, + str_wireach_23, + str_wireach_24, + str_wireach_25, + str_wireach_26, + str_wireach_27, + str_wireach_28, + str_wireach_29, + str_wireach_30, + str_wireach_31, + str_wireach_32, + str_wireach_33, + str_wireach_34, + str_wireach_35, + str_wireach_36, + str_wireach_37, + str_wireach_38, + str_wireach_39, + str_wireach_40, + str_wireach_41, + str_wireach_42, + str_wireach_43, + str_wireach_44, + str_wireach_45, + str_wireach_46, + str_wireach_47, + str_wireach_48, + str_wireach_49, + str_wireach_50, + str_wireach_51, + str_wireach_52, + str_wireach_53, + str_wireach_54, + str_wireach_55, + str_wireach_56, + str_wireach_57, + str_wireach_58, + str_wireach_59, + str_wireach_60, + str_wireach_61, + str_wireach_62, + str_wireach_63, +}; + + + + +/// table_FORMAT ////////////////////////////////////////////////////////////// + +const char str_wireach_format_00[] PROGMEM = " (%u)"; // 0 +const char str_wireach_format_01[] PROGMEM = "I/ERROR (%u)\r\n"; // 1 +const char str_wireach_format_02[] PROGMEM = "I/%lu\r\n"; // 2 +const char str_wireach_format_03[] PROGMEM = "\r\n"; // 3 +const char str_wireach_format_04[] PROGMEM = "ERROR ("; // 4 +const char str_wireach_format_05[] PROGMEM = "%lu\r\n"; // 5 +const char str_wireach_format_06[] PROGMEM = ")\r\n"; // 6 +const char str_wireach_format_07[] PROGMEM = "AT+iRP10\r\nI/(%u,%u,%u,%u)"; // 7 +const char str_wireach_format_08[] PROGMEM = "AT+iIPA?\r\n%s\r\n"; // 8 +const char str_wireach_format_09[] PROGMEM = "0.0.0.0"; // 9 +const char str_wireach_format_10[] PROGMEM = "\"%s://%s:%s/%s\""; // 10 +const char str_wireach_format_11[] PROGMEM = "%s%s:%s,%lu:"; // 11 +const char str_wireach_format_12[] PROGMEM = "%u)"; // 12 +const char str_wireach_format_13[] PROGMEM = "I/%u:"; // 13 +const char str_wireach_format_14[] PROGMEM = "%02u%02u-%02u-%02uT%02u:%02u:%02u+%02u:%02u"; // 14 +const char str_wireach_format_15[] PROGMEM = "AT+i!rp10\r\nI/OK"; // 15 +const char str_wireach_format_16[] PROGMEM = "%s%01u"; // 16 +const char str_wireach_format_17[] PROGMEM = " ,)"; // 17 +const char str_wireach_format_18[] PROGMEM = "I/0\r\n"; // 18 +const char str_wireach_format_19[] PROGMEM = "FILE:"; // 19 +const char str_wireach_format_20[] PROGMEM = "PATH:"; // 20 +const char str_wireach_format_21[] PROGMEM = "SIZE:"; // 21 +const char str_wireach_format_22[] PROGMEM = "VERSION:"; // 22 +const char str_wireach_format_23[] PROGMEM = " ,"; // 23 +const char str_wireach_format_24[] PROGMEM = "\r\n.\r\n"; // 24 +const char str_wireach_format_25[] PROGMEM = "%d)"; // 25 +const char str_wireach_format_26[] PROGMEM = "AT+iIPG?\r\n%s\r\n"; // 26 +const char str_wireach_format_27[] PROGMEM = "AT+iSNET?\r\n%s\r\n"; // 27 +const char str_wireach_format_28[] PROGMEM = "AT+iDNS1?\r\n%s\r\n"; // 28 +const char str_wireach_format_29[] PROGMEM = "AT+iDNS2?\r\n%s\r\n"; // 29 +const char str_wireach_format_30[] PROGMEM = "AT+iWLSI?\r\n%s\r\n"; // 30 + + +const char* const table_WIFI_FORMAT[] PROGMEM= +{ + str_wireach_format_00, + str_wireach_format_01, + str_wireach_format_02, + str_wireach_format_03, + str_wireach_format_04, + str_wireach_format_05, + str_wireach_format_06, + str_wireach_format_07, + str_wireach_format_08, + str_wireach_format_09, + str_wireach_format_10, + str_wireach_format_11, + str_wireach_format_12, + str_wireach_format_13, + str_wireach_format_14, + str_wireach_format_15, + str_wireach_format_16, + str_wireach_format_17, + str_wireach_format_18, + str_wireach_format_19, + str_wireach_format_20, + str_wireach_format_21, + str_wireach_format_22, + str_wireach_format_23, + str_wireach_format_24, + str_wireach_format_25, + str_wireach_format_26, + str_wireach_format_27, + str_wireach_format_28, + str_wireach_format_29, + str_wireach_format_30, +}; + + + + + +#endif diff --git a/libraries/Wasp4G/Wasp4G.cpp b/libraries/Wasp4G/Wasp4G.cpp new file mode 100755 index 0000000..a36d399 --- /dev/null +++ b/libraries/Wasp4G/Wasp4G.cpp @@ -0,0 +1,6947 @@ +/*! \file Wasp4G.cpp + * \brief Library for managing Telit LE910 + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.1 + * Design: David Gascón + * Implementation: A. Gállego, Y. Carmona + */ + +#ifndef __WPROGRAM_H__ +#include "WaspClasses.h" +#endif + +#include "Wasp4G.h" +#include + + + +//! class constructor +Wasp4G::Wasp4G() +{ + memset(_apn, '\0', sizeof(_apn)); + memset(_apn_login, '\0', sizeof(_apn_login)); + memset(_apn_password, '\0', sizeof(_apn_password)); + strncpy(_apn, LE910_GPRS_APN, min(sizeof(_apn), strlen(LE910_GPRS_APN))); + strncpy(_apn_login, LE910_GPRS_LOGIN, min(sizeof(_apn_login), strlen(LE910_GPRS_LOGIN))); + strncpy(_apn_password, LE910_GPRS_PASSW, min(sizeof(_apn_password), strlen(LE910_GPRS_PASSW))); +} + + +// Private Methods //////////////////////////////////////////////////////////// + + + +/* + * Function: This function parses the error copde returned by the module. At the + * point this function is called, the UART is supposed to have received: + * "+CME ERROR: \r\n" and the first part of the response has been already + * detected: "+CME ERROR:", so this function needs to parse the error code + * + * If error code is parsed succesfully then the attribute _errorCode stores + * this error information + * + * @return '0' if ok; '1' if error + */ +uint8_t Wasp4G::getErrorCode() +{ + uint8_t status; + char format[20]; + + // wait for " \r\n" + status = waitFor((char*)"\r\n", 3000); + + if (status == 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("no response\n")); + #endif + return 1; + } + else + { + parseUint32((uint32_t*)&_errorCode, " \r\n"); + + #if DEBUG_WASP4G > 0 + printErrorCode( _errorCode ); + #endif + return 0; + } + +} + + + +/* Function: This function checks connection status and connect to data service + * Parameters: time: max allowed time in seconds to connect + * Return: 0 If the module is connected to data service + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + */ +uint8_t Wasp4G::checkDataConnection(uint8_t time) +{ + uint8_t answer; + uint32_t previous, max_time; + uint8_t status; + + char command_buffer[40]; + char answer1[20]; + char answer2[20]; + + answer = 0; + max_time = (unsigned long)time * 1000; + previous = millis(); + + + //// 1. Check if the module has the GPRS connection active + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[26]))); // "AT#GPRS?\r" + strcpy_P(answer1, (char*)pgm_read_word(&(table_4G[27]))); // "GPRS: 1" + strcpy_P(answer2, (char*)pgm_read_word(&(table_4G[28]))); // "GPRS: 0" + + // send command + answer = sendCommand(command_buffer, answer1, answer2, 2000); + if (answer == 1) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Connection active, nothing more to check\n")); + #endif + return 0; + } + + + //// 2. Check Network Registration Report + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[0]))); //AT+CREG?\r + strcpy_P(answer1, (char*)pgm_read_word(&(table_4G[1]))); //+CREG: 0, + do{ + // Sends the command and waits for the answer: + // answer "0,1" for "home network" + // answer "0,5" for "roaming" + answer = sendCommand(command_buffer, answer1, LE910_ERROR_CODE, 2000); + + if (answer == 1) + { + status = waitFor("\r\n", LE910_ERROR_CODE, 500); + + if (status == 1) + { + parseUint8(&answer, "\r\n"); + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("CREG: 0,")); + USB.println(answer, DEC); + #endif + } + } + delay(1000); + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + }while (((answer == 2) || (answer == 3) || (answer == 4) || (answer == 0)) && ((millis() - previous) < max_time)); + + // check bad responses or timeout + if (((answer != 1) && (answer != 5)) || ((millis() - previous) > max_time)) + { + if (answer == 0) + { + return answer + 1; + } + return answer; + } + + + //// 3. Check GPRS Network Registration Status + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[2]))); //AT+CGREG?\r + strcpy_P(answer1, (char*)pgm_read_word(&(table_4G[3]))); //+CGREG: 0, + do{ + // Sends the command and waits for the answer: + // answer "0,1" for "home network" + // answer "0,5" for "roaming" + answer = sendCommand(command_buffer, answer1, LE910_ERROR_CODE, 2000); + if (answer == 1) + { + status = waitFor("\r\n", LE910_ERROR_CODE, 500); + + if (status == 1) + { + parseUint8(&answer, "\r\n"); + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("CGREG: 0,")); + USB.println(answer, DEC); + #endif + } + } + delay(1000); + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + }while (((answer == 2) || (answer == 3) || (answer == 4) || (answer == 0)) && ((millis() - previous) < max_time)); + + // check good responses + if (((answer != 1) && (answer != 5)) || ((millis() - previous) > max_time)) + { + return answer + 6; + } + + + //// 4. Define PDP Context + // AT+CGDCONT=1,"IP",""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[29])), _apn); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 12; + } + + + //// 5. Set Authentication User ID + // AT#USERID=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[5])), _apn_login); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 13; + } + + + //// 6. Set Authentication Password + // AT#PASSW=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[6])), _apn_password); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 14; + } + + + //// 7. GPRS Context Activation + // "AT#GPRS=1\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[31]))); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 15; + } + + // delimiters <--- "+IP: \"\r\n" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[32]))); + + // get IP address in response + answer = parseString(_ip, sizeof(_ip), command_buffer); + + if (answer != 0) + { + return 16; + } + + return 0; +} + + +/* This function configures the remote server and sends the request + * Parameters; + * method: selected HTTP method: GET_METHOD + * HEAD_METHOD + * DELETE_METHOD + * POST_METHOD + * PUT_METHOD + * url: host name or IP address of the server + * port: server port + * resource: parameter indicating the HTTP resource, object of the request + * data: data to send in POST/PUT method + * + * Return: '0' if OK + * 'x' if error. See httpRequest() + */ +uint8_t Wasp4G::httpRequest(uint8_t method, + char* url, + uint16_t port, + char* resource, + char* data) +{ + return httpRequest( method, + url, + port, + resource, + (uint8_t*)data, + strlen(data)); + +} + +/* This function configures the remote server and sends the request + * Parameters; + * method: selected HTTP method: GET_METHOD + * HEAD_METHOD + * DELETE_METHOD + * POST_METHOD + * PUT_METHOD + * url: host name or IP address of the server + * port: server port + * resource: parameter indicating the HTTP resource, object of the request + * data: data to send in POST/PUT method + * length: data length to send in POST/PUT method + * + * Return: 0 if OK + * 1 if error setting URL and port + * 2 if error sending the request + * 3 if error sending POST / PUT data + * 4 if wrong method has been selected + */ +uint8_t Wasp4G::httpRequest(uint8_t method, + char* url, + uint16_t port, + char* resource, + uint8_t* data, + uint16_t length) +{ + uint8_t answer; + char command_buffer[500]; + char aux[3]; + memset( aux, 0x00, sizeof(aux) ); + + // Step1: Configure HTTP parameters + // Generate: AT#HTTPCFG=0,"",\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[0])), url, port); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, LE910_ERROR_CODE, 2000); + + if (answer == 2) + { + _errorCode = WASP4G_ERROR_MESSAGE; + return 1; + } + else if (answer == 3) + { + getErrorCode(); + return 1; + } + else if (answer == 0) + { + // timeout + _errorCode = WASP4G_ERROR_TIMEOUT; + return 1; + } + + + // Step2: Perform the request depending on the method selected as input + // in the function: GET, HEAD, DELETE, POST or PUT + if ((method == Wasp4G::HTTP_GET) || + (method == Wasp4G::HTTP_HEAD) || + (method == Wasp4G::HTTP_DELETE)) + { + // AT#HTTPQRY=0,,""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[1])), method, resource); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 5000); + + if (answer == 1) + { + return 0; + } + else + { + return 2; + } + } + else if ((method == Wasp4G::HTTP_POST) || + (method == Wasp4G::HTTP_PUT)) + { + // 2a. Send HTTP POST or PUT request + // AT#HTTPSND=0,,"", + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[2])), + method - 3, + resource, + length); + + // send command + answer = sendCommand(command_buffer, LE910_DATA_TO_MODULE, LE910_ERROR, 5000); + if (answer != 1) + { + return 2; + } + + // 2b. Send POST/PUT data + answer = sendCommand((char*)data, LE910_OK ,LE910_ERROR, 5000); + if (answer != 1) + { + return 3; + } + + return 0; + } + else if (method == Wasp4G::HTTP_POST_FRAME) + { + char php_file[27]; + + // 2a. Perform the request + // "/getpost_frame_parser.php" + strcpy_P(php_file, (char*)pgm_read_word(&(table_HTTP[5]))); + + // AT#HTTPSND=0,0,"", + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[2])), + 0, + php_file, + 6 + (length * 2)); + + answer = sendCommand(command_buffer, LE910_DATA_TO_MODULE, LE910_ERROR, 5000); + if (answer != 1) + { + return 2; + } + + // Add "frame=" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[6]))); + printString(command_buffer, 1); + + // Add frame contents in ASCII representation: 3C3D3E... + for(uint16_t x = 0; x < length; x++) + { + // make conversion from byte to hex representation in ASCII (2Bytes) + Utils.hex2str((uint8_t*)&data[x], aux, 1); + printByte(aux[0], 1); + printByte(aux[1], 1); + } + + + // 2b. Send POST/PUT data + answer = waitFor(LE910_OK ,LE910_ERROR, 5000); + if (answer != 1) + { + return 3; + } + + return 0; + + } + + // Wrong method + return 4; + +} + +/* This function waits the URC code and reads the data availble + * Parameters: wait_timeout: timeout for URC * + * Return: 0 if OK + * 1 if timeout waiting the URC + * 2 if error reading the URC + * 3 if error reading the HTTP status + * 4 if error reading the HTTP data length + * 5 if error reading the HTTP data + * 6 if error code from 4G module + * 7 if timeout waiting for data + * 8 if data length is zero + */ +uint8_t Wasp4G::httpWaitResponse(uint32_t wait_timeout) +{ + char *pointer; + uint8_t answer; + uint16_t data_size; + char command_buffer[50]; + + // 1. Wait URC: "#HTTPRING: 0," + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[3]))); + + answer = waitFor(command_buffer, wait_timeout); + if (answer == 0) + { + return 1; + } + + // 2. Read the whole response: "#HTTPRING: 0,,,\r + answer = waitFor("\r", 5000); + if (answer == 0) + { + return 2; + } + + // 3. Read + pointer = strtok((char*)_buffer, ","); + + if (pointer == NULL) + { + return 3; + } + else + { + // Store the HTTP code in attribute + _httpCode = atoi(pointer); + } + + + // 4. Skip + strtok(NULL, ","); + + + // 5. Read + pointer = strtok((char*)_buffer, ","); + + if (pointer == NULL) + { + return 4; + } + else + { + // Store the HTTP code in attribute + data_size = atoi(pointer); + } + + // 6. Read data received + if (data_size > 0) + { + // AT#HTTPRCV=0,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_HTTP[4])), 0, 0); + + // send command + answer = sendCommand(command_buffer, LE910_DATA_FROM_MODULE, LE910_ERROR, 2000); + + // check answer + if (answer == 1) + { + // Read the data + answer = waitFor("\r", 5000); + if (answer == 0) + { + return 5; + } + + // Add end of string in _buffer + _buffer[_length] = '\0'; + + return 0; + } + else if (answer == 2) + { + return 6; + } + else + { + // Timeout + return 7; + } + } + + return 8; + +} + + +/* Function: This function reads the size of a file in a FTP server + * Parameters: ftp_file: file + * Return: 0 if "ok" + * 1 if error + */ +uint8_t Wasp4G::ftpFileSize( char* ftp_file) +{ + uint8_t answer; + char *pointer; + char command_buffer[50]; + + // init variable + _filesize = 0; + + // AT#FTPFSIZE=\r + memset(command_buffer,0x00,sizeof(command_buffer)); + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_FTP[5])),ftp_file); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting filesize\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + // parse file size + char delimiters[50]; + memset(delimiters, 0x00, sizeof(delimiters)); + strcat(delimiters, "#FTPFSIZE: "); + strcat(delimiters, "\r\n"); + + if (strstr((char*)_buffer, "FTPFSIZE:") == NULL) + { + return 2; + } + + + answer = parseUint32(&_filesize, delimiters); + + if (answer == 0) + { + return 0; + } + + return 3; +} + + +/* Function: This function gets the status of a TCP or UDP socket + * Parameters: socketId: number of the socket Id + * Return: 0: ok; 1: error + */ +uint8_t Wasp4G::getSocketStatus(uint8_t socketId) +{ + uint8_t answer; + char delimiters[20]; + char command_buffer[20]; + char *pointer; + + // clear structure + socketStatus[socketId].id = 0; + socketStatus[socketId].state = 0; + socketStatus[socketId].localPort = 0; + socketStatus[socketId].remotePort = 0; + memset(socketStatus[socketId].localIp, 0x00, sizeof(socketStatus[socketId].localIp)); + memset(socketStatus[socketId].remoteIp, 0x00, sizeof(socketStatus[socketId].remoteIp)); + + // AT#SS=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[0])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 1; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + + // delimiters <-- "#SS: " + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[20]))); + + // seek pattern in module response + // the response is something similar to this: + // "#SS: ,,,,,\r\n\r\nOK\r\n" + pointer = strstr((char*)_buffer, delimiters); + + if (pointer == NULL) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: null pointer1\n")); + #endif + return 1; + } + + // delimiters <-- "#SS: ,\r\n" + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[21]))); + + // find first value skipping delimiters + pointer = strtok(pointer, delimiters); + + // iterate through response + for (int i = 0; i < 6; i++) + { + if (pointer == NULL) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: null pointer2\n")); + #endif + return 1; + } + + if (i == 0) + { + socketStatus[socketId].id = (uint8_t) strtoul( pointer, NULL, 10); + } + else if (i == 1) + { + socketStatus[socketId].state = (uint8_t) strtoul( pointer, NULL, 10); + + // if state is closed then break + if (socketStatus[socketId].state == 0) + { + break; + } + } + else if (i == 2) + { + strncpy(socketStatus[socketId].localIp, pointer, sizeof(socketStatus[socketId].localIp)); + } + else if (i == 3) + { + socketStatus[socketId].localPort = (uint16_t) strtoul( pointer, NULL, 10); + } + else if (i == 4) + { + strncpy(socketStatus[socketId].remoteIp, pointer, sizeof(socketStatus[socketId].remoteIp)); + } + else if (i == 5) + { + socketStatus[socketId].remotePort = (uint16_t) strtoul( pointer, NULL, 10); + break; + } + + pointer = strtok (NULL, " ,\r\n"); + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("socketStatus.id:")); + USB.println(socketStatus[socketId].id, DEC); + PRINT_LE910(F("socketStatus.state:")); + USB.println(socketStatus[socketId].state, DEC); + if (socketStatus[socketId].state != 0) + { + PRINT_LE910(F("socketStatus.localIp:")); + USB.println(socketStatus[socketId].localIp); + PRINT_LE910(F("socketStatus.localPort:")); + USB.println(socketStatus[socketId].localPort, DEC); + PRINT_LE910(F("socketStatus.remoteIp:")); + USB.println(socketStatus[socketId].remoteIp); + PRINT_LE910(F("socketStatus.remotePort:")); + USB.println(socketStatus[socketId].remotePort, DEC); + } + #endif + + return 0; + +} + + +/* Function: This function gets the status of all TCP/UDP socket from + * SOCKET_1 to SOCKET_6 + * + * Return: 0: ok; 1: error + */ +uint8_t Wasp4G::getAllSocketStatus() +{ + uint8_t answer; + char command_pattern[20]; + char command_buffer[20]; + char *pointer; + + // clear structure + memset(socketStatus, 0x00, sizeof(socketStatus)); + + // "AT#SS\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[31]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 1; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + // iterate through all profile from 1 to 6 + for (int profile = 0; profile < 6; profile++) + { + // "#SS: %u," + sprintf_P(command_pattern, (char*)pgm_read_word(&(table_IP[32])), profile+1); + + // seek start of correct index + pointer = strstr((char*)_buffer, command_pattern); + + // delimiters <-- "#SS: ,\r\n" + strcpy_P(command_pattern, (char*)pgm_read_word(&(table_IP[21]))); + + // find first value skipping delimiters + pointer = strtok(pointer, command_pattern); + + // iterate through response + for (int i = 0; i < 6; i++) + { + if (pointer == NULL) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: null pointer2\n")); + #endif + return 1; + } + + if (i == 0) + { + socketStatus[profile].id = (uint8_t) strtoul( pointer, NULL, 10); + } + else if (i == 1) + { + socketStatus[profile].state = (uint8_t) strtoul( pointer, NULL, 10); + + // if state is closed then break + if (socketStatus[profile].state == 0) + { + break; + } + } + else if (i == 2) + { + strncpy(socketStatus[profile].localIp, pointer, sizeof(socketStatus[profile].localIp)); + } + else if (i == 3) + { + socketStatus[profile].localPort = (uint16_t) strtoul( pointer, NULL, 10); + } + else if (i == 4) + { + strncpy(socketStatus[profile].remoteIp, pointer, sizeof(socketStatus[profile].remoteIp)); + } + else if (i == 5) + { + socketStatus[profile].remotePort = (uint16_t) strtoul( pointer, NULL, 10); + break; + } + + pointer = strtok (NULL, " ,\r\n"); + } + } + + #if DEBUG_WASP4G > 1 + for (int i = 0; i < 6; i++) + { + PRINT_LE910(F("socketStatus.id:")); + USB.println(socketStatus[i].id, DEC); + PRINT_LE910(F("socketStatus.state:")); + USB.println(socketStatus[i].state, DEC); + if (socketStatus[i].state != 0) + { + PRINT_LE910(F("socketStatus.localIp:")); + USB.println(socketStatus[i].localIp); + PRINT_LE910(F("socketStatus.localPort:")); + USB.println(socketStatus[i].localPort, DEC); + PRINT_LE910(F("socketStatus.remoteIp:")); + USB.println(socketStatus[i].remoteIp); + PRINT_LE910(F("socketStatus.remotePort:")); + USB.println(socketStatus[i].remotePort, DEC); + } + PRINT_LE910(F("---------------------------\n")); + } + #endif + + return 0; + +} + + +/* Function: This function gets the status of a TCP or UDP socket + * Parameters: socketId: number of the socket Id + * Return: 0: ok; 1: error + */ +uint8_t Wasp4G::getSocketStatusSSL(uint8_t socketId) +{ + uint8_t answer; + char delimiters[20]; + char command_buffer[20]; + char *pointer; + + // clear structure + socketStatusSSL[socketId].id = 0; + socketStatusSSL[socketId].state = 0; + + // AT#SSLS=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[13])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 1; + } + + // delimiters <-- "#SSLS: " + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[22]))); + + // seek pattern in module response + // the response is something similar to this: + // "#SSLS: ,\r\n\r\nOK\r\n" + pointer = strstr((char*)_buffer, delimiters); + + if (pointer == NULL) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: null pointer1\n")); + #endif + return 1; + } + + // delimiters <-- "#SSLS: ,\r\n" + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[23]))); + + // find first value skipping delimiters + pointer = strtok(pointer, delimiters); + + // iterate through response + for (int i = 0; i < 2; i++) + { + if (pointer == NULL) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: null pointer2\n")); + #endif + return 1; + } + + if (i == 0) + { + socketStatusSSL[socketId].id = (uint8_t) strtoul( pointer, NULL, 10); + } + else if (i == 1) + { + socketStatusSSL[socketId].state = (uint8_t) strtoul( pointer, NULL, 10); + break; + } + + pointer = strtok (NULL, " ,\r\n"); + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("socketStatusSSL.id:")); + USB.println(socketStatusSSL[socketId].id, DEC); + PRINT_LE910(F("socketStatusSSL.state:")); + USB.println(socketStatusSSL[socketId].state, DEC); + #endif + + return 0; + +} + + +/* Function: This function gets info from a TCP or UDP socket + * Parameters: socketId: number of the socket Id + * parameter: 0 for total amount (in bytes) of sent data + * 1 for total amount (in bytes) of received data + * 2 for total amount (in bytes) of data just + * arrived through the socket connection and + * currently buffered, not yet read + * 3 for total amount (in bytes) of sent and not yet + * acknowledged data + * Return: 0 or positive value from the command + * -1 if error reading the info from the socket + */ +uint8_t Wasp4G::getSocketInfo(uint8_t socketId) +{ + uint8_t answer; + char delimiters[20]; + char command_buffer[20]; + char *pointer; + + // clear structure + socketInfo[socketId].id = 0; + socketInfo[socketId].sent = 0; + socketInfo[socketId].received = 0; + socketInfo[socketId].size = 0; + socketInfo[socketId].ack = 0; + + // AT#SI=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[1])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // delimiters <-- #SI: " + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[24]))); + + // seek pattern in module response + // the reponse is something similar to this: + // "#SI: ,,,,\r\n\r\nOK\r\n" + pointer = strstr((char*)_buffer, delimiters); + + if (pointer == NULL) + { + return 1; + } + + // delimiters <-- "#SI: ,\r\n" + strcpy_P(delimiters, (char*)pgm_read_word(&(table_IP[25]))); + + // find first value skipping delimiters + pointer = strtok(pointer, delimiters); + + // iterate through response + for (int i = 0; i < 5; i++) + { + if (pointer == NULL) + { + return 1; + } + + if (i == 0) + { + socketInfo[socketId].id = (uint8_t) strtoul( pointer, NULL, 10); + } + else if (i == 1) + { + socketInfo[socketId].sent = (uint16_t) strtoul( pointer, NULL, 10); + } + else if (i == 2) + { + socketInfo[socketId].received = (uint16_t) strtoul( pointer, NULL, 10); + } + else if (i == 3) + { + socketInfo[socketId].size = (uint16_t) strtoul( pointer, NULL, 10); + } + else if (i == 4) + { + socketInfo[socketId].ack = (uint16_t) strtoul( pointer, NULL, 10); + break; + } + + pointer = strtok (NULL, " ,\r\n"); + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("socketInfo.id:")); + USB.println(socketInfo[socketId].id, DEC); + PRINT_LE910(F("socketInfo.sent:")); + USB.println(socketInfo[socketId].sent, DEC); + PRINT_LE910(F("socketInfo.received:")); + USB.println(socketInfo[socketId].received, DEC); + PRINT_LE910(F("socketInfo.size:")); + USB.println(socketInfo[socketId].size, DEC); + PRINT_LE910(F("socketInfo.ack:")); + USB.println(socketInfo[socketId].ack, DEC); + #endif + + return 0; +} + + + +// Public Methods ///////////////////////////////////////////////////////////// + +/* Function: This function inits the LE910 module + * Return: 0 if OK + * 1 for no comunication + * 2 if error switching CME errors to numeric response + * 3 if error disabling the echo from the module + * 4 if error enabling RTC update with network time + */ +uint8_t Wasp4G::ON() +{ + uint8_t counter; + uint8_t answer; + char command_buffer[50]; + + // set UART1 multiplexer to Socket1 + Utils.setMuxSocket1(); + + // Set UART + _uart = UART1; + _baudrate = LE910_RATE; + beginUART(); + + // Power on the module + digitalWrite(GPRS_PW, LOW); + delay(500); + digitalWrite(GPRS_PW, HIGH); + delay(10000); + + + // Check communication with the module sending a basic AT command + counter = 15; + answer = 0; + while ((counter > 0) && (answer == 0)) + { + answer = sendCommand("AT\r", LE910_OK, 1000); + counter--; + } + + if (answer == 0) + { + // No comunication with the module + // Power off and return an error + digitalWrite(GPRS_PW, LOW); + + // Error code for no communication + return 1; + } + + + // Set Report Mobile Equipment Error (CMEE) + counter = 3; + answer = 0; + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[19]))); //AT+CMEE=1\r + while ((counter > 0) && (answer == 0)) + { + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 500); + counter--; + } + if (answer != 1) + { + // Error switching CME errors to numeric response + // Power off and return an error + digitalWrite(GPRS_PW, LOW); + + // Error code for error switching CME errors to numeric response + return 2; + } + + + // Disable command echo + counter = 3; + answer = 0; + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[20]))); //ATE0\r + while ((counter > 0) && (answer == 0)) + { + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 500); + counter--; + } + if (answer != 1) + { + // Error disabling the echo from the module + // Power off and return an error + digitalWrite(GPRS_PW, LOW); + + // Error code disabling the echo from the module + return 3; + } + + + // setup NETWORK_UTRAN + answer = setWirelessNetwork(Wasp4G::NETWORK_3GPP); + + return 0; +} + +/* Function: This function powers off the LE910 module + * Return: nothing + */ +void Wasp4G::OFF() +{ + // close UART0 + closeUART(); + + // power down + pinMode(GPRS_PW,OUTPUT); + digitalWrite(GPRS_PW, LOW); + +} + +/* Function: This function sets a PIN / PUK code + * Parameters: code: string with the requested code + * Return: 0 if OK + * 1 if error + */ +uint8_t Wasp4G::enterPIN(char* code) +{ + return enterPIN(code, NULL); +} + +/* Function: This function sets a PIN / PUK code + * Parameters: + * code: string with the requested code + * new_code: string with the new code (only for SIM PUK or SIM PUK2) + * Return: 0 if OK, 1 if error + */ +uint8_t Wasp4G::enterPIN(char* code, char* new_code) +{ + uint8_t answer; + char command_buffer[50]; + + // generate command depending on selection + if (new_code == NULL) + { + // AT+CPIN=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_PIN[18])), code); + } + else + { + // AT+CPIN="",""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_PIN[19])), code, new_code); + } + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check response + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + return 0; +} + +/* Function: This function returns the result code for a PIN request + * Return: + * 0 for PIN ready + * 1 LE910 is awaiting SIM PIN + * 2 LE910 is awaiting SIM PUK + * 3 LE910 is awaiting phone-to-SIM card password. + * 4 LE910 is awaiting phone-to-very-first-SIM card password. + * 5 LE910 is awaiting phone-to-very-first-SIM card unblocking password. + * 6 LE910 is awaiting SIM PIN2 + * 7 LE910 is awaiting SIM PUK2 + * 8 LE910 is awaiting network personalization password + * 9 LE910 is awaiting network personalization unblocking password + * 10 LE910 is awaiting network subset personalization password + * 11 LE910 is awaiting network subset personalization unblocking password + * 12 LE910 is awaiting service provider personalization password + * 13 LE910 is awaiting service provider personalization unblocking password + * 14 LE910 is awaiting corporate personalization password + * 15 LE910 is awaiting corporate personalization unblocking password + * 254 if not expected code returned + * 255 if command error + */ +uint8_t Wasp4G::checkPIN() +{ + char command_buffer[20]; + char command_answer[20]; + uint8_t answer; + + // command: AT+CPIN?\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_PIN[0]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 255; + } + + // Seeks a code + for (int x = 0; x < 17; x++ ) + { + strcpy_P(command_answer, (char*)pgm_read_word(&(table_PIN[x+1]))); + answer = find( _buffer, _length, command_answer); + if (answer == 1) + { + return x; + } + } + + return 254; +} + + + +/* Function: This function checks connection status + * Parameters: time: max allowed time in seconds to connect + * Return: 0 If the module is connected to the network + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + */ +uint8_t Wasp4G::checkConnection(uint8_t time) +{ + uint8_t answer; + uint8_t status; + uint8_t value; + uint32_t previous; + + char command_buffer[40]; + char command_answer[20]; + + answer = 0; + previous = millis(); + + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[0]))); //AT+CREG?\r + strcpy_P(command_answer, (char*)pgm_read_word(&(table_4G[1]))); //+CREG: 0, + + while ((millis()-previous) < (uint32_t)time*1000) + { + // Sends the command and waits for the answer. The status options in + // "+CREG: 0," response are: + // 0: not registered, ME is not currently searching a new operator to register to + // 1: registered, home network + // 2: not registered, but ME is currently searching a new operator to register to + // 3: registration denied + // 4: unknown + // 5: registered, roaming + answer = sendCommand(command_buffer, command_answer, 2000); + + if (answer == 1) + { + status = waitFor("OK",500); + + if (status == 1) + { + parseUint8(&answer, "\r\n OK"); + } + } + + if ((answer == 1) || (answer == 5)) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Break condition\n")); + PRINT_LE910(F("answer:")); + USB.println(answer,DEC); + #endif + break; + } + else + { + // continue waiting for correct response + delay(1000); + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + } + + if (((answer != 1) && (answer != 5)) || ((millis() - previous) > (unsigned long)(time * 1000))) + { + if (answer == 0) + { + return answer + 1; + } + return answer; + } + + return 0; + +} + + +/* Function: This function checks EPS Network Registratio Status + * Parameters: time: max allowed time in seconds to connect + * Return: 0 if OK + + */ +uint8_t Wasp4G::checkConnectionEPS(uint8_t time) +{ + uint8_t answer; + uint8_t status; + uint32_t previous; + char command_buffer[40]; + char command_answer[20]; + + // init variables + status = 0; + answer = 0; + previous = millis(); + + //// 1. Generate command + // "AT+CEREG?\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[41]))); + + //// 2. Generate answer + // "+CEREG: 0," + strcpy_P(command_answer, (char*)pgm_read_word(&(table_4G[42]))); + + //// 3. Iterate until status is correct + while ((status != 1) && (status != 5)) + { + // Sends the command and waits for the answer. The status options in + // "+CEREG: 0," response are: + // 0 - not registered, MT is not currently searching an operator to register to. + // 1 - registered, home network. + // 2 - not registered, but MT is currently trying to attach or searching an operator to register to. + // 3 - registration denied. + // 4 - unknown (e.g. out of E-UTRAN coverage). + // 5 - registered, roaming. + // 6 - registered for "SMS only", home network (not applicable) + // 7 - registered for "SMS only", roaming (not applicable). + // 8 - attached for emergency bearer services only (See NOTE 2). + // 9 - registered for "CSFB not preferred", home network (not applicable). + // 10 - registered for "CSFB not preferred", roaming (not applicable). + + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, 2000); + + if (answer == 1) + { + // get whole response + status = waitFor(LE910_OK, 500); + + if (status == 1) + { + parseUint8(&status, "\r\n OK"); + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("----> status:")); + USB.println(status,DEC); + #endif + } + } + + // check status from response + if ((status == 1) || (status == 5)) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Break condition\n")); + PRINT_LE910(F("status:")); + USB.println(status,DEC); + #endif + break; + } + else if (status == 2) + { + // continue waiting for correct response + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Continue waiting for correct response\n")); + #endif + } + + delay(1000); + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + + // check timeout error + if ((millis() - previous) > (uint32_t)(time * 1000)) + { + return status; + } + } + + // check bad responses + if ((status != 1) && + (status != 5) && + (status != 6) && + (status != 7) && + (status != 8) && + (status != 9) && + (status != 10)) + { + if (status == 0) + { + return status + 1; + } + + return status; + } + + return 0; +} + + + +/* This function manages incoming data from the module + * Parameters: wait_time: maximum waiting time in milliseconds + * Return: 0 if 'OK', 'x' if error +*/ +uint8_t Wasp4G::manageIncomingData(unsigned long wait_time) +{ + + uint8_t answer; + char command_buffer[50]; + char sms_incoming[15]; + char IP_incoming[15]; + + // set _incomingType to no data received + _incomingType = 0; + + // "+CMTI" + strcpy_P(sms_incoming, (char*)pgm_read_word(&(table_4G[22]))); + + // "SRING: " + strcpy_P(IP_incoming, (char*)pgm_read_word(&(table_4G[23]))); + + // Wait for data + answer = waitFor(sms_incoming, IP_incoming, wait_time); + + if (answer == 1) + { + // Received data: "+CMTI: ,\r" + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Incoming SMS\n")); + #endif + + // wait for first ',' + waitFor(",", 1000); + + // wait for end of response + answer = waitFor("\r", 2000); + + if (answer == 1) + { + // store index + _smsIndex = atoi((char*) _buffer); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("SMS index:")); + USB.println(_smsIndex, DEC); + #endif + + // set attribute to SMS data + _incomingType = LE910_INCOMING_SMS; + + return 0; + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error reading SMS index\n")); + #endif + } + + return 1; + + } + else if (answer == 2) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Incoming IP data\n")); + #endif + + answer = waitFor("\r", 2000); + if (answer == 1) + { + _socketIndex = atoi((char*) _buffer); + _socketIndex--; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket Index:")); + USB.println(_socketIndex, DEC); + #endif + + // set attribute to IP data + _incomingType = LE910_INCOMING_IP; + + // wait for get socket status: + answer = getSocketStatus(_socketIndex); + + if (answer == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("getSocketStatus OK: ")); + USB.println(socketStatus[_socketIndex].state, DEC); + #endif + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("getSocketStatus ERROR.\n")); + #endif + return 1; + } + + // check if socket state is a Socket with an incoming connection, + // in that case module accepts the connection with the client + if (socketStatus[_socketIndex].state == 5) + { + // accept connection in command mode + // AT#SA=,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[37])), _socketIndex+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // get new socket status + answer = getSocketStatus(_socketIndex); + + if (answer == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("getSocketStatus OK: ")); + USB.println(socketStatus[_socketIndex].state, DEC); + #endif + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("getSocketStatus ERROR.\n")); + #endif + return 1; + } + } + else + { + return 1; + } + + // return OK + return 0; + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error reading SocketId\n")); + #endif + } + } + + // timeout error + return 3; +} + + + + +/* This function manages incoming data from sockets + * Return: 0 if 'OK', 'x' if error +*/ +uint8_t Wasp4G::manageSockets() +{ + return manageSockets(0); +} + + +/* This function manages incoming data from sockets + * Parameters: wait_time: maximum waiting time in milliseconds + * Return: 0 if 'OK', 'x' if error +*/ +uint8_t Wasp4G::manageSockets(uint32_t wait_time) +{ + uint8_t answer; + char command_buffer[50]; + uint32_t previous = millis(); + bool pending_accept = false; + bool new_accepted = false; + + //// 1. Get socket status and wait until there is + // at least one pending connection to be accepted + do + { + answer = getAllSocketStatus(); + + if (answer != 0) + { + return 1; + } + + for (int profile = 0; profile < 6; profile++) + { + if (socketStatus[profile].state == 5) + { + pending_accept = true; + } + } + + // check if there is any pending connection + if (pending_accept == true) + { + break; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(500); + + } while (((millis() - previous) < wait_time)); + + + //// 2. Accept connections if needed + for (int profile = 0; profile < 6; profile++) + { + // check if socket state is a Socket with an incoming connection, + // in that case module accepts the connection with the client + if (socketStatus[profile].state == 5) + { + // accept connection in command mode + // AT#SA=,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[37])), profile+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer == 1) + { + new_accepted = true; + } + else + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + } + } + + + //// 3. Get new socket status + answer = getAllSocketStatus(); + + if (answer == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("getSocketStatus OK\n")); + #endif + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("getSocketStatus ERROR.\n")); + #endif + return 1; + } + + // return OK if new incoming connections have been accepted + if (new_accepted == true) + { + return 0; + } + + return 1; +} + + + + +/* This function sets the parameters to use SMS + * Return: 0 if OK + * 1 if error setting the SMS format + * 2 if error selecting the storage + * 3 if error setting the incoming SMS indication +*/ +uint8_t Wasp4G::configureSMS() +{ + uint8_t answer; + char command_buffer[50]; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Setting SMS parameters\n")); + #endif + + // 1. Configure format, storage and indication parameters + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_SMS[0]))); //AT+CMGF=1 + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR,500); + if (answer != 1) + { + return 1; + } + + /* + memset(command_buffer,0x00,sizeof(command_buffer)); + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_SMS[1]))); //AT+CPMS="SM","SM","SM" + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR,500); + + if (answer != 1) + { + USB.println("Error CPMS"); + return 2; + } + + memset(command_buffer,0x00,sizeof(command_buffer)); + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_SMS[2]))); //AT+CNMI=2,1,0,0,0 + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR,500); + if (answer != 1) + { + USB.println("Error CNMI"); + return 3; + } + */ + return 0; + +} + +/* This function sends a SMS + * Parameters: phone_number: number to send the SMS + * sms_string: body of the SMS + * Return: 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown connection error + * 5 if error setting the phone number + * 6 if error sending the body +*/ +uint8_t Wasp4G::sendSMS(char* phone_number, char* sms_string) +{ + char command_buffer[50]; + uint8_t answer; + + + //// 1. Check connection + answer = checkConnection(60); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking connection\n")); + #endif + return answer; + } + + + //// 2. Send SMS + // AT+CMGS="" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_SMS[4])), phone_number); + + // send command + answer = sendCommand(command_buffer, ">"); + + // check answer + if (answer != 1) + { + printByte(0x1B, 1); //ESC ASCII + return 5; + } + + printString(sms_string, 1); + command_buffer[0] = 0x1A; + command_buffer[1] = '\0'; + answer = sendCommand(command_buffer, LE910_OK); + if (answer != 1) + { + printByte(0x1B, 1); //ESC ASCII + return 6; + } + + return 0; + +} + + + +/* Function: This function reads the last unread received message + * Parameters: none + * Return: 0 if ok + * 1 if error + */ +uint8_t Wasp4G::readNewSMS() +{ + return readNewSMS(0); +} + + +/* Function: This function reads the last unread received message + * Parameters: none + * Return: 0 if ok + * 1 if error + */ +uint8_t Wasp4G::readNewSMS(uint32_t timeout) +{ + uint8_t answer; + char command_buffer[50]; + char command_answer[10]; + char *pointer; + uint32_t previous; + + //// 1. Check connection + answer = checkConnection(60); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking connection\n")); + #endif + return answer; + } + + + //// 3. Read unread message + // AT+CMGL="REC UNREAD"\r + memset(command_buffer, 0x00, sizeof(command_buffer)); + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[36]))); + + // "+CMGL: " + memset(command_answer, 0x00, sizeof(command_answer)); + sprintf_P(command_answer, (char*)pgm_read_word(&(table_4G[39]))); + + + // get current time + previous = millis(); + + do + { + // send command + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, LE910_ERROR, LE910_OK, 2000); + + // check answer + if (answer == 1) + { + // read first line + answer = waitFor("\r\n", 1000); + + // _buffer stores a response like: + // 19,"REC UNREAD","+345901000118833","","16/06/20,12:20:20+08" + pointer = strtok((char*)_buffer,"\","); + + for (int i = 0; i < 5; i++) + { + // Get SMS index + if (i == 0) + { + _smsIndex = atoi((char*)pointer); + } + + // Get SMS status + if (i == 1) + { + strncpy(_smsStatus, pointer, sizeof(_smsStatus)); + } + + // Get phone number + if (i == 2) + { + strncpy(_smsNumber, pointer, sizeof(_smsNumber)); + } + + // Get date + if (i == 3) + { + strncpy(_smsDate, pointer, sizeof(_smsDate)); + } + + // Get time + if (i == 4) + { + strncpy(_smsTime, pointer, sizeof(_smsTime)); + } + + pointer = strtok(NULL, "\","); + } + + // Get body + waitFor("\r\n\r\nOK", 1000); + + // update buffer length + _length -= strlen("\r\n\r\nOK"); + _buffer[_length] = 0x00; + + return 0; + } + else if (answer == 4) + { + // LE910_OK + // do nothing because no incoming SMS was received + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting response\n")); + #endif + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + } while (millis()-previous < timeout); + + return 1; +} + + +/* This function reads a SMS + * Parameters: sms_index: index of the SMS into the memory + * sms_buffer: buffer to store the SMS + * Return: 0 if OK + * 1 if error getting the SMS +*/ +uint8_t Wasp4G::readSMS(uint8_t sms_index) +{ + char command_buffer[40]; + char command_answer[15]; + uint8_t answer; + char* pointer; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Reading SMS from index ")); + USB.println(sms_index, DEC); + #endif + + //// 1. Generate command request + // AT+CMGR=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_SMS[3])), sms_index); + + //// 2. Generate expected answer + // +CMGR: + memset(command_answer, 0x00, sizeof(command_answer)); + sprintf_P(command_answer,(char*)pgm_read_word(&(table_4G[40]))); + + // send command + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, LE910_ERROR, LE910_OK, 5000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // read first line + answer = waitFor("\r\n", 1000); + + // _buffer stores a response like: + // "REC READ","+34666666666","","16/06/20,10:12:34+08" + + pointer = strtok((char*)_buffer,"\","); + + for (int i = 0; i < 4; i++) + { + // Get SMS status + if (i == 0) + { + strncpy(_smsStatus, pointer, sizeof(_smsStatus)); + } + // Get phone number + if (i == 1) + { + strncpy(_smsNumber, pointer, sizeof(_smsNumber)); + } + + // Get date + if (i == 2) + { + strncpy(_smsDate, pointer, sizeof(_smsDate)); + } + + // Get time + if (i == 3) + { + strncpy(_smsTime, pointer, sizeof(_smsTime)); + } + + pointer = strtok(NULL, "\","); + } + + // Get body + waitFor("\r\n\r\nOK", 1000); + + // update buffer length + _length -= strlen("\r\n\r\nOK"); + _buffer[_length] = 0x00; + + return 0; +} + + +/* This function deletes a SMS + * Parameters: sms_index: index of the SMS into the memory + * Return: 0 if OK + * 1 if error deleting the SMS +*/ +uint8_t Wasp4G::deleteSMS(uint8_t sms_index) +{ + return deleteSMS(sms_index, SMS_DELETE_MESSAGE); +} + + + +/* This function deletes a SMS + * Parameters: + * sms_index: index of the SMS into the memory + * del_flag: + * 0: Delete message specified in + * 1: Delete all read messages from storage, leaving unread messages + * and stored mobile originated messages (whether sent or not) untouched + * 2: Delete all read messages from storage and sent mobile originated + * messages, leaving unread messages and unsent mobile originated messages untouched + * 3: Delete all read messages from storage, sent and unsent mobile + * originated messages, leaving unread messages untouched + * 4: Delete all messages from storage + * Return: 0 if OK + * 1 if error deleting the SMS +*/ +uint8_t Wasp4G::deleteSMS(uint8_t sms_index, uint8_t del_flag) +{ + char command_buffer[20]; + uint8_t answer; + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Deleting SMS from index: ")); + USB.println(sms_index, DEC); + #endif + + // AT+CMGD=,\r + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_SMS[6])), sms_index, del_flag); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + return 0; +} + + + + +/* Function: This function performs a HTTP request + * Parameters: + * method: selected HTTP method: Wasp4G::HTTP_GET + * Wasp4G::HTTP_HEAD + * Wasp4G::HTTP_DELETE + * url: host name or IP address of the server + * port: server port + * resource: parameter indicating the HTTP resource, object of the request + * Return: '0' if OK + * 'x' if error. See http() + */ +uint8_t Wasp4G::http(uint8_t method, + char* url, + uint16_t port, + char* resource) +{ + return http(method, + url, + port, + resource, + NULL); +} + + +/* Function: This function performs a HTTP request + * Parameters: + * method: selected HTTP method: Wasp4G::HTTP_GET + * Wasp4G::HTTP_HEAD + * Wasp4G::HTTP_DELETE + * Wasp4G::HTTP_POST + * Wasp4G::HTTP_PUT + * Wasp4G::HTTP_POST_FRAME + * url: host name or IP address of the server + * port: server port + * resource: parameter indicating the HTTP resource, object of the request + * data: data to send in HTTP method + * + * Return: 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + * 16 if error setting URL and port + * 17 if error sending the request + * 18 if error sending POST / PUT data + * 19 if wrong method has been selected + * 20 if timeout waiting the URC + * 21 if error reading the URC + * 22 if error reading the HTTP status + * 23 if error reading the HTTP data length + * 24 if error reading the HTTP data + * 25 if error code from 4G module while waiting for HTTP response + * 26 if timeout waiting for HTTP response + * 27 if HTTP response data length is zero + */ +uint8_t Wasp4G::http( uint8_t method, + char* url, + uint16_t port, + char* resource, + char* data) +{ + uint8_t answer; + int16_t http_data; + + // 1. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + return answer; // 1 to 15 error codes + } + + // 2. Configure parameters and send the request + answer = httpRequest(method, url, port, resource, data); + if (answer != 0) + { + return answer+15; // 16 to 19 error codes + } + + // 3. Wait for the response + answer = httpWaitResponse(LE910_HTTP_TIMEOUT); + if (answer != 0) + { + return answer+19; // 20 to 27 error codes + } + + return 0; +} + + + + + + +/* Function: This function performs a HTTP GET request to the Meshlium device + * connected in port and host specified as input + * Parameters: + * url: host name or IP address of the server + * port: server port + * resource: parameter indicating the HTTP resource, object of the + * request + * POST_PUT_data: data to send in POST/PUT method + * POST_PUT_length: data length to send in POST/PUT method + * Return: 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + * 16 if error setting URL and port + * 17 if error sending the request + * 18 if error sending POST / PUT data + * 19 if wrong method has been selected + * 20 if timeout waiting the URC + * 21 if error reading the URC + * 22 if error reading the HTTP status + * 23 if error reading the HTTP data length + * 24 if error reading the HTTP data + * 25 if error code from 4G module while waiting for HTTP response + * 26 if timeout waiting for HTTP response + * 27 if HTTP response data length is zero + */ +uint8_t Wasp4G::sendFrameToMeshlium(char* url, + uint16_t port, + uint8_t* data, + uint16_t length) +{ + uint8_t answer; + int16_t http_data; + + // 1. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + return answer; // 1 to 15 error codes + } + + // 2. Configure parameters and send the request + answer = httpRequest(Wasp4G::HTTP_POST_FRAME, url, port, NULL, data, length); + if (answer != 0) + { + return answer+15; // 16 to 19 error codes + } + + // 3. Wait for the response + answer = httpWaitResponse(LE910_HTTP_TIMEOUT); + if (answer != 0) + { + return answer+19; // 20 to 27 error codes + } + + return 0; +} + + + + +/* Function: This function configures FTP parameters and opens the connection + * Parameters: server: address of FTP server + * port: port of FTP server + * username: authentication user identification string for FTP + * password: authentication password for FTP + * Return: 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + * 16 if error opening the FTP connection + * 17 if error setting the transfer type + */ +uint8_t Wasp4G::ftpOpenSession( char* server, + uint16_t port, + char* username, + char* password) +{ + uint8_t answer; + char command_buffer[100]; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Checking connection\n")); + #endif + + // 1. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + return answer; // 1 to 15 error codes + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Opening FTP session\n")); + #endif + + // 2. Configure FTP parameters and open the connection + // AT#FTPOPEN=":","","",1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_FTP[0])), + server, + port, + username, + password); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, LE910_FTP_CONF_TIMEOUT); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 16; + } + + + // 3. Set binary transfer. Once connected we can call the AT#FTPTYPE command + // AT#FTPTYPE=0\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_FTP[4]))); + + // mandatory delay + delay(2000); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + return 17; + } + + + return 0; +} + + + +/* Function: This function closes the FTP connection + * Return: 0 if OK + * 1 if error + */ +uint8_t Wasp4G::ftpCloseSession() +{ + char command_buffer[50]; + uint8_t answer; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Closing FTP session\n")); + #endif + + delay(1000); + + //AT#FTPCLOSE\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_FTP[1]))); + + // First attempt + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 10000); + + if (answer == 1) + { + // ok + return 0; + } + else if (answer == 2) + { + // error code + getErrorCode(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error code:")); + USB.println((char*)_buffer); + #endif + return 1; + } + + // Second attempt + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 1000); + + if (answer == 1) + { + // ok + return 0; + } + else if (answer == 2) + { + // error code + getErrorCode(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error code:")); + USB.println((char*)_buffer); + #endif + return 1; + } + else + { + return 2; + } +} + + + +/* Function: This function requests the current working directory in FTP server + * + * Return: '0' if OK + * 'x' otherwise + */ +uint8_t Wasp4G::ftpGetWorkingDirectory() +{ + uint8_t answer; + char command_buffer[100]; + char* pointer; + + // AT#FTPPWD\r + memset(command_buffer, 0x00, sizeof(command_buffer)); + strcpy_P(command_buffer,(char*)pgm_read_word(&(table_FTP[15]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error showing Working Directory\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + // parse response similar to: "\r\n#FTPPWD: 257 "/""\r\n + // so the working directory is in the second token: + answer = parseString(_ftpWorkingDirectory, sizeof(_ftpWorkingDirectory), "\"", 2); + + if (answer != 0) + { + return 2; + } + + return 0; +} + + + + +/* Function: This function changes the working directory of the FTP session + * Parameters: dirname: destiny directory in FTP server + * Return: '0' if OK + * 'x' otherwise + */ +uint8_t Wasp4G::ftpChangeWorkingDirectory(char* dirname) +{ + uint8_t answer; + char command_buffer[100]; + + // AT#FTPCWD="dirname"\r + memset(command_buffer, 0x00, sizeof(command_buffer)); + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_FTP[17])), dirname); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error changing Working Directory\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + // update attribute if OK + memset(_ftpWorkingDirectory, 0x00, sizeof(_ftpWorkingDirectory)); + strncpy(_ftpWorkingDirectory, "/", 1); + strncat(_ftpWorkingDirectory, dirname, sizeof(_ftpWorkingDirectory)-2); + + return 0; +} + + +/* Function: This function uses DELETE to delete a file to in the current + * working directory of the FTP server + * Parameters: ftp_file: file to delete in FTP session + * Return: '0' if OK + * 'x' otherwise + */ +uint8_t Wasp4G::ftpDelete(char* ftp_file) +{ + uint8_t answer; + char command_buffer[100]; + + // AT#FTPDELE=""\r + memset(command_buffer, 0x00, sizeof(command_buffer)); + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_FTP[14])),ftp_file); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_buffer:")); + USB.println((char*)_buffer); + #endif + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error deleting file\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + return 0; +} + + +/* Function: This function uses PUT to send a file to a FTP server + * Parameters: ftp_file: destiny file + * sd_file: origin file + * Return: 0 if OK + * 1 if no SD present + * 2 if file does not exist + * 3 if error opening the file + * 4 if error setting the pointer of the file + * 5 if error getting the file size + * 6 if error opening the PUT connection + * 7 if error exiting from the data mode + * 8 if error sending data + */ +uint8_t Wasp4G::ftpUpload( char* ftp_file, char* sd_file) +{ + + uint8_t answer; + char command_answer[20]; + char command_buffer[512]; + int32_t file_size = 0; + int nBytes = 0; + uint8_t error_counter = 5; + + //// 1. Delete file in FTP server if exists + ftpDelete(ftp_file); + + // define file variable + SdFile file; + + // get current state of SD card power supply + bool sd_state = SPI.isSD; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: SD not present\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + return 1; + } + + // Delete file in the case it exists + if (!SD.isFile(sd_file)) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: file does not exist\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + return 2; + } + + // search file in current working directory and open it + // exit if error and modify the general flag with FILE_OPEN_ERROR + if (!SD.openFile((char*)sd_file, &file, O_RDONLY)) + { + // SD error + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: opening file\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + return 3; + } + + // set pointer to the beginning of the file + if (!file.seekSet(0)) + { + // SD error + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: setting initial offset in file\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + return 4; + } + + // get file size + file_size = SD.getFileSize(sd_file); + if (file_size < 0) + { + // Return the SD to the original state + if (sd_state == 0) + { + SD.OFF(); + } + + return 5; + } + + // mandatory delay so the module works ok + delay(1000); + + // 5. Open the PUT connection + // AT#FTPPUT=,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_FTP[2])), ftp_file); + + // send command + answer = sendCommand(command_buffer, "CONNECT", "NO CARRIER", 15000); + if (answer != 1) + { + // Close file + file.close(); + + // Return the SD to the original state + if (sd_state == 0) + { + SD.OFF(); + } + + return 6; + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("File size: ")); + USB.println(file_size, DEC); + PRINT_LE910(F("error_counter: ")); + USB.println(error_counter, DEC); + #endif + + // 6. Send data to the server + while ((file_size > 0) && (error_counter > 0)) + { + // 6a. Read data from SD + nBytes = file.read(command_buffer, 500); + + // 6b. Send the data if no errors + if (nBytes == -1) + { + // SD error + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error reading the file\n")); + #endif + error_counter--; + } + else + { + for (int i = 0; i < nBytes; i++) + { + printByte(command_buffer[i], 1); + } + + file_size -= nBytes; + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Remains: ")); + USB.print(file_size); + USB.println(F("Bytes")); + #endif + } + + // 7. Close file + file.close(); + + // 8. Return the SD to the original state + if (sd_state == 0) + { + SD.OFF(); + } + + // 9. Exit from data mode + delay(1000); + + // "+++" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_FTP[11]))); + // "NO CARRIER" + strcpy_P(command_answer, (char*)pgm_read_word(&(table_FTP[12]))); + + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, 15000); + if (answer != 1) + { + return 7; + } + + if (error_counter == 0) + { + return 8; + } + + return 0; +} + + + +/* Function: This function uses GET to read a file from a FTP server + * Parameters: sd_file: destiny file + * ftp_file: origin file + * Return: '0' if OK + * 'x' if error + */ +uint8_t Wasp4G::ftpDownload( char* sd_file, char* ftp_file) +{ + uint8_t error; + uint8_t answer; + char command_buffer[50]; + char command_answer[50]; + bool sd_state; + uint32_t server_filesize = 0; + uint32_t sd_filesize = 0; + int32_t packet_size = LE910_MAX_DL_PAYLOAD; + int nBytes = 0; + uint8_t error_counter = 5; + int data_available; + uint32_t prev; + + // init error code variable + _errorCode = 0; + + delay(2000); + + /// 1. Get filesize in FTP server + error = ftpFileSize(ftp_file); + + if (error == 0) + { + server_filesize = _filesize; + + if (server_filesize == 0) + { + USB.println(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Server file size is zero\n")); + #endif + return 1; + } + + + if (server_filesize < LE910_MAX_DL_PAYLOAD) + { + packet_size = server_filesize; + } + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error retrieving file size\n")); + #endif + return 2; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("File size in FTP: ")); + USB.println(server_filesize, DEC); + #endif + + + + /// 2. Prepare SD card for downloading + + // define file variable + SdFile file; + + // get current state of SD card power supply + sd_state = SPI.isSD; + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("SD not present\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + return 3; + } + + // Delete file in the case it exists + if (SD.isFile(sd_file) == 1) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("delete file\n")); + #endif + SD.del(sd_file); + } + + // Creates a file in that folder + if (!SD.create(sd_file)) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("file not created\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + + return 4; + } + + // search file in current directory and open it in write mode + if (!SD.openFile(sd_file, &file, O_READ | O_WRITE | O_SYNC)) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("error opening file\n")); + #endif + if (sd_state == false) + { + SD.OFF(); + } + + return 5; + } + + // select correct SPI slave for the rest of the function + SPI.setSPISlave(SD_SELECT); + + // jump over zero 'offset' + if (!file.seekSet(0)) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("setting file offset\n")); + #endif + file.close(); + if (sd_state == false) + { + SD.OFF(); + } + + return 6; + } + + /// 3. Open the GET connection + + // AT#FTPGETPKT=""\r + memset(command_buffer,0x00,sizeof(command_buffer)); + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_FTP[3])),ftp_file); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, LE910_FTP_TIMEOUT); + + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + + // Close file + file.close(); + + // Return the SD to the original state + if (sd_state == 0) + { + SD.OFF(); + } + + return 7; + } + + // calculate delay for retrieving packets depending on file size + uint32_t delay_ms; + + if (_filesize > 50000) + { + delay_ms = 700; + } + else if (_filesize > 25000) + { + delay_ms = _filesize/100; + } + else + { + delay_ms = _filesize/160; + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Set delay_ms = ")); + USB.println(delay_ms); + #endif + + setDelay(delay_ms); + + // Note: Please commnent this line if your SIM card does not + // permit good data transmission + setDelay(0); + + delay(500); + + // "#FTPRECV: " + sprintf_P(command_answer, (char*)pgm_read_word(&(table_FTP[13]))); + + /// 4. Read data from the module + while ((server_filesize > 0) && (error_counter > 0)) + { + if (server_filesize > LE910_MAX_DL_PAYLOAD) + { + packet_size = LE910_MAX_DL_PAYLOAD; + } + else + { + packet_size = server_filesize; + } + + //// 6b Request data + // AT#FTPRECV=\r + memset(command_buffer, 0x00, sizeof(command_buffer)); + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_FTP[6])),packet_size); + + // send command + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, LE910_ERROR, 2000); + + if (answer == 2) + { + getErrorCode(); + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + setDelay(DEF_COMMAND_DELAY); + return 8; + } + else if (answer != 1) + { + error_counter--; + // Error could be that no data in the buffer, wait one second + delay(1000); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting data\n")); + #endif + } + else + { + //// 6c Read the number of bytes of the packet + waitFor("\r\n", 100); + error = parseInt32(&packet_size,"\r\n"); + + if (error == 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting packet size\n")); + #endif + file.close(); + + if (sd_state == false) + { + SD.OFF(); + } + setDelay(DEF_COMMAND_DELAY); + return 9; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Packet size: ")); + USB.println(packet_size); + #endif + + // Read the data from the UART and stores in _buffer + nBytes = readBuffer(packet_size); + + if (nBytes != packet_size) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error in packet size mismatch\n")); + #endif + file.close(); + + if (sd_state == false) + { + SD.OFF(); + } + setDelay(DEF_COMMAND_DELAY); + return 10; + } + + // Write the data into the SD + if (file.write(_buffer, nBytes) != (int)nBytes) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Writing SD error")); + #endif + file.close(); + + if (sd_state == false) + { + SD.OFF(); + } + setDelay(DEF_COMMAND_DELAY); + return 11; + } + + // decrement filesize + server_filesize -= nBytes; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Remaining server_filesize: ")); + USB.println(server_filesize); + #endif + } + } + + // Close file + file.close(); + + // check error counter + if (error_counter == 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error counter=0\n")); + #endif + return 12; + } + + // save the actual server file size + server_filesize = _filesize; + + // update file size in SD card + sd_filesize = SD.getFileSize(sd_file); + + // check size mismatch + if (sd_filesize != server_filesize) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("File size mismatch\n")); + PRINT_LE910(F("sd_filesize:")); + USB.println(sd_filesize); + PRINT_LE910(F("server_filesize:")); + USB.println(server_filesize); + #endif + setDelay(DEF_COMMAND_DELAY); + return 13; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("DOWNLOAD OK\n")); + PRINT_LE910(F("sd_filesize:")); + USB.println(sd_filesize,DEC); + PRINT_LE910(F("server_filesize:")); + USB.println(server_filesize,DEC); + #endif + + + // 8. Return the SD to the original state + if (sd_state == false) + { + SD.OFF(); + } + + setDelay(DEF_COMMAND_DELAY); + + return 0; +} + + + + +/* Function: This function configures and open a socket + * Parameters: socketId: number of the socket Id + * protocol: 0 for TCP and 1 for UDP + * remote_IP: address of the remote host (IPv6 allowed) + * remote_port: remote host port to contact + * Return: 0 if OK; 'x' if error (see below) + */ +uint8_t Wasp4G::openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port) +{ + return openSocketClient(socketId, + protocol, + remote_IP, + remote_port, + 0, + 0); +} + +/* Function: This function configures and opens a socket + * Parameters: socketId: number of the socket Id + * protocol: 0 for TCP and 1 for UDP + * remote_IP: address of the remote host (IPv6 allowed) + * remote_port: remote host port to contact + * local_port: UDP connections local port + * Return: 0 if OK; 'x' if error (see below) + */ +uint8_t Wasp4G::openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port, + uint16_t local_port) +{ + return openSocketClient(socketId, + protocol, + remote_IP, + remote_port, + local_port, + 0); +} + + +/* Function: This function configures and opens a socket + * Parameters: socketId: number of the socket Id (from 1 to 6) + * protocol: 0 for TCP and 1 for UDP + * remote_IP: address of the remote host (IPv6 allowed) + * remote_port: remote host port to contact + * local_port: UDP connections local port + * keep_alive: From 0 (disabled) to 240 minutes + * Return: + * 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + * 16 error getting socket status + * 17 Socket with an active data transfer connection + * 18 Socket suspended + * 19 Socket suspended with pending data + * 20 Socket listening + * 21 Socket with an incoming connection. Waiting for the user accept or shutdown command + * 22 Socket in opening process. The socket is not in Closed state but + * still not in Active or Suspended or Suspended with pending data state + * 23 if error in Socket Configuration + * 24 if error in Socket Configuration Extended 3 + * 25 if error sending the open command + * 26 if timeout opening the socket + */ +uint8_t Wasp4G::openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port, + uint16_t local_port, + uint8_t keep_alive) +{ + uint8_t error; + uint8_t answer; + char command_buffer[100]; + + + //// 1. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking data connection\n")); + #endif + return answer; // 1 to 15 error codes + } + + + //// 2. Check socket status + answer = getSocketStatus(socketId); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking socket status\n")); + #endif + return 16; + } + + // check if socket is not closed before opening it and return error code + if (socketStatus[socketId].state != 0) + { + return socketStatus[socketId].state+16; // 17 to 22 error codes + } + + + //// 3. Socket Configuration Extended + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Configuring connection\n")); + #endif + + + // AT#SCFGEXT=,0,0,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[3])), + socketId+1, + 0, + 0, + keep_alive); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + return 23; + } + + + //// 4. Socket Configuration Extended 3 + // AT#SCFGEXT3=,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[5])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 24; + } + + + //// 5. Socket Dial + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Opening the socket\n")); + #endif + + if (local_port == 0) + { + local_port = remote_port; + } + + // AT#SD=,,,"",0,,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[6])), + socketId+1, + protocol, + remote_port, + remote_IP, + local_port); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 25; + } + + + //// 6. Wait for opening the socket + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatus(socketId); + + if (answer == 0) + { + if (socketStatus[socketId].state == 2) + { + // Socket suspended + return 0; + } + else if (socketStatus[socketId].state == 3) + { + // Socket suspended with pending data + return 0; + } + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while (((millis() - previous) < LE910_IP_TIMEOUT)); + + + return 26; +} + + + + + +/* Function: This function opens a socket listening for an incoming + * connection on a specified port + * Parameters: socketId: number of the socket Id (from 1 to 6) + * protocol: 0 for TCP_SERVER and 1 for UDP_SERVER + * local_port: TCP/UDP local port + * Return: '0' if OK; 'x' if error + */ +uint8_t Wasp4G::openSocketServer(uint8_t socketId, + bool protocol, + uint16_t local_port) +{ + return openSocketServer(socketId, protocol, local_port, 0); +} + + +/* Function: This function opens a socket listening for an incoming + * connection on a specified port + * Parameters: socketId: number of the socket Id (from 1 to 6) + * protocol: 0 for TCP_SERVER and 1 for UDP_SERVER + * local_port: TCP/UDP local port + * keep_alive: From 0 (disabled) to 240 minutes + * Return: '0' if OK; 'x' if error + */ +uint8_t Wasp4G::openSocketServer(uint8_t socketId, + bool protocol, + uint16_t local_port, + uint8_t keep_alive) +{ + uint8_t error; + uint8_t answer; + char command_buffer[100]; + + + //// 1. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking data connection\n")); + #endif + return answer; // 1 to 15 error codes + } + + + //// 2. Check socket status + answer = getSocketStatus(socketId); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking socket status\n")); + #endif + return 16; + } + + //// 3. Socket Configuration Extended + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Configuring connection\n")); + #endif + + // AT#SCFGEXT=,0,0,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[3])), + socketId+1, + 0, + 0, + keep_alive); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + + return 17; + } + + + //// 4. Socket Listen TCP / Socket Listen UDP + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Opening the socket listen\n")); + #endif + + if (protocol == Wasp4G::TCP) + { + // AT#SL=,1,,255\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[29])), + socketId+1, + 1, + local_port, + 255); + } + else if (protocol == Wasp4G::UDP) + { + // AT#SLUDP=,1,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[30])), + socketId+1, + 1, + local_port); + } + else + { + return 18; + } + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 19; + } + + return 0; +} + + + + + +/* Function: This function configures and opens a socket SSL + * Parameters: + * socketId: Secure Socket Identifier (must be 1 because until now SSL block manage only 1 socket) + * remote_IP: address of the remote host (IPv6 allowed) + * remote_port: remote host port to contact + * Return: + * 0 if OK + * 1 not registered, ME is not currently searching for a new operator to register to + * 2 not registered, but ME is currently searching for a new operator to register to + * 3 registration denied + * 4 unknown + * 6 not registered, ME is not currently searching for a new operator to register to + * 8 not registered, but ME is currently searching for a new operator to register to + * 9 registration denied + * 10 unknown + * 12 if error setting APN + * 13 if error setting login + * 14 if error setting password + * 15 if error activating GPRS connection + * 16 Socket with an active data transfer connection + * 17 Socket suspended + * 18 Socket suspended with pending data + * 19 Socket listening + * 20 Socket with an incoming connection. Waiting for the user accept or shutdown command + * 21 Socket in opening process. The socket is not in Closed state but + * still not in Active or Suspended or Suspended with pending data state + * 22 if error reading the status of the socket + * 23 if error configuring of the socket + * 24 if error configuring of the socket + * 25 if error sending the open command + * 26 if timeout opening the socket + * 27 if timeout opening the socket + */ +uint8_t Wasp4G::openSocketSSL( uint8_t socketId, + char* remote_IP, + uint16_t remote_port) +{ + uint8_t answer; + char command_buffer[100]; + + + //// 1. Enable a SSL socket + // "AT#SSLEN=,1\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[33])), socketId+1, 1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check response + // If the socket has already been enabled for SSL, + // the module returns error, so we continue if error + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + } + + + //// 2. Check data connection + answer = checkDataConnection(60); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error in checkDataConnection()\n")); + #endif + return answer; // 1 to 15 error codes + } + + + //// 3. Check socket status + answer = getSocketStatusSSL(socketId); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error in getSocketStatusSSL()\n")); + #endif + return 16; + } + + // check if socket is not closed before opening it and return error code + // available values are: + // 0: Socket Disabled + // 1: Connection closed + // 2: Connection open + if (socketStatusSSL[socketId].state != 1) + { + return socketStatusSSL[socketId].state+17; // 17 to 19 error codes + } + + + //// 4. Socket Dial + // AT#SSLD=1,,"",0,1\r + sprintf_P(command_buffer, + (char*)pgm_read_word(&(table_IP[12])), + remote_port, + remote_IP); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 15000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 20; + } + + + //// 5. Wait for opening the socket + // available values are: + // 0: Socket Disabled + // 1: Connection closed + // 2: Connection open + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatusSSL(socketId); + + if (answer == 0) + { + if (socketStatusSSL[socketId].state == 2) + { + // Socket suspended + return 0; + } + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while (((millis() - previous) < LE910_IP_TIMEOUT)); + + + return 21; + +} + + +/* Function: This function closes a socket previously opened + * Parameters: socketId: number of the socket Id + * Return: 0 Socket Closed + * 1 if error sending the command + * 2 if timeout shutting down the socket + */ +uint8_t Wasp4G::closeSocketClient(uint8_t socketId) +{ + uint8_t answer; + char command_buffer[10]; + + //// 1. Check socket status + answer = getSocketStatus(socketId); + + if ((answer == 0) && (socketStatus[socketId].state == 0)) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket status: closed\n")); + #endif + return 0; + } + + + //// 2. Configure connection + // AT#SH=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[7])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error closing connection\n")); + #endif + return 1; + } + + + //// 3. Wait the shutdown of the socket + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatus(socketId); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 2; + } + + if (socketStatus[socketId].state == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket closed\n")); + #endif + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while ((millis() - previous) < LE910_IP_TIMEOUT); + + + return 3; +} + + + +/* Function: This function closes a socket previously opened + * Parameters: socketId: number of the socket Id + * Return: 0 Socket Closed + * 1 if error sending the command + * 2 if timeout shutting down the socket + */ +uint8_t Wasp4G::closeSocketServer(uint8_t socketId, uint8_t protocol) +{ + uint8_t answer; + char command_buffer[10]; + + //// 1. Check socket status + answer = getSocketStatus(socketId); + + if ((answer == 0) && (socketStatus[socketId].state == 0)) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket status: closed\n")); + #endif + return 0; + } + + + //// 2. Close socket listening + if (protocol == Wasp4G::TCP) + { + // AT#SL=,0,,255\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[29])), + socketId+1, + 0, + socketStatus[socketId].localPort, + 255); + } + else if (protocol == Wasp4G::UDP) + { + // AT#SLUDP=,0,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[30])), + socketId+1, + 0, + socketStatus[socketId].localPort); + } + else + { + return 1; + } + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + + #if DEBUG_WASP4G > 0 + printErrorCode(); + #endif + } + return 1; + } + + + //// 3. Configure connection + // AT#SH=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[7])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error closing connection\n")); + #endif + return 1; + } + + + //// 3. Wait the shutdown of the socket + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatus(socketId); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 2; + } + + if (socketStatus[socketId].state == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket closed\n")); + #endif + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while ((millis() - previous) < LE910_IP_TIMEOUT); + + + return 1; +} + + + + +/* Function: This function closes a socket previously opened + * Parameters: socketId: number of the socket Id + * Return: 0 Socket Closed + * 1 if error sending the command + * 2 if timeout shutting down the socket + */ +uint8_t Wasp4G::closeSocketSSL(uint8_t socketId) +{ + uint8_t answer; + char command_buffer[10]; + + //// 1. Check socket status + answer = getSocketStatusSSL(socketId); + + if ((answer == 0) && (socketStatusSSL[socketId].state == 1)) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket status: closed\n")); + #endif + return 0; + } + + + //// 2. Configure connection + // AT#SSLH=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[19])), socketId+1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error closing connection\n")); + #endif + return 1; + } + + + //// 3. Wait the shutdown of the socket + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatusSSL(socketId); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 2; + } + + if (socketStatusSSL[socketId].state == 1) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Socket closed\n")); + #endif + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while ((millis() - previous) < LE910_IP_TIMEOUT); + + + return 3; +} + + + +/* Function: This function sends data through a socket previously opened + * Parameters: socketId: number of the socket Id + * data: string with the data + * Return: '0' if OK; 'x' if error + */ +uint8_t Wasp4G::send(uint8_t socketId, char* data) +{ + return send(socketId, (uint8_t*)data, strlen(data)); +} + + +/* Function: This function sends data through a socket previously opened + * Parameters: socketId: number of the socket Id + * data: buffer with the data + * data_length: length of the data buffer + * Return: 0 if OK, 'x' error + */ +uint8_t Wasp4G::send(uint8_t socketId, + uint8_t* data, + uint16_t data_length) +{ + uint8_t answer; + char command_buffer[25]; + + //// 1. Check socket status + answer = getSocketStatus(socketId); + + // check answer error + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking socket status\n")); + #endif + return 1; + } + + // check correct socket status + if ((socketStatus[socketId].state != 1) && + (socketStatus[socketId].state != 2) && + (socketStatus[socketId].state != 3)) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Incorrect socket status\n")); + #endif + return 2; + } + + + //// 2. Send data + // AT#SSENDEXT=,\r + sprintf_P(command_buffer, + (char*)pgm_read_word(&(table_IP[8])), + socketId+1, + data_length); + + // send command + answer = sendCommand(command_buffer, ">", LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if(answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error sending data\n")); + #endif + return 3; + } + + // send array of data + for (int i = 0; i < data_length; i++) + { + printByte(data[i], 1); + } + + // wait for "OK" + answer = waitFor(LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error waiting OK\n")); + #endif + return 4; + } + + + //// 3. Wait that all data have been sent + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatus(socketId); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 5; + } + + if (socketStatus[socketId].state == 2) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Data sent\n")); + #endif + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while ((millis() - previous) < LE910_IP_TIMEOUT); + + + return 6; +} + + + + + + +/* Function: This function sends data through a socket previously opened + * Parameters: socketId: number of the socket Id + * data: string with the data + * Return: 0 if OK + * 1 if error with the socket + * 2 if error sending the command + * 3 if error sending the command + * 4 if timeout shutting down the socket + */ +uint8_t Wasp4G::sendSSL(uint8_t socketId, char* data) +{ + return sendSSL(socketId, (uint8_t*)data, strlen(data)); +} + +/* Function: This function sends data through a socket previously opened + * Parameters: socketId: number of the socket Id + * data: buffer with the data + * data_length: length of the data buffer + * Return: 0 if OK, 'x' error + */ +uint8_t Wasp4G::sendSSL(uint8_t socketId, + uint8_t* data, + uint16_t data_length) +{ + uint8_t answer; + char command_buffer[25]; + + //// 1. Check socket status + answer = getSocketStatusSSL(socketId); + + // check answer error + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error checking socket status\n")); + #endif + return 1; + } + + // check correct socket status + if (socketStatusSSL[socketId].state != 2) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Socket status incorrect\n")); + #endif + return 2; + } + + + //// 2. Send data + // AT#SSLSEND=\r + sprintf_P(command_buffer, + (char*)pgm_read_word(&(table_IP[14])), + socketId+1, + data_length); + + // send command + answer = sendCommand(command_buffer, ">", LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error sending data\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + } + return 3; + } + + // send array of data + for (int i = 0; i < data_length; i++) + { + printByte(data[i], 1); + } + // send 0x1A to complete the operation + printByte(0x1A, 1); + + // wait for "OK" + answer = waitFor(LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check answer + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error waiting OK\n")); + #endif + + if (answer == 2) + { + getErrorCode(); + } + return 4; + } + + + //// 3. Wait that all data have been sent + uint32_t previous = millis(); + + do + { + // get socket status + answer = getSocketStatusSSL(socketId); + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket status\n")); + #endif + return 5; + } + + if (socketStatusSSL[socketId].state == 2) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Data sent\n")); + #endif + + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + delay(1000); + + } while ((millis() - previous) < LE910_IP_TIMEOUT); + + + return 6; +} + + +/* Function: This function read data received in the module + * Parameters: socketId: number of the socket Id + * Return: '0' if OK; 'x' if error + * + */ +uint8_t Wasp4G::receive(uint8_t socketId) +{ + return receive(socketId, 0); +} + +/* Function: This function read data received in the module + * Parameters: socketId: number of the socket Id + * timeout: number of ms to wait for incoming bytes + * Return: '0' if OK; 'x' if error + */ +uint8_t Wasp4G::receive(uint8_t socketId, uint32_t timeout) +{ + uint8_t answer; + int incoming_bytes; + char command_buffer[25]; + char command_answer[25]; + uint32_t nBytes = 0; + uint32_t readBufferBytes = 0; + uint32_t previous; + + previous = millis(); + + //// 1. Get socket pending bytes to be read for specified 'timeout' in the + // case the timeout is zero, do it once + do + { + // get socket info + answer = getSocketInfo(socketId); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting socket info\n")); + #endif + return 2; + } + + if (socketInfo[socketId].size > 0) + { + break; + } + + if (timeout == NULL) + { + return 1; + } + + delay(500); + } + while (millis()-previous < timeout); + + if (socketInfo[socketId].size == 0) + { + return 3; + } + + // get number of pending bytes to be read in socket + incoming_bytes = socketInfo[socketId].size; + + + //// 2. Send command to read received data and save it + // generate the expected response + // AT#SRECV: , + sprintf_P(command_answer,(char*)pgm_read_word(&(table_IP[9])), socketId+1); + + // generate command + // AT#SRECV=,\r + sprintf_P(command_buffer,(char*)pgm_read_word(&(table_IP[26])), + socketId+1, + LE910_MAX_DL_PAYLOAD); + + // send command + answer = sendCommand(command_buffer, command_answer, 2000); + + // check answer + if (answer == 1) + { + // wait for end of response "\r\n" + answer = waitFor("\r\n", 1000); + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error waiting EOL\n")); + #endif + return 4; + } + + // parse + answer = parseUint32(&nBytes, " \r\n"); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error parsing nBytes\n")); + #endif + return 5; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("nBytes:")); + USB.println(nBytes, DEC); + #endif + + // wait for number of bytes in data received + readBufferBytes = readBuffer(nBytes); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("readBufferBytes:")); + USB.println(readBufferBytes, DEC); + #endif + + if (readBufferBytes != nBytes) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting received bytes\n")); + #endif + return 6; + } + } + + // update attribute length + _length = nBytes; + + return 0; +} + + + + +/* Function: This function read data received in the module + * Parameters: socketId: number of the socket Id + * Return: '0' if ok; 'x' if error + */ +uint8_t Wasp4G::receiveSSL(uint8_t socketId) +{ + return receiveSSL(socketId, 0); +} + +/* Function: This function read data received in the module + * Parameters: socketId: number of the socket Id + * timeout: number of ms to wait for incoming bytes + * Return: '0' if ok; 'x' if error + */ +uint8_t Wasp4G::receiveSSL(uint8_t socketId, uint32_t timeout) +{ + uint8_t answer; + char command_buffer[50]; + char answer1[25]; + char answer2[25]; + char answer3[25]; + uint32_t nBytes = 0; + uint32_t readBufferBytes = 0; + uint32_t previous; + + // get current execution time + previous = millis(); + + // generate command + // AT#SSLRECV=,\r + sprintf_P(command_buffer, + (char*)pgm_read_word(&(table_IP[15])), + socketId+1, + LE910_MAX_DL_PAYLOAD); + + // Generate answers + strcpy_P(answer1, (char*)pgm_read_word(&(table_IP[16]))); //"#SSLRECV: " + strcpy_P(answer2, (char*)pgm_read_word(&(table_IP[17]))); //"TIMEOUT\r\n" + strcpy_P(answer3, (char*)pgm_read_word(&(table_IP[18]))); //"DISCONNECTED\r\n" + + + //// 1. Send command to read received data and save it + do + { + // send command to read data from SSL socket + answer = sendCommand(command_buffer, answer1, answer2, answer3, LE910_ERROR_CODE, 5000); + + // check timeout with no answer + if (answer == 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("No answer from module\n")); + #endif + return 1; + } + + // check OK response with incoming data, then break + if (answer == 1) + { + break; + } + + // check OK response with incoming data, then break + if (answer == 3) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("SSL Socket DISCONNECTED\n")); + #endif + return 2; + } + + // check error code + if (answer == 4) + { + getErrorCode(); + return 3; + } + + delay(500); + } + while ((millis()-previous < timeout)); + + + //// 2. If bytes have been received, then proceed to read them + if (answer == 1) + { + // wait for end of response "\r\n" + answer = waitFor("\r\n", 1000); + + if (answer != 1) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error waiting EOL\n")); + #endif + return 4; + } + + // parse + answer = parseUint32(&nBytes, " \r\n"); + + if (answer != 0) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error parsing nBytes\n")); + #endif + return 5; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("nBytes:")); + USB.println(nBytes, DEC); + #endif + + // wait for number of bytes in data received + readBufferBytes = readBuffer(nBytes); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("readBufferBytes:")); + USB.println(readBufferBytes, DEC); + #endif + + if (readBufferBytes != nBytes) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting received bytes\n")); + #endif + return 6; + } + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error waiting LE910_OK\n")); + #endif + return 7; + } + + // update attribute length + _length = nBytes; + + return 0; +} + + + +/* Function: This function allows to store, delete and read security data + * (Certificate, CAcertificate, private key) into the non-volatile + * memory of the module + * + * Parameters: socketId: Secure Socket Identifier (must be 1) + * action: Action to do: + * 0 – Delete data from NVM + * 1 – Store data into NVM + * 2 – Read data from NVM + * dataType: + * 0 – Certificate + * 1 – CA certificate + * 2 – RSA Private key + * data: string with the security data + * + * Return: 0 if OK; 'x' if error + */ +uint8_t Wasp4G::manageSSL( uint8_t socketId, + uint8_t action, + uint8_t dataType) +{ + return manageSSL(socketId, action, dataType, NULL); +} + + +/* Function: This function allows to store, delete and read security data + * (Certificate, CAcertificate, private key) into the non-volatile + * memory of the module + * + * Parameters: socketId: Secure Socket Identifier (must be 1) + * action: Action to do: + * 0 – Delete data from NVM + * 1 – Store data into NVM + * 2 – Read data from NVM + * dataType: + * 0 – Certificate + * 1 – CA certificate + * 2 – RSA Private key + * data: string with the security data + * + * Return: 0 if OK; 'x' if error + */ +uint8_t Wasp4G::manageSSL( uint8_t socketId, + uint8_t action, + uint8_t dataType, + char *data) +{ + uint8_t answer; + char command_buffer[50]; + char command_answer[50]; + + // clear buffers + memset(command_buffer,0x00,sizeof(command_buffer)); + memset(command_answer,0x00,sizeof(command_answer)); + + + //// 1. Enable a SSL socket + // "AT#SSLEN=,1\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[33])), socketId+1, 1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check response + // If the socket has already been enabled for SSL, + // the module returns error, so we continue if error + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + } + + + //// 2. Set SSL settings + if ((action == Wasp4G::SSL_ACTION_STORE) && (data != NULL)) + { + // AT#SSLSECDATA=,,,\r + sprintf_P( command_buffer, + (char*)pgm_read_word(&(table_IP[10])), + socketId+1, + action, + dataType, + strlen(data)); + + // send command + answer = sendCommand(command_buffer, ">", LE910_ERROR_CODE, LE910_ERROR); + + // check response + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // send certificate data + printString(data, 1); + printByte(0x1A, 1); + + waitFor(LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + + // check response + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 2; + } + + return 0; + } + else if (action == Wasp4G::SSL_ACTION_READ) + { + // command_buffer <-- AT#SSLSECDATA=,,\r + sprintf_P( command_buffer, + (char*)pgm_read_word(&(table_IP[11])), + socketId+1, + action, + dataType); + + // command_answer <-- "#SSLSECDATA: " + strcpy_P( command_answer, (char*)pgm_read_word(&(table_IP[27]))); + + // send command + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, LE910_ERROR); + + // check response + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 3; + } + + waitFor("\r\n"); + waitFor(LE910_OK); + + return 0; + + } + else if (action == Wasp4G::SSL_ACTION_DELETE) + { + // AT#SSLSECDATA=,,\r + sprintf_P( command_buffer, + (char*)pgm_read_word(&(table_IP[11])), + socketId+1, + action, + dataType); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + + // check response + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 4; + } + + return 0; + } + + return 5; +} + + + +/* Function: Starts the GPS engine with hot start and stand alone mode + * Parameters: + * reset_mode: + * 1 Coldstart + * 2 Warmstart + * 3 Hotstart + * gps_mode: + * 0: Pure MS Assisted - Location estimate from the network (MS Assisted mode). + * 1: MS Based - Assistance Data from the network (MS Based mode). + * 2: MS Assisted Based - Combination of MS-A and MS-B modes, location + * estimate computed both at UE and Network. + * 3: Autonomous – Autonomous GPS mode of operation. + * + * Return: 0 if OK + * 1 if GPS is powered yet + * 2 if error setting the reset mode + * 3 if error starting the GPS engine + */ +uint8_t Wasp4G::gpsStart() +{ + return gpsStart(Wasp4G::GPS_AUTONOMOUS, 3); +} + + +/* Function: Starts the GPS engine with the reset and location mode desired + * Parameters: + * reset_mode: + * 1 Coldstart + * 2 Warmstart + * 3 Hotstart + * gps_mode: + * 0: Pure MS Assisted - Location estimate from the network (MS Assisted mode). + * 1: MS Based - Assistance Data from the network (MS Based mode). + * 2: MS Assisted Based - Combination of MS-A and MS-B modes, location + * estimate computed both at UE and Network. + * 3: Autonomous – Autonomous GPS mode of operation. + * + * Return: 0 if OK + * 1 if GPS is powered yet + * 2 if error setting the reset mode + * 3 if error starting the GPS engine + */ +uint8_t Wasp4G::gpsStart(uint8_t gps_mode) +{ + return gpsStart(gps_mode,3); +} + + +/* Function: Starts the GPS engine with the reset and location mode desired + * Parameters: + * reset_mode: + * 1 Coldstart + * 2 Warmstart + * 3 Hotstart + * gps_mode: + * 0: Pure MS Assisted - Location estimate from the network (MS Assisted mode). + * 1: MS Based - Assistance Data from the network (MS Based mode). + * 2: MS Assisted Based - Combination of MS-A and MS-B modes, location + * estimate computed both at UE and Network. + * 3: Autonomous – Autonomous GPS mode of operation. + * + * Return: 0 if OK; 'x' if error + */ +uint8_t Wasp4G::gpsStart(uint8_t gps_mode, uint8_t reset_mode) +{ + uint8_t answer; + char command_buffer[50]; + char command_answer[10]; + + //// 1. Set reset mode + // AT$GPSR=\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[2])), reset_mode); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + + //// 2. Check if the GPS engine is powered on + //// In that case, we return OK; if not we start the gps power + // AT$GPSP?\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_GPS[13]))); + + // Generate answer to be parsed + // "GPSP: 1" + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[14]))); + + // send command + answer = sendCommand(command_buffer, command_answer, LE910_ERROR_CODE, LE910_ERROR, 1000); + + // check answer + if (answer == 1) + { + return 0; + } + else if ((answer == 2) || (answer == 3)) + { + if (answer == 2) + { + getErrorCode(); + } + return 2; + } + + + //// 3. Switch GPS to on + // Send corresponding command depending on gps mode + if (gps_mode == Wasp4G::GPS_AUTONOMOUS) + { + //// GPS Power Management: GPS controller is powered up + // "AT$GPSP=1\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[0])), 1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 1000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 3; + } + + // return OK + return 0; + } + else if ((gps_mode == Wasp4G::GPS_MS_ASSISTED) || (gps_mode == Wasp4G::GPS_MS_BASED)) + { + //// 4. setup NETWORK_UTRAN + answer = setWirelessNetwork(Wasp4G::NETWORK_UTRAN); + if (answer != 0) + { + return 4; + } + + //// 5. Define PDP Context + // AT+CGDCONT=1,"IP",""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[29])), _apn); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + return 5; + } + + //// 6. Set Authentication User ID + // AT#USERID=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[5])), _apn_login); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + return 6; + } + + //// 7. Set Authentication Password + // AT#PASSW=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[6])), _apn_password); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 5000); + if (answer != 1) + { + return 7; + } + + //// 8. + // AT#SCFG=1,1,300,90,600,50\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_IP[2])), 1, 1, 300, 90, 600, 50); + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 8; + } + + //// 9. Set QoS for GPS: + // horiz_accuracy = 5 + // vertic_accuracy = 5 + // rsp_time = 100 + // age_of_location_info = 0 + // location_type = 0 (current location) + // nav_profile = 0 Car navigation profile (default) + // velocity_request = TRUE + answer = gpsSetQualityOfService(5, 5, 100, 0, 0, 0, 1); + + if (answer != 0) + { + return 9; + } + + //// 10. Set SLP server + // AT$SLP=1,"supl.nokia.com:7275"\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[21]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 10; + } + + //// 11. Set the version of supported SUPL + // AT$SUPLV=%u\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[20])), 1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 1000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 11; + } + + //// 12. Update terminal information + // AT$LCSTER=1,,,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[22]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 12; + } + + //// 13. Enable unsolicited response + // AT$LICLS=1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[23]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 13; + } + + //// 14. Lock context for LCS use + // AT$LCSLK=1,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[24]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 14; + } + + //// 15. Enable GNSS (or GLONASS) + // AT$GPSGLO=1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[25]))); + + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR); + if (answer != 1) + { + return 15; + } + + //// 16. GPS Start Location Service Request: + // AT$GPSSLSR=,,,,,,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[1])), + 1, + gps_mode, + 1); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 1000); + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 16; + } + + // check connection + answer = checkDataConnection(60); + if (answer != 0) + { + return 17; + } + + // return OK + return 0; + } + else + { + return 18; + } + + return 0; +} + + +/* Function: Stops the GPS engine + * Return: '0' if OK; '1' error + */ +uint8_t Wasp4G::gpsStop() +{ + uint8_t answer; + char command_buffer[20]; + + // AT$GPSP=0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[0])), 0); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 1000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + return 0; + +} + +/* Function: Checks the GPS and parses GPS data if the sats are fixed + * Return: '0' if OK; 'x' error + */ +int8_t Wasp4G::checkGPS() +{ + char *pointer; + uint8_t answer; + char command_buffer[20]; + char command_pattern[20]; + + //// 1. Check if the GPS position is fixed + // AT$GPSACP\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_GPS[4]))); + + // pattern <--- "$GPSACP: ," + strcpy_P(command_pattern, (char*)pgm_read_word(&(table_GPS[15]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // check if there is not any available data in _buffer + // If so, _buffer has the following string within it: + // "$GPSACP: ,,,...." + if (find(_buffer, _length, command_pattern) == true) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("pattern not found\n")); + #endif + return 2; + } + + + //// 2. Parses the data + // Example below: + /* $GPSACP: , // field 1: UTC time + * , // field 2: latitude + * , // field 3: longitude + * , // field 4: HDOP + * , // field 5: altitude + * , // field 6: fix mode + * , // field 7: Course over ground + * , // field 8: Speed over ground (Km/hr) + * , // field 9: Speed over ground (knots) + * , // field 10: Date + * // field 11: Number of satellites + */ + // $GPSACP: 073041.000,4139.7780N,00051.3417W,500.0,-394.4,2,0.0,0.0,0.0,050515,00 + + // pattern <--- "\r\n$GPSACP: .," + strcpy_P(command_pattern, (char*)pgm_read_word(&(table_GPS[16]))); + + // skip first characters + pointer = strtok((char*)_buffer, command_pattern); + if (pointer == NULL) + { + return 3; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("UTC:")); + USB.println(pointer); + #endif + + /// field 1: Get UTC time + memset(_time, 0x00, sizeof(_time)); + strncpy(_time, pointer, 6); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 4; + } + + // skip '.000' after time field + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 5; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Latitude:")); + USB.println(pointer); + #endif + + /// field 2: Get latitude + memset(_latitude, '\0', sizeof(_latitude)); + strcpy(_latitude, pointer); + + /// Get NS_indicator + _latitudeNS = _latitude[strlen(_latitude)-1]; + _latitude[strlen(_latitude)-1] = '\0'; + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 6; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Longitude:")); + USB.println(pointer); + #endif + + /// field 3: Get longitude + memset(_longitude, 0x00, sizeof(_longitude)); + strcpy(_longitude, pointer); + + /// Get EW_indicator + _longitudeEW = _longitude[strlen(_longitude)-1]; + _longitude[strlen(_longitude)-1] = '\0'; + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 7; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("HDOP:")); + USB.println(pointer); + #endif + + /// field 4: Get HDOP + _hdop = atof(pointer); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 8; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Altitude:")); + USB.println(pointer); + #endif + + /// field 5: Get altitude + _altitude = atof(pointer); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 9; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Fix mode:")); + USB.println(pointer); + #endif + + /// field 6: Get fix mode + _fixMode = atoi(pointer); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 10; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Course over ground:")); + USB.println(pointer); + #endif + + /// field 7: Get course over ground + memset(_courseOG, 0x00, sizeof(_courseOG)); + strcpy(_courseOG, pointer); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 11; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Speed over ground (kmh):")); + USB.println(pointer); + #endif + + /// field 8: Get Speed over ground (Km/hr) + _speedOG = atof(pointer); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 12; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Speed over ground (knots):")); + USB.println(pointer); + #endif + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 13; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Get date:")); + USB.println(pointer); + #endif + + /// field 10: Get date + memset(_date, 0x00, sizeof(_date)); + strncpy(_date, pointer, 6); + + // skip ',' + pointer = strtok(NULL, ","); + if (pointer == NULL) + { + return 14; + } + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Num Satellites:")); + USB.println(pointer); + #endif + + /// field 11: Get satellites in use + _numSatellites = (uint8_t)atoi(pointer); + + return 0; +} + + + + + +/* + * convert2Degrees ( input , indicator ) - performs the conversion from input + * parameters in DD°MM.mmm’ notation to DD.dddddd° notation. + * + * Sign '+' is set for positive latitudes/longitudes (North, East) + * Sign '-' is set for negative latitudes/longitudes (South, West) + * + * parameter: 'input' is a string indicating the latitude/longitude in + * DDDmm.mmmm' notation for latitude and DDDmm.mmmm' notation for longitude + * parameter: 'indicator' is a char indicating 'N' for North, 'S' for South, 'E' + * for East and 'W' for West + * Returns: a float indicating the latitude in DD.dddddd° notation + * + */ +float Wasp4G::convert2Degrees(char* input, char indicator) +{ + // final latitude expresed in degrees + float degrees; + float minutes; + + // auxiliar variable + char aux[10] = ""; + + // check if 'indicator' is a valid input + if ((indicator != 'N') && + (indicator != 'S') && + (indicator != 'E') && + (indicator != 'W')) + { + // invalid indicator + return 0; + } + + // get 'degrees' from input parameter + if ((indicator == 'N') || (indicator == 'S')) + { + // latitude format: DDmm.mmmm' + aux[0] = input[0]; + aux[1] = input[1]; + aux[2] = '\0'; + } + else if ((indicator == 'E') || (indicator == 'W')) + { + // longitude format: DDDmm.mmmm' + aux[0]=input[0]; + aux[1]=input[1]; + aux[2]=input[2]; + aux[3]='\0'; + } + + // convert string to integer and add it to final float variable + degrees = atoi(aux); + + // get 'minutes' from input parameter + if ((indicator == 'N') || (indicator == 'S')) + { + // latitude format: DDmm.mmmm' + for ( int i=0; i<7; i++ ) + { + aux[i] = input[i+2]; + } + aux[7] = '\0'; + } + else if ((indicator == 'E') || (indicator == 'W')) + { + // longitude format: DDDmm.mmmm' + for ( int i = 0; i < 7; i++ ) + { + aux[i] = input[i+3]; + } + aux[7] = '\0'; + } + + // convert string to integer and add it to final float variable + minutes = atof(aux); + + // add minutes to degrees + degrees = degrees + minutes/60; + + // add sign: '+' for North/East; '-' for South/West + if ((indicator == 'S') || (indicator == 'W')) + { + degrees *= -1.0; + } + + return degrees; +} + + + +/* Function: It waits for satellites signal + * Return: '0' if OK; '1' if error + */ +uint8_t Wasp4G::waitForSignal() +{ + return waitForSignal(60000, -1.0); +} + + +/* Function: It waits for satellites signal + * Parameters: timeout: milliseconds to wait for signal + * Return: '0' if OK; '1' if error + */ +uint8_t Wasp4G::waitForSignal(uint32_t timeout) +{ + return waitForSignal(timeout, -1.0); +} + + +/* Function: It waits for satellites signal + * Parameters: timeout: milliseconds to wait for signal + * Return: '0' if OK; '1' if error + */ +uint8_t Wasp4G::waitForSignal(uint32_t timeout, float desired_HDOP) +{ + int8_t answer = 0; + uint32_t previous; + + // get current time + previous = millis(); + + // update variable status + _fixMode = 0; + + //// 1. get current gps status + while((_fixMode != 2) && (_fixMode != 3)) + { + answer = checkGPS(); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("checkGPS answer: ")); + USB.println(answer); + #endif + + if (answer == 0) + { + if ((_fixMode == 2) || (_fixMode == 3)) + { + // Good options: + // 2 - 2D fix + // 3 - 3D fix + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_fixMode ok\n")); + #endif + break; + } + else + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("_fixMode is not correct yet. _fixmode = ")); + USB.println(_fixMode, DEC); + #endif + } + } + else + { + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("checkGPS error\n")); + #endif + } + + delay(500); + + if (millis()-previous > timeout) + { + // timeout error + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("_fixMode error timeout ==> Exit function\n")); + #endif + return 1; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + } + + + //// 2. Check if desired HDOP is correct + if (desired_HDOP != -1.0) + { + while(((millis() - previous) < timeout) && (_hdop > desired_HDOP)) + { + answer = checkGPS(); + + if (answer == 0) + { + if ((_fixMode == 2) || (_fixMode == 3)) + { + // Good options: + // 2 - 2D fix + // 3 - 3D fix + break; + } + } + + delay(1000); + } + + // if down the threshold then return ok + if (_hdop <= desired_HDOP) + { + return 0; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + } + + if (_hdop < desired_HDOP) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("_hdop not valid\n")); + #endif + return 1; + } + + return 0; +} + + +/* + * Function: It sets the quality of service of GPS + * + */ +uint8_t Wasp4G::gpsSetQualityOfService( uint32_t horiz_accuracy, + uint16_t vertic_accuracy, + uint16_t rsp_time, + uint32_t age_of_location_info, + uint8_t location_type, + uint8_t nav_profile, + uint8_t velocity_request) +{ + uint8_t answer; + char command_buffer[80]; + + // "AT$GPSQOS=%lu,%u,%u,%lu,%u,%u,%u\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[19])), + horiz_accuracy, + vertic_accuracy, + rsp_time, + age_of_location_info, + location_type, + nav_profile, + velocity_request); + + // send command + answer = (int)sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + + // error + return 1; + } + + return 0; +} + + + + +/* + * Function: It gets the NMEA string + * + */ +bool Wasp4G::getNMEAString(uint8_t NMEA) +{ + char command_answer[20]; + char command_buffer[30]; + char NMEA_string[100]; + uint16_t NMEA_length; + uint8_t answer; + + switch(NMEA) + { + case LE910_GGA: + // AT$GPSNMUN=3,1,0,0,0,0,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 1, 0, 0, 0, 0, 0); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[10]))); //$GPGGA + break; + case LE910_GSA: + // AT$GPSNMUN=3,0,0,1,0,0,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 0, 0, 1, 0, 0, 0); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[9]))); //$GPGSA + break; + case LE910_GLL: + // AT$GPSNMUN=3,0,1,0,0,0,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 0, 1, 0, 0, 0, 0); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[7]))); //$GPGLL + break; + case LE910_VTG: + // AT$GPSNMUN=3,0,0,0,0,1,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 0, 0, 0, 0, 1, 0); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[11]))); //$GPRMC + break; + case LE910_RMC: + // AT$GPSNMUN=3,0,0,0,0,0,1\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 0, 0, 0, 0, 0, 1); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[8]))); //$GPVTG + break; + case LE910_GSV: + // AT$GPSNMUN=3,0,0,0,1,0,0\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_GPS[17])), 0, 0, 0, 1, 0, 0); + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[12]))); //$GPGSV + break; + } + + //command_answer <-- "CONNECT\r\n" + strcpy_P(command_answer, (char*)pgm_read_word(&(table_GPS[6]))); + answer = sendCommand(command_buffer, command_answer, 5000); + if (answer != 1) + { + return 1; + } + + // "+++" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_GPS[18]))); + + answer = waitFor("\r\n", 5000); + if (answer != 1) + { + // Exit from data mode + sendCommand(command_buffer, LE910_OK, 2000); + return 1; + } + + memset(NMEA_string, '\0', sizeof(NMEA_string)); + NMEA_length = (strchr((char*)_buffer, '*') - (char*)_buffer); + memcpy(NMEA_string, _buffer, NMEA_length); + + // Exit from data mode + sendCommand(command_buffer, LE910_OK, 2000); + + USB.println(NMEA_string); + + return 0; +} + + + +/* Function: This function gets the temperature interval or the temperature value + * Parameters: mode: 0 for read the temperature interval + * 1 for read the temperature value + * Return: If interval mode selected + * -2 Extreme temperature lower bound. + * -1 Operating temperature lower bound. + * 0 normal temperature. + * 1 Operating temperature upper bound. + * 2 Extreme temperature upper bound. + * -1000 if error + * + * If temperature value selected return temperature in Celsius + * -1000 if error +*/ +uint8_t Wasp4G::getTemp() +{ + int answer; + char *ptr; + char command_answer[20]; + char command_buffer[20]; + + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[8]))); //AT#TEMPMON=1 + strcpy_P(command_answer, (char*)pgm_read_word(&(table_4G[9]))); //#TEMPMEAS: + + // send command + answer = (int)sendCommand(command_buffer, command_answer, LE910_ERROR, 2000); + if (answer != 1) + { + return 1; + } + + answer = waitFor(LE910_OK, 2000); + if (answer != 1) + { + return 1; + } + + // Get temperature interval + ptr = strtok((char*)_buffer, ","); + + if (ptr == NULL) + { + return 1; + } + + _tempInterval = atoi(ptr); + + + // Get temperature in Celsius degrees + ptr = strtok(NULL, "\r"); + + if (ptr == NULL) + { + return 1; + } + _temp = atoi(ptr); + + + return 0; + +} + +/* Function: This function gets the RSSI level + * Return: 0 if OK; 1 if error +*/ +uint8_t Wasp4G::getRSSI() +{ + uint8_t answer; + uint8_t error; + char command_buffer[30]; + char delimiters[30]; + + // AT+CSQ\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[10]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 2000); + + // check answer + if (answer == 1) + { + // delimiters <-- "AT+CSQ\r\n: ," + strcpy_P(delimiters, (char*)pgm_read_word(&(table_4G[33]))); + + error = parseInt(&_rssi, delimiters); + + if (error != 0) + { + return 1; + } + + #if DEBUG_WASP4G > 0 + USB.print(F("Raw RSSI: ")); + USB.println(_rssi, DEC); + #endif + + // converts the RSSI from the command to dBm + switch(_rssi) + { + case 0: + case 99: + _rssi = -113; + break; + case 1: + _rssi = -111; + break; + case 33: + _rssi = 0; + break; + default: + _rssi = (_rssi * 2) - 113; + } + + return 0; + } + + return 1; + +} + +/* Function: This function gets the packet service network type + * Return: '0' if OK; '1' if error + * + * The _networkType attribute stores the corresponding answer: + * 0 for GPRS network + * 1 for EGPRS network + * 2 for WCDMA network + * 3 for HSDPA network + * 4 for LTE network + * 5 for unknown or not registered +*/ +uint8_t Wasp4G::getNetworkType() +{ + uint8_t answer; + uint8_t error; + char command_buffer[50]; + char delimiters[30]; + + // AT#PSNT?\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[11]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 2000); + + if (answer == 1) + { + // delimiters <-- "AT#PSNT?: ,\r\n" + strcpy_P(delimiters, (char*)pgm_read_word(&(table_4G[34]))); + + // parse second response from: "#PSNT: ," + error = parseUint8(&_networkType, delimiters, 2); + + if (error != 0) + { + return 1; + } + + return 0; + } + + return 1; +} + + +/* Function: This function gets the operator name + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::getOperator(char* answer_storage) +{ + uint8_t answer; + char command_buffer[50]; + char* pointer; + + // AT+COPS?\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[24]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + // parse response: "+COPS: 0,0,"",7"\r\n + pointer = strtok((char*)_buffer, "\""); + + if (pointer == NULL) + { + return 2; + } + + strcpy(answer_storage, (char*) strtok(NULL, "\"")); + + return 0; +} + + +/* Function: This function gets info from the module + * Parameters: info_req: + * Wasp4G::INFO_HW + * Wasp4G::INFO_MANUFACTURER_ID + * Wasp4G::INFO_MODEL_ID + * Wasp4G::INFO_REV_ID + * Wasp4G::INFO_IMEI + * Wasp4G::INFO_IMSI + * Wasp4G::INFO_ICCID + * Return: 0 if OK; 1 if error +*/ +int8_t Wasp4G::getInfo(uint8_t info_req) +{ + uint8_t answer; + char command_buffer[50]; + + switch (info_req) + { + case 0: + // Hardware revision + // "AT#HWREV\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[12]))); + break; + case 1: + // Manufacturer identification + // "AT#CGMI\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[13]))); + break; + case 2: + // Model identification + // "AT#CGMM\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[14]))); + break; + case 3: + // Revision identification + // "AT#CGMR\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[15]))); + break; + case 4: + // IMEI + // "AT#CGSN\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[16]))); + break; + case 5: + // IMSI + // "AT#CIMI\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[17]))); + break; + case 6: + // ICCID + // "AT#CCID\r" + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[18]))); + break; + + } + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR, 2000); + + // check answer + if (answer == 1) + { + char aux[30]; + char* pointer; + pointer = strchr((char*)_buffer, ':'); + + // skip command name within response buffer + if (pointer != NULL) + { + pointer++; + _length = strlen(pointer); + memmove((char*)_buffer, pointer, strlen(pointer)); + } + + // success response format: "\r\n\r\n" + answer = parseString(aux, sizeof(aux), " \r\n"); + + if (answer == 0) + { + memset(_buffer, 0x00 ,sizeof(_buffer)); + _length = strlen(aux); + strncpy((char*)_buffer, aux, strlen(aux)); + return 0; + } + return 1; + } + return 1; +} + + + + +/* + * This function selects the cellular network (Wireless Data Service, WDS) to + * operate with the TA (WDS-Side Stack Selection). + * + * NETWORK_GSM + * NETWORK_UTRAN + * NETWORK_3GPP + * NETWORK_EUTRAN_ONLY + * NETWORK_GERAN_UTRAN + * NETWORK_GERAN_EUTRAN + * NETWORK_UTRAN_EUTRAN + * + * @return '0' if OK; '1' if error + * + */ +uint8_t Wasp4G::setWirelessNetwork(uint8_t n) +{ + uint8_t answer; + char command_buffer[20]; + + // "AT+WS46=\r" + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_4G[38])), n); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + return 0; +} + + + +/* + * This function sets the RTC time and date from the Network's response + * + * @return '0' if OK; '1' if error + * + */ +uint8_t Wasp4G::setTimeFrom4G() +{ + int8_t answer, networkType; + char format[60]; + char command_buffer[50]; + uint8_t year, month, day; + uint8_t hour, minute, second, timezone; + bool RTC_status; + + // AT+CCLK?\r + strcpy_P(command_buffer, (char*)pgm_read_word(&(table_4G[25]))); + + // send command + answer = sendCommand(command_buffer, "\"", LE910_ERROR, 2000); + + if (answer == 1) + { + waitFor("\"", 2000); + + // format <-- "%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%hhd\"" + strcpy_P(format, (char*)pgm_read_word(&(table_4G[35]))); + + sscanf( (char*)_buffer, + format, + &year, + &month, + &day, + &hour, + &minute, + &second, + &timezone); + + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Network time:")); + USB.print(F("year: ")); + USB.print(year, DEC); + USB.print(F(" | month: ")); + USB.print(month, DEC); + USB.print(F(" | day: ")); + USB.println(day, DEC); + USB.print(F("hour: ")); + USB.print(hour, DEC); + USB.print(F(" | minute: ")); + USB.print(minute, DEC); + USB.print(F(" | second: ")); + USB.print(second, DEC); + USB.print(F(" | timezone: ")); + USB.println(timezone, DEC); + #endif + + // Get current state of RTC power mode + if (RTC.isON == 0 ) + { + RTC_status = false; + RTC.ON(); + } + else + { + RTC_status = true; + } + + #if DEBUG_WASP4G > 0 + USB.print(F("RTC time before: ")); + USB.println(RTC.getTime()); + #endif + + // set Time & Date + RTC.setTime( year, month, day, (uint8_t)RTC.dow((int)year, (int)month, (int)day), hour, minute, second); + + #if DEBUG_WASP4G > 0 + USB.print(F("RTC time after: ")); + USB.println(RTC.getTime()); + #endif + + if (RTC_status == false ) + { + RTC.OFF(); + } + + return 0; + } + + return 1; + +} + +/* This function sets the apn from operator + * Parameters: apn: operator APN + * Return: nothing +*/ +void Wasp4G::set_APN( char* apn) +{ + + set_APN( apn, NULL, NULL); +} + +/* This function sets the apn, login and password from operator + * Parameters: apn: operator APN + * login: login or user + * password: password + * Return: nothing +*/ +void Wasp4G::set_APN( char* apn, char* login, char* password) +{ + + memset(_apn, '\0', sizeof(_apn)); + memset(_apn_login, '\0', sizeof(_apn_login)); + memset(_apn_password, '\0', sizeof(_apn_password)); + + strncpy(_apn, apn, min(sizeof(_apn), strlen(apn))); + strncpy(_apn_login, login, min(sizeof(_apn_login), strlen(login))); + strncpy(_apn_password, password, min(sizeof(_apn_password), strlen(password))); + +} + +/* This function shows the apn, login and password constants + * + * Return: nothing +*/ +void Wasp4G::show_APN() +{ + // APN parameters depends on SIM + USB.println(F("*****************************")); + USB.print(F("APN: ")); + USB.println(_apn); + USB.print(F("LOGIN: ")); + USB.println(_apn_login); + USB.print(F("PASSWORD: ")); + USB.println(_apn_password); + USB.println(F("*****************************")); +} + + + + +/* Function: This function sets the SMTP server address, used for E-mail sending. + * + * Parameter: SMTP server address, string type. This parameter can be either: + * - any valid IP address in the format: xxx.xxx.xxx.xxx + * - any host name to be solved with a DNS query in the format: + * (factory default is the empty string “”) + * + * Note: the max length for is the output of Test command. + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailSetServerSMTP(char* serverSMTP) +{ + uint8_t answer; + char command_buffer[80]; + + // AT#ESMTP=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[0])),serverSMTP); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + return 0; +} + + + + +/* Function: This function sets the SMTP security and port + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailConfigureSMTP(uint8_t security, uint16_t port) +{ + uint8_t error; + char command_buffer[50]; + char answer[20]; + + // AT#SMTPCFG=,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[7])),security,port); + + // send command + error = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (error != 1) + { + if (error == 2) + { + getErrorCode(); + } + return 1; + } + return 0; +} + + +/* Function: This function sets the email sender parameters + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailSetSender(char* address, char* user, char* password) +{ + uint8_t answer; + char command_buffer[100]; + + //// 1. Set sender address + // AT#EADDR="
"\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[1])),address); + + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + + + //// 2. Set sender user + // AT#EUSER=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[2])),user); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 2; + } + + //// 3. Set sender password + // AT#EPASSW=""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[3])),password); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 3; + } + + return 0; +} + + + +/* Function: This function activates context + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailActivateContext(char* user, char* password) +{ + uint8_t error; + char command_buffer[50]; + char answer[20]; + + // AT#SGACT=1,1,"",""\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[5])),user,password); + + // "#SGACT: " + sprintf_P(answer, (char*)pgm_read_word(&(table_EMAIL_LE910[6]))); + + // send command + error = sendCommand(command_buffer, answer, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (error != 1) + { + if (error == 2) + { + getErrorCode(); + } + return 1; + } + return 0; +} + + +/* Function: This function sends the email + * Return: '0' if OK; 'x' if error +*/ + +uint8_t Wasp4G::emailSend(char* address,char* subject,char* body) +{ + uint8_t error; + char command_buffer[50]; + char answer[20]; + + //// 1. Check data connection + error = checkDataConnection(60); + if (error != 0) + { + return error; // 1 to 15 error codes + } + + + //// 2. Send email + // AT#EMAILD=
,\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[8])),address,subject); + + // send command + error = sendCommand(command_buffer, ">", LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (error != 1) + { + if (error == 2) + { + getErrorCode(); + } + return 1; + } + + // send e-mail body to the module + printString(body,1); + printByte(0x1A,1); + + error = waitFor(LE910_OK,LE910_ERROR_CODE,LE910_ERROR,10000); + + // check answer + if (error != 1) + { + if (error == 2) + { + getErrorCode(); + } + return 2; + } + return 0; +} + + +/* Function: This function resets the actual e-mail parameters in the NVM of + * the module to the default ones. The values reset are: + * E-mail User Name + * E-mail Password + * E-mail Sender Address + * E-mail SMTP server + * + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailReset() +{ + uint8_t answer; + char command_buffer[15]; + + // AT#ERST\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[9]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + return 0; +} + + +/* Function: This function saves the actual e-mail parameters in the NVM of the + * device. The values reset are: + * E-mail User Name + * E-mail Password + * E-mail Sender Address + * E-mail SMTP server + * + * Return: '0' if OK; 'x' if error +*/ +uint8_t Wasp4G::emailSave() +{ + uint8_t answer; + char command_buffer[15]; + + // AT#ESAV\r + sprintf_P(command_buffer, (char*)pgm_read_word(&(table_EMAIL_LE910[10]))); + + // send command + answer = sendCommand(command_buffer, LE910_OK, LE910_ERROR_CODE, LE910_ERROR, 2000); + + // check answer + if (answer != 1) + { + if (answer == 2) + { + getErrorCode(); + } + return 1; + } + return 0; +} + + + + +/* + * requestOTA + * + * This function downloads a new OTA file if OTA is necessary + * + * Returns 'x' if error + */ +uint8_t Wasp4G::requestOTA( char* ftp_server, + uint16_t ftp_port, + char* ftp_user, + char* ftp_pass) +{ + + uint8_t error; + char format_no_file[10]; + char format_file[10]; + char format_path[10]; + char format_size[10]; + char format_version[10]; + int length; + uint8_t error_flag; + + char* str_pointer; + char aux_name[8]; + char path[100]; + char aux_str[10]; + long int aux_size; + uint8_t aux_version; + + + //////////////////////////////////////////////////////////////////////////// + // 1. SD init + //////////////////////////////////////////////////////////////////////////// + + // switch SD card ON + SD.ON(); + + // go to Root directory + SD.goRoot(); + + // check if the card is there or not + if (!SD.isSD()) + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error: SD not present\n")); + #endif + SD.OFF(); + return 1; + } + + // Delete file in the case it exists + if (SD.isFile(LE910_OTA_FILE) == 1) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("delete file\n")); + #endif + SD.del(LE910_OTA_FILE); + } + + // switch off the SD card + SD.OFF(); + + + //////////////////////////////////////////////////////////////////////////// + // 2. Open FTP session and download config file + //////////////////////////////////////////////////////////////////////////// + error = ftpOpenSession(ftp_server, ftp_port, ftp_user, ftp_pass); + + if (error == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Downloading OTA config file...\n")); + #endif + + // download "UPGRADE.TXT" + error = ftpDownload(LE910_OTA_FILE, LE910_OTA_FILE); + + if (error == 0) + { + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("LE910_OTA_FILE download OK\n")); + #endif + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("LE910_OTA_FILE download ERROR\n")); + #endif + return 2; + } + } + else + { + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Open FTP session ERROR\n")); + #endif + return 3; + } + + + //////////////////////////////////////////////////////////////////////////// + // 3. Analyze LE910_OTA_FILE + //////////////////////////////////////////////////////////////////////////// + + // "NO_FILE" + strcpy_P( format_no_file, (char*)pgm_read_word(&(table_OTA_LE910[1]))); + // "FILE:" + strcpy_P( format_file, (char*)pgm_read_word(&(table_OTA_LE910[2]))); + // "PATH:" + strcpy_P( format_path, (char*)pgm_read_word(&(table_OTA_LE910[3]))); + // "SIZE:" + strcpy_P( format_size, (char*)pgm_read_word(&(table_OTA_LE910[4]))); + // "VERSION:" + strcpy_P( format_version, (char*)pgm_read_word(&(table_OTA_LE910[5]))); + + // init SD + SD.ON(); + SD.goRoot(); + + // clear buffer + memset(_buffer, 0x00, sizeof(_buffer)); + + // Reads the config file and copy to '_buffer' + SD.cat(LE910_OTA_FILE, 0, sizeof(_buffer)); + strcpy((char*)_buffer, SD.buffer); + + + /// 1. Search the file name + str_pointer = strstr((char*) _buffer, format_file); + if (str_pointer != NULL) + { + // Copy the FILE contents: + // get string length and check it is equal to 7 + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + if (length != 7) + { + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("length:")); + USB.println(length); + #endif + return 4; + } + // copy string + strncpy(aux_name, strchr(str_pointer, ':')+1, 7); + aux_name[7] = '\0'; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("FILE:")); + USB.println(aux_name); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("No FILE label\n")); + #endif + return 5; + } + + /// 2. Check if NO_FILE is the filename + if (strcmp(aux_name, format_no_file) == 0) + { + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(format_no_file); + USB.println(format_no_file); + #endif + return 6; + } + + /// 3. Search the path + str_pointer = strstr((char*) _buffer, format_path); + if (str_pointer != NULL) + { + // copy the PATH contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + strncpy(path, strchr(str_pointer, ':') + 1, length ); + path[length] = '\0'; + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("PATH:")); + USB.println(path); + #endif + + // delete actual program + SD.del(aux_name); + } + else + { + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("No PATH label\n")); + #endif + return 7; + } + + /// 4. Search file size + str_pointer = strstr((char*) _buffer, format_size); + if (str_pointer != NULL) + { + // copy the SIZE contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + // check length does not overflow + if (length >= (int)sizeof(aux_str)) + { + length = sizeof(aux_str)-1; + } + strncpy(aux_str, strchr(str_pointer, ':')+1, length); + aux_str[length] = '\0'; + + // converto from string to int + aux_size = atol(aux_str); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("SIZE:")); + USB.println(aux_size); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("No SIZE label\n")); + #endif + return 8; + } + + /// 5. Search Version + str_pointer = strstr((char*) _buffer, format_version); + if (str_pointer != NULL) + { + // copy the SIZE contents + length = strchr(str_pointer, '\n')-1-strchr(str_pointer, ':'); + // check length does not overflow + if (length >= (int)sizeof(aux_str)) + { + length = sizeof(aux_str)-1; + } + strncpy(aux_str, strchr(str_pointer, ':')+1, length); + aux_str[length] = '\0'; + + // convert from string to uint8_t + aux_version=(uint8_t)atoi(aux_str); + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("VERSION:")); + USB.println(aux_version,DEC); + #endif + } + else + { + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("No VERSION label\n")); + #endif + return 9; + } + + + + // get actual program version + uint8_t prog_version = Utils.getProgramVersion(); + // get actual program name (PID) + char prog_name[8]; + Utils.getProgramID(prog_name); + + // check if version number + #ifdef LE910_CHECK_VERSION + if (strcmp(prog_name,aux_name) == 0) + { + if ((prog_version >= aux_version) && (prog_version != 255)) + { + ftpCloseSession(); + + // if we have specified the same program id and lower/same version + // number, then do not proceed with OTA + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Invalid version: actual=")); + USB.print(prog_version,DEC); + USB.print(F("; new=")); + USB.println(aux_version,DEC); + #endif + return 10; + } + } + #endif + + + //////////////////////////////////////////////////////////////////////////// + // 4. Download binary file + //////////////////////////////////////////////////////////////////////////// + + #if DEBUG_WASP4G > 1 + PRINT_LE910(F("Downloading OTA FILE\n")); + #endif + + // get binary file + error = ftpDownload((char*)aux_name, aux_name); + + if (error == 0) + { + // check if size matches + SD.ON(); + + // get file size + int32_t sd_file_size = SD.getFileSize(aux_name); + if (sd_file_size != aux_size) + { + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Size does not match\n")); + PRINT_LE910(F("sd_file_size:")); + USB.println(sd_file_size); + PRINT_LE910(F("UPGRADE.TXT size field:")); + USB.println(aux_size); + #endif + return 11; + } + #if DEBUG_WASP4G > 1 + SD.ls(); + #endif + ftpCloseSession(); + + // call OTA function + Utils.loadOTA(aux_name,aux_version); + return 0; + } + else + { + error_flag = error; + SD.OFF(); + ftpCloseSession(); + #if DEBUG_WASP4G > 0 + PRINT_LE910(F("Error getting binary\n")); + #endif + return error_flag + 11; // error codes: 12 to 24 + } + +} + + + + +/* This function shows the error code number stored in the related attribute + * + * @return: nothing + */ +void Wasp4G::printErrorCode() +{ + printErrorCode(_errorCode); +} + + + +#if DEBUG_WASP4G > 0 +/* This function shows the error code indicated as input + * + * @return: nothing + */ +void Wasp4G::printErrorCode( uint16_t error ) +{ + PRINT_LE910(F("==> ERROR CODE: ")); + switch (error) + { + case WASP4G_CME_ERROR_0000: USB.println(F("phone failure")); break; + case WASP4G_CME_ERROR_0001: USB.println(F("No connection to phone")); break; + case WASP4G_CME_ERROR_0002: USB.println(F("phone-adaptor link reserved")); break; + case WASP4G_CME_ERROR_0003: USB.println(F("operation not allowed")); break; + case WASP4G_CME_ERROR_0004: USB.println(F("operation not supported")); break; + case WASP4G_CME_ERROR_0005: USB.println(F("PH-SIM PIN required")); break; + case WASP4G_CME_ERROR_0010: USB.println(F("SIM not inserted")); break; + case WASP4G_CME_ERROR_0011: USB.println(F("SIM PIN required")); break; + case WASP4G_CME_ERROR_0012: USB.println(F("SIM PUK required")); break; + case WASP4G_CME_ERROR_0013: USB.println(F("SIM failure")); break; + case WASP4G_CME_ERROR_0014: USB.println(F("SIM busy")); break; + case WASP4G_CME_ERROR_0015: USB.println(F("SIM wrong")); break; + case WASP4G_CME_ERROR_0016: USB.println(F("incorrect password")); break; + case WASP4G_CME_ERROR_0017: USB.println(F("SIM PIN2 required")); break; + case WASP4G_CME_ERROR_0018: USB.println(F("SIM PUK2 required")); break; + case WASP4G_CME_ERROR_0020: USB.println(F("memory full")); break; + case WASP4G_CME_ERROR_0021: USB.println(F("invalid index")); break; + case WASP4G_CME_ERROR_0022: USB.println(F("not found")); break; + case WASP4G_CME_ERROR_0023: USB.println(F("memory failure")); break; + case WASP4G_CME_ERROR_0024: USB.println(F("text string too long")); break; + case WASP4G_CME_ERROR_0025: USB.println(F("invalid characters in text string")); break; + case WASP4G_CME_ERROR_0026: USB.println(F("dial string too long")); break; + case WASP4G_CME_ERROR_0027: USB.println(F("invalid characters in dial string")); break; + case WASP4G_CME_ERROR_0030: USB.println(F("no network service")); break; + case WASP4G_CME_ERROR_0031: USB.println(F("network time-out")); break; + case WASP4G_CME_ERROR_0032: USB.println(F("network not allowed - emergency calls only")); break; + case WASP4G_CME_ERROR_0040: USB.println(F("network personalization PIN required")); break; + case WASP4G_CME_ERROR_0041: USB.println(F("network personalization PUK required")); break; + case WASP4G_CME_ERROR_0042: USB.println(F("network subset personalization PIN required")); break; + case WASP4G_CME_ERROR_0043: USB.println(F("network subset personalization PUK required")); break; + case WASP4G_CME_ERROR_0044: USB.println(F("service provider personalization PIN required")); break; + case WASP4G_CME_ERROR_0045: USB.println(F("Service provider personalization PUK required")); break; + case WASP4G_CME_ERROR_0046: USB.println(F("corporate personalization PIN required")); break; + case WASP4G_CME_ERROR_0047: USB.println(F("corporate personalization PUK required")); break; + case WASP4G_CME_ERROR_0100: USB.println(F("unknown")); break; + case WASP4G_CME_ERROR_0770: USB.println(F("SIM invalid")); break; + case WASP4G_CME_ERROR_0103: USB.println(F("Illegal MS (#3)*")); break; + case WASP4G_CME_ERROR_0106: USB.println(F("Illegal ME (#6)*")); break; + case WASP4G_CME_ERROR_0107: USB.println(F("GPRS service not allowed (#7)*")); break; + case WASP4G_CME_ERROR_0111: USB.println(F("PLMN not allowed (#11)*")); break; + case WASP4G_CME_ERROR_0112: USB.println(F("Location area not allowed (#12)*")); break; + case WASP4G_CME_ERROR_0113: USB.println(F("Roaming not allowed in this location area (#13)*")); break; + case WASP4G_CME_ERROR_0132: USB.println(F("service option not supported (#32)*")); break; + case WASP4G_CME_ERROR_0133: USB.println(F("requested service option not subscribed (#33)*")); break; + case WASP4G_CME_ERROR_0134: USB.println(F("service option temporarily out of order (#34)*")); break; + case WASP4G_CME_ERROR_0148: USB.println(F("unspecified GPRS error")); break; + case WASP4G_CME_ERROR_0149: USB.println(F("PDP authentication failure")); break; + case WASP4G_CME_ERROR_0150: USB.println(F("invalid mobile class")); break; + case WASP4G_CME_ERROR_0550: USB.println(F("generic undocumented error")); break; + case WASP4G_CME_ERROR_0551: USB.println(F("wrong state")); break; + case WASP4G_CME_ERROR_0552: USB.println(F("wrong mode")); break; + case WASP4G_CME_ERROR_0553: USB.println(F("context already activated")); break; + case WASP4G_CME_ERROR_0554: USB.println(F("stack already active")); break; + case WASP4G_CME_ERROR_0555: USB.println(F("activation failed")); break; + case WASP4G_CME_ERROR_0556: USB.println(F("context not opened")); break; + case WASP4G_CME_ERROR_0557: USB.println(F("cannot setup socket")); break; + case WASP4G_CME_ERROR_0558: USB.println(F("cannot resolve DN")); break; + case WASP4G_CME_ERROR_0559: USB.println(F("time-out in opening socket")); break; + case WASP4G_CME_ERROR_0560: USB.println(F("cannot open socket")); break; + case WASP4G_CME_ERROR_0561: USB.println(F("remote disconnected or time-out")); break; + case WASP4G_CME_ERROR_0562: USB.println(F("connection failed")); break; + case WASP4G_CME_ERROR_0563: USB.println(F("tx error")); break; + case WASP4G_CME_ERROR_0564: USB.println(F("already listening")); break; + case WASP4G_CME_ERROR_0568: USB.println(F("wrong PDP")); break; + case WASP4G_CME_ERROR_0615: USB.println(F("FTP not connected")); break; + case WASP4G_CME_ERROR_0623: USB.println(F("FTP write data closed")); break; + case WASP4G_CME_ERROR_0643: USB.println(F("FTP communication timeout")); break; + case WASP4G_CME_ERROR_0657: USB.println(F("Network survey error (No Carrier)*")); break; + case WASP4G_CME_ERROR_0658: USB.println(F("Network survey error (Busy)*")); break; + case WASP4G_CME_ERROR_0659: USB.println(F("Network survey error (Wrong request)*")); break; + case WASP4G_CME_ERROR_0660: USB.println(F("Network survey error (Aborted)*")); break; + case WASP4G_CME_ERROR_0257: USB.println(F("network rejected request")); break; + case WASP4G_CME_ERROR_0258: USB.println(F("retry operation")); break; + case WASP4G_CME_ERROR_0259: USB.println(F("invalid deflected to number")); break; + case WASP4G_CME_ERROR_0260: USB.println(F("deflected to own number")); break; + case WASP4G_CME_ERROR_0261: USB.println(F("unknown subscriber")); break; + case WASP4G_CME_ERROR_0262: USB.println(F("service not available")); break; + case WASP4G_CME_ERROR_0263: USB.println(F("unknown class specified")); break; + case WASP4G_CME_ERROR_0264: USB.println(F("unknown network message")); break; + case WASP4G_CME_ERROR_0680: USB.println(F("LU processing")); break; + case WASP4G_CME_ERROR_0681: USB.println(F("Network search aborted")); break; + case WASP4G_CME_ERROR_0682: USB.println(F("PTM mode")); break; + case WASP4G_CME_ERROR_0683: USB.println(F("Active call state")); break; + case WASP4G_CME_ERROR_0684: USB.println(F("SSL already activated")); break; + case WASP4G_CMS_ERROR_0300: USB.println(F("ME failure")); break; + case WASP4G_CMS_ERROR_0301: USB.println(F("SMS service of ME reserved")); break; + case WASP4G_CMS_ERROR_0302: USB.println(F("operation not allowed")); break; + case WASP4G_CMS_ERROR_0303: USB.println(F("operation not supported")); break; + case WASP4G_CMS_ERROR_0304: USB.println(F("invalid PDU mode parameter")); break; + case WASP4G_CMS_ERROR_0305: USB.println(F("invalid text mode parameter")); break; + case WASP4G_CMS_ERROR_0310: USB.println(F("SIM not inserted")); break; + case WASP4G_CMS_ERROR_0311: USB.println(F("SIM PIN required")); break; + case WASP4G_CMS_ERROR_0312: USB.println(F("PH-SIM PIN required")); break; + case WASP4G_CMS_ERROR_0313: USB.println(F("SIM failure")); break; + case WASP4G_CMS_ERROR_0314: USB.println(F("SIM busy")); break; + case WASP4G_CMS_ERROR_0315: USB.println(F("SIM wrong ")); break; + case WASP4G_CMS_ERROR_0316: USB.println(F("SIM PUK required")); break; + case WASP4G_CMS_ERROR_0317: USB.println(F("SIM PIN2 required")); break; + case WASP4G_CMS_ERROR_0318: USB.println(F("SIM PUK2 required")); break; + case WASP4G_CMS_ERROR_0320: USB.println(F("memory failure")); break; + case WASP4G_CMS_ERROR_0321: USB.println(F("invalid memory index")); break; + case WASP4G_CMS_ERROR_0322: USB.println(F("memory full")); break; + case WASP4G_CMS_ERROR_0330: USB.println(F("SMSC address unknown")); break; + case WASP4G_CMS_ERROR_0331: USB.println(F("no network service")); break; + case WASP4G_CMS_ERROR_0332: USB.println(F("network time-out")); break; + case WASP4G_CMS_ERROR_0340: USB.println(F("no +CNMA acknowledgement expected")); break; + case WASP4G_CMS_ERROR_0500: USB.println(F("unknown error")); break; + case WASP4G_CME_ERROR_1000: USB.println(F("SSL not activated")); break; + case WASP4G_CME_ERROR_1001: USB.println(F("SSL certs and keys wrong or not stored")); break; + case WASP4G_CME_ERROR_1003: USB.println(F("SSL already activated")); break; + case WASP4G_CME_ERROR_1008: USB.println(F("SSL not connected")); break; + default: USB.println(F("UNKNOWN")); break; + } +} +#else +void Wasp4G::printErrorCode( uint16_t error ) +{ + USB.print(F("==> ERROR CODE: ")); + USB.println( error, DEC); +} +#endif + + +// Preinstantiate Objects ///////////////////////////////////////////////////// + +Wasp4G _4G = Wasp4G(); + +/////////////////////////////////////////////////////////////////////////////// diff --git a/libraries/Wasp4G/Wasp4G.h b/libraries/Wasp4G/Wasp4G.h new file mode 100755 index 0000000..395e6bf --- /dev/null +++ b/libraries/Wasp4G/Wasp4G.h @@ -0,0 +1,1433 @@ +/*! \file Wasp4G.h + \brief Library for managing Telit LE910 + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: A. Gállego, Y. Carmona + + */ + +/*! \def Wasp4G_h + \brief The library flag + */ +#ifndef Wasp4G_h +#define Wasp4G_h + +/****************************************************************************** + * Includes + *****************************************************************************/ + +#include +#include +#include "./utility/Wasp4G_constants.h" + +/****************************************************************************** + * Definitions & Declarations + *****************************************************************************/ + +//! DEBUG_WASP4G +/*! Possible values: + * 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + */ +#define DEBUG_WASP4G 0 + +//! Flag to enable the version number checking in OTA process +#define LE910_CHECK_VERSION + +// define print message +#define PRINT_LE910(str) USB.print(F("[LE910] ")); USB.print(str); + +// APN default settings +#define LE910_GPRS_APN "APN" +#define LE910_GPRS_LOGIN "user" +#define LE910_GPRS_PASSW "password" + +// Error Constants +#define LE910_ERROR_CME "+CME ERROR:" +#define LE910_ERROR_CMS "+CMS ERROR:" +#define LE910_ERROR_CODE "ERROR:" +#define LE910_ERROR "ERROR\r\n" +#define LE910_OK "OK" + + +static char LE910_OTA_FILE[] = "UPGRADE.TXT"; + + +// LE910 Baud Rate +#define LE910_RATE 115200 + +#define LE910_GGA 0 +#define LE910_GSA 1 +#define LE910_GLL 2 +#define LE910_VTG 3 +#define LE910_RMC 4 +#define LE910_GSV 5 + +// Incoming data options +#define LE910_INCOMING_SMS 1 +#define LE910_INCOMING_IP 2 + +// Patterns for module communication +#define LE910_DATA_TO_MODULE ">>>" +#define LE910_DATA_FROM_MODULE "<<<" + +// Maximum packet size for FTP download +#define LE910_MAX_DL_PAYLOAD 490 + + + +//! Structure to define the info to be stored for all sockets +struct SocketInfo_t +{ + uint8_t id; // from 1 to 6 + uint16_t sent; // total num of bytes sent since socket was opened + uint16_t received; // total num of bytes received since socket was opened + uint16_t size; // total num of pending bytes to read which arrived through the socket + uint16_t ack; // total num of bytes sent and not yet acknowledged data since socket was opened +}; + + +//! Structure to define the status to be stored for all sockets +struct SocketStatus_t +{ + uint8_t id; // from 1 to 6 + uint8_t state; // actual state of the socket + char localIp[16]; // local IP address + uint16_t localPort; // local port + char remoteIp[16]; // remote IP address + uint16_t remotePort;// remote port +}; + + +//! Structure to define the status to be stored for all sockets +struct SocketStatusSSL_t +{ + uint8_t id; // from 1 to 6 + uint8_t state; // actual state of the socket +}; + + +/****************************************************************************** + * Class + *****************************************************************************/ +//! Wasp4G class + +class Wasp4G : public WaspUART +{ + +private: + /*! Attribute for APN + */ + char _apn[30]; + + /*! Attribute for APN login + */ + char _apn_login[30]; + + /*! Attribute for APN password + */ + char _apn_password[30]; + + /*! This function parses the error copde returned by the module. At the + * point this function is called, the UART is supposed to have received: + * "+CME ERROR: \r\n" and the first part of the response has been + * already detected: "+CME ERROR:", so this function needs to parse the + * error code. + * + * If error code is parsed succesfully then the attribute _errorCode stores + * this error information + * + * @return '0' ok; '1' error + */ + uint8_t getErrorCode(); + + //! This function configures the remote server and sends the request + /*! + \param uint8_t method: selected HTTP method: Wasp4G::HTTP_GET + Wasp4G::HTTP_HEAD + Wasp4G::HTTP_DELETE + Wasp4G::HTTP_POST + Wasp4G::HTTP_PUT + \param char* url: host name or IP address of the server + \param uint16_t port: server port + \param char* resource: parameter indicating the HTTP resource, object of the + request + \param char* data: data to send in POST/PUT method + \param uint16_t data_length: data length to send in POST/PUT method + \return 0 if OK + 1 if error setting URL and port + 2 if error sending the request + 3 if error sending POST / PUT data + 4 if worng method has been selected + */ + uint8_t httpRequest(uint8_t method, + char* url, + uint16_t port, + char* resource, + char* data); + + uint8_t httpRequest(uint8_t method, + char* url, + uint16_t port, + char* resource, + uint8_t* data, + uint16_t length); + + //! This function waits the URC code and reads the data availble + /*! + \param uint32_t wait_timeout: timeout for URC + \return 0 if OK + 1 if timeout waiting the URC + 2 if error reading the URC + 3 if error reading the HTTP data + 4 if error reading the HTTP data + */ + uint8_t httpWaitResponse(uint32_t wait_timeout); + + + + +public: + + char _ip[16]; // xxx.yyy.zzz.www + uint16_t _errorCode; + int _temp; + int _tempInterval; + int _rssi; + uint8_t _networkType; + uint8_t _incomingType; + int _smsIndex; + int _socketIndex; + int _httpCode; + uint32_t _filesize; + char _smsStatus[12]; + char _smsNumber[20]; + char _smsDate[9]; + char _smsTime[12]; + char _ftpWorkingDirectory[20]; + SocketInfo_t socketInfo[6]; + SocketStatus_t socketStatus[6]; + SocketStatusSSL_t socketStatusSSL[1]; + + //! Profile definition for multiple sockets + enum ProfileSocketEnum + { + CONNECTION_1 = 0, + CONNECTION_2 = 1, + CONNECTION_3 = 2, + CONNECTION_4 = 3, + CONNECTION_5 = 4, + CONNECTION_6 = 5, + }; + + //! Socket Status definition + enum SocketStatusEnum + { + STATUS_CLOSED = 0, + STATUS_ACTIVE = 1, + STATUS_SUSPENDED = 2, + STATUS_SUSPENDED_DATA = 3, + STATUS_LISTENING = 4, + STATUS_INCOMING = 5, + STATUS_OPENING = 6, + }; + + //! Wireless Network enumeration + enum WirelessNetworkEnum + { + NETWORK_GSM = 12, + NETWORK_UTRAN = 22, + NETWORK_3GPP = 25, // default + NETWORK_EUTRAN_ONLY = 28, + NETWORK_GERAN_UTRAN = 29, + NETWORK_GERAN_EUTRAN = 30, + NETWORK_UTRAN_EUTRAN = 31, + }; + + //! GPS Mode Enumeration + enum GPSModeEnum + { + GPS_MS_ASSISTED = 0, + GPS_MS_BASED = 1, + GPS_AUTONOMOUS = 3, + }; + + //! Module Information Enumeration + enum ModuleInformationEnum + { + INFO_HW = 0, + INFO_MANUFACTURER_ID = 1, + INFO_MODEL_ID = 2, + INFO_REV_ID = 3, + INFO_IMEI = 4, + INFO_IMSI = 5, + INFO_ICCID = 6, + }; + + //! Network Type Enumeration + enum NetworkTypeEnumeration + { + NETWORK_GPRS = 0, + NETWORK_EGPRS = 1, + NETWORK_WCDMA = 2, + NETWORK_HSDPA = 3, + NETWORK_LTE = 4, + NETWORK_UNKNOWN = 5, + }; + + //! SMS Delete Flag + enum DeleteFlagEnumeration + { + SMS_DELETE_MESSAGE = 0, + SMS_DELETE_ALL_1 = 1, + SMS_DELETE_ALL_2 = 2, + SMS_DELETE_ALL_3 = 3, + SMS_DELETE_ALL_4 = 4, + }; + + //! HTTP method Enumeration + enum HttpMethodEnumeration + { + HTTP_GET = 0, + HTTP_HEAD = 1, + HTTP_DELETE = 2, + HTTP_POST = 3, + HTTP_PUT = 4, + HTTP_POST_FRAME = 5, + }; + + //! TCP/UDP sockets protocol enumeration + enum MultisocketProtocolEnumeration + { + TCP = 0, + UDP = 1, + }; + + //! Security data actions enumeration + enum SecurityDataActionsEnumeration + { + SSL_ACTION_DELETE = 0, + SSL_ACTION_STORE = 1, + SSL_ACTION_READ = 2, + SSL_EMAIL_DISABLED = 0, + SSL_EMAIL_ENABLES = 1, + }; + + //! E-mail security enumeration + enum EmailSecurityEnumeration + { + EMAIL_NONSSL = 0, + EMAIL_SSL = 1, + }; + + //! Security data types + enum SecurityDataTypesEnumeration + { + SSL_TYPE_CERT = 0, + SSL_TYPE_CA_CERT = 1, + SSL_TYPE_RSA = 2, + }; + + + //! class constructor + /*! + \brief It initializes some variables + \param void + \return void + */ + Wasp4G(); + + /*! + \brief This function inits the LE910 module + \return 0 if OK + 1 for no comunication + 2 if error switching CME errors to numeric response + 3 if error disabling the echo from the module + 4 if error enabling RTC update with network time + */ + uint8_t ON(); + + + /*! + \brief This function powers off the LE910 module + \return nothing + */ + void OFF(); + + /*! + \brief This function enters a PIN / PUK code + \param char* code: string with the requested code + \return 0 if OK; 1 if error + */ + uint8_t enterPIN(char* code); + + /*! + \brief This function enters a PIN / PUK code + \param char* code: string with the requested code + \param char* new_code: string with the new code (only for SIM PUK or SIM PUK2) + \return '0' if OK; '1' if error + */ + uint8_t enterPIN(char* code, char* new_code); + + /*! + \brief This function returns the result code for a PIN request + \return 0 for PIN ready + 1 LE910 is awaiting SIM PIN + 2 LE910 is awaiting SIM PUK + 3 LE910 is awaiting phone-to-SIM card password. + 4 LE910 is awaiting phone-to-very-first-SIM card password. + 5 LE910 is awaiting phone-to-very-first-SIM card unblocking password. + 6 LE910 is awaiting SIM PIN2 + 7 LE910 is awaiting SIM PUK2 + 8 LE910 is awaiting network personalization password + 9 LE910 is awaiting network personalization unblocking password + 10 LE910 is awaiting network subset personalization password + 11 LE910 is awaiting network subset personalization unblocking password + 12 LE910 is awaiting service provider personalization password + 13 LE910 is awaiting service provider personalization unblocking password + 14 LE910 is awaiting corporate personalization password + 15 LE910 is awaiting corporate personalization unblocking password + 254 if not expected code returned + 255 if command error + */ + uint8_t checkPIN(); + + /*! + \brief This function checks connection status + \param uint8_t time: max allowed time in seconds to connect + \return 0 If the module is connected to the network + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + */ + uint8_t checkConnection(uint8_t time); + uint8_t checkConnectionEPS(uint8_t time); + + /*! + \brief This function checks connection status and connect to data service + \param uint8_t time: max allowed time in seconds to connect + \return 0 If the module is connected to data service + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + */ + uint8_t checkDataConnection(uint8_t time); + + + /*! + \brief This function manages incoming data from serial port + \param unsigned long wait_time: maximum waiting time in milliseconds + \return 0 for error or not data + 1 for SMS + 2 for IP data + */ + uint8_t manageIncomingData(unsigned long wait_time); + + + /*! + \brief This function sets the parameters to use SMS + \return 0 if OK + 1 if error setting the SMS format + 2 if error selecting the storage + 3 if error setting the incoming SMS indication + */ + uint8_t configureSMS(); + + /*! + \brief This function reads the last unread received message + \param uint32_t timeout: time to wait for a new SMS + \return 0 if OK; 1 if error + */ + uint8_t readNewSMS(); + uint8_t readNewSMS(uint32_t timeout); + + + /*! + \brief This function sends a SMS + \param char* phone_number: number to send the SMS + \param char* sms_string: body of the SMS + \return 0 if OK + 1 if error setting the phone number + 2 if error sending the body + */ + uint8_t sendSMS(char* phone_number, char* sms_string); + + + /*! + \brief This function reads a SMS + \param uint8_t sms_index: index of the SMS into the memory + \return 0 if OK + 1 if error getting the SMS + 2 if error storing the message + */ + uint8_t readSMS(uint8_t sms_index); + + + /*! + \brief This function deletes a SMS + \param uint8_t sms_index: index of the SMS into the memory + \return 0 if OK + 1 if error deleting the SMS + */ + uint8_t deleteSMS(uint8_t sms_index); + + + /*! + \brief This function deletes a SMS + \param uint8_t sms_index: index of the SMS into the memory + \return 0 if OK + 1 if error deleting the SMS + */ + uint8_t deleteSMS(uint8_t sms_index, uint8_t del_flag); + + /*! + \brief This function performs a HTTP request + \param uint8_t method: selected HTTP method: Wasp4G::HTTP_GET + Wasp4G::HTTP_HEAD + Wasp4G::HTTP_DELETE + \param char* url: host name or IP address of the server + \param uint16_t port: server port + \param char* resource: parameter indicating the HTTP resource, object of the request + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 if error setting URL and port + 17 if error sending the request + 18 if error sending POST / PUT data + 19 if wrong method has been selected + 20 if timeout waiting the URC + 21 if error reading the URC + 22 if error reading the HTTP status + 23 if error reading the HTTP data length + 24 if error reading the HTTP data + 25 if error code from 4G module while waiting for HTTP response + 26 if timeout waiting for HTTP response + 27 if HTTP response data length is zero + */ + uint8_t http( uint8_t method, + char* url, + uint16_t port, + char* resource); + + /*! + \brief This function performs a HTTP request + \param uint8_t method: selected HTTP method: Wasp4G::HTTP_GET + Wasp4G::HTTP_HEAD + Wasp4G::HTTP_DELETE + Wasp4G::HTTP_POST + Wasp4G::HTTP_PUT + Wasp4G::HTTP_POST_FRAME + \param char* url: host name or IP address of the server + \param uint16_t port: server port + \param char* resource: parameter indicating the HTTP resource, object of the request + \param char* POST_PUT_data: data to send in POST/PUT method + \param uint16_t POST_PUT_length: data length to send in POST/PUT method + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 if error setting URL and port + 17 if error sending the request + 18 if error sending POST / PUT data + 19 if wrong method has been selected + 20 if timeout waiting the URC + 21 if error reading the URC + 22 if error reading the HTTP status + 23 if error reading the HTTP data length + 24 if error reading the HTTP data + 25 if error code from 4G module while waiting for HTTP response + 26 if timeout waiting for HTTP response + 27 if HTTP response data length is zero + */ + uint8_t http( uint8_t method, + char* url, + uint16_t port, + char* resource, + char* data); + + + /*! + \brief This function performs a HTTP request to send data to Meshlium. It + is mandatory to use a Waspmote frame as input + \param char* url: host name or IP address of the Meshlium device + \param uint16_t port: server port + \param uint8_t* data: pointer to frame buffer + \param uint16_t length: data length to send in POST/PUT method + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 if error setting URL and port + 17 if error sending the request + 18 if error sending POST / PUT data + 19 if wrong method has been selected + 20 if timeout waiting the URC + 21 if error reading the URC + 22 if error reading the HTTP status + 23 if error reading the HTTP data length + 24 if error reading the HTTP data + 25 if error code from 4G module while waiting for HTTP response + 26 if timeout waiting for HTTP response + 27 if HTTP response data length is zero + */ + uint8_t sendFrameToMeshlium(char* url, + uint16_t port, + uint8_t* data, + uint16_t length); + + + /*! + \brief This function configures FTP parameters and opens the connection + \param uint8_t method: selected HTTP method: Wasp4G::HTTP_GET + Wasp4G::HTTP_HEAD + Wasp4G::HTTP_DELETE + Wasp4G::HTTP_POST + Wasp4G::HTTP_PUT + Wasp4G::HTTP_POST_FRAME + \param char* server: address of FTP server + \param uint16_t port: port of FTP server + \param char* username: authentication user identification string for FTP + \param char* password: authentication password for FTP + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 if error opening the FTP connection + 17 if error setting the transfer type + */ + uint8_t ftpOpenSession( char* server, + uint16_t port, + char* username, + char* password); + + /*! + \brief This function closes the FTP connection + \return 0 if OK; 1 if error + */ + uint8_t ftpCloseSession(); + + + /*! + \brief This function deletes a file in the FTP server + \param ftp_file: file to delete in FTP session + \return 0 if OK; 1 if error + */ + uint8_t ftpDelete(char* ftp_file); + + /*! + \brief This function requests the current working directory in FTP server + \return 0 if OK; 'x' if error + */ + uint8_t ftpGetWorkingDirectory(); + + /*! + \brief This function changes the working directory of the FTP session + \param dirname: destiny directory in FTP server + \return 0 if OK; 'x' if error + */ + uint8_t ftpChangeWorkingDirectory(char* dirname); + + /*! + \brief This function uses PUT to send a file to a FTP server + \param char* ftp_file: destiny file + \param char* sd_file: origin file + \return 0 if OK + 1 if no SD present + 2 if file does not exist + 3 if error opening the file + 4 if error setting the pointer of the file + 5 if error getting the file size + 6 if error opening the PUT connection + 7 if error exiting from the data mode + 8 if error sending data + */ + uint8_t ftpUpload( char* ftp_file, char* sd_file); + + /*! + \brief This function uses GET to read a file from a FTP server + \param char* SD_file: destiny file + \param char* FTP_file: origin file + \return 0 if OK + 1 if server file size is zero + 2 if error reading the file size + 3 if SD not present + 4 if error creating the file in SD + 5 if error opening the file + 6 if error setting the pointer of the file + 7 if error opening the GET connection + 8 if the module returns error code after requesting data + 9 if error getting packet size + 10 if error in packet size mismatch + 11 if error writing SD error + 12 if no more retries getting data + 13 if file size mismatch + */ + uint8_t ftpDownload( char* sd_file, char* ftp_file); + + /*! + \brief This function reads the size of a file in a FTP server + \param char* FTP_file: file + \return '0' if OK, '1' if error + */ + uint8_t ftpFileSize( char* ftp_file); + + + /*! + \brief This function requests OTA + \param char* OTA_server: address of FTP server with OTA files + \param uint16_t OTA_port: port of FTP server with OTA files + \param char* OTA_username: authentication user identification string for FTP + \param char* OTA_password: authentication password for FTP + \return 0 if OK + 1 if SD not present + 2 if error downloading LE910_OTA_FILE (UPGRADE.TXT) + 3 if error opening FTP session + 4 if filename is different to 7 bytes + 5 if no "FILE" pattern found + 6 if "NO_FILE" is the filename + 7 if no "PATH" pattern found + 8 if no "SIZE" pattern found + 9 if no "VERSION" pattern found + 10 if invalid program version number + 11 if file size does not match in UPGRADE.TXT and server + 12 if error downloading binary file: server file size is zero + 13 if error downloading binary file: reading the file size + 14 if error downloading binary file: SD not present + 15 if error downloading binary file: error creating the file in SD + 16 if error downloading binary file: error opening the file + 17 if error downloading binary file: error setting the pointer of the file + 18 if error downloading binary file: error opening the GET connection + 19 if error downloading binary file: error module returns error code after requesting data + 20 if error downloading binary file: error getting packet size + 21 if error downloading binary file: packet size mismatch + 22 if error downloading binary file: error writing SD + 23 if error downloading binary file: no more retries getting data + 24 if error downloading binary file: size mismatch + */ + uint8_t requestOTA(char* OTA_server, + uint16_t OTA_port, + char* OTA_username, + char* OTA_password); + + + /*! + \brief This function configures and opens a socket + \param uint8_t socketId: number of the socket Id + \param bool protocol: 0 for TCP_CLIENT and 1 for UDP_CLIENT + \param char* remote_IP: address of the remote host (IPv6 allowed) + \param uint16_t remote_port: remote host port to contact + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 error getting socket status + 17 Socket with an active data transfer connection + 18 Socket suspended + 19 Socket suspended with pending data + 20 Socket listening + 21 Socket with an incoming connection. Waiting for the user accept or shutdown command + 22 Socket in opening process. The socket is not in Closed state but + still not in Active or Suspended or Suspended with pending data state + 23 if error in Socket Configuration + 24 if error in Socket Configuration Extended 3 + 25 if error sending the open command + 26 if timeout opening the socket + */ + uint8_t openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port); + + /*! + \brief This function configures and opens a socket + \param uint8_t socketId: number of the socket Id + \param bool protocol: 0 for TCP_CLIENT and 1 for UDP_CLIENT + \param char* remote_IP: address of the remote host (IPv6 allowed) + \param uint16_t remote_port: remote host port to contact + \param uint16_t local_port: UDP connections local port + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 error getting socket status + 17 Socket with an active data transfer connection + 18 Socket suspended + 19 Socket suspended with pending data + 20 Socket listening + 21 Socket with an incoming connection. Waiting for the user accept or shutdown command + 22 Socket in opening process. The socket is not in Closed state but + still not in Active or Suspended or Suspended with pending data state + 23 if error in Socket Configuration + 24 if error in Socket Configuration Extended 3 + 25 if error sending the open command + 26 if timeout opening the socket + */ + uint8_t openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port, + uint16_t local_port); + + /*! + \brief This function configures and opens a socket + \param uint8_t socketId: number of the socket Id + \param bool protocol: 0 for TCP and 1 for UDP + \param char* remote_IP: address of the remote host (IPv6 allowed) + \param uint16_t remote_port: remote host port to contact + \param uint16_t local_port: UDP connections local port + \param bool keep_alive: 0 disable, 1 enable + \param uint8_t keep_alive: From 0 (disabled) to 240 minutes + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 error getting socket status + 17 Socket with an active data transfer connection + 18 Socket suspended + 19 Socket suspended with pending data + 20 Socket listening + 21 Socket with an incoming connection. Waiting for the user accept or shutdown command + 22 Socket in opening process. The socket is not in Closed state but + still not in Active or Suspended or Suspended with pending data state + 23 if error in Socket Configuration + 24 if error in Socket Configuration Extended 3 + 25 if error sending the open command + 26 if timeout opening the socket + */ + uint8_t openSocketClient(uint8_t socketId, + bool protocol, + char* remote_IP, + uint16_t remote_port, + uint16_t local_port, + uint8_t keep_alive); + + /*! + \brief This function opens a socket listening for an incoming connection on + a specified port + \param uint8_t socketId: number of the socket Id + \param bool protocol: 0 for TCP_SERVER and 1 for UDP_SERVER + \param uint16_t local_port: TCP/UDP connections local port + \param keep_alive: From 0 (disabled) to 240 minutes + \return 0 if OK + 1: not registered, ME is not currently searching for a new operator to register to + 2: not registered, but ME is currently searching for a new operator to register to + 3: registration denied + 4: unknown + 6: not registered, ME is not currently searching for a new operator to register to + 8: not registered, but ME is currently searching for a new operator to register to + 9: registration denied + 10: unknown + 12: if error setting APN + 13: if error setting login + 14: if error setting password + 15: if error activating GPRS connection + 16: if error getting socket status + 17: if error in Socket Configuration + 18: if protocol input not valid + 19: if error opening the socket + */ + uint8_t openSocketServer(uint8_t socketId, + bool protocol, + uint16_t local_port); + + uint8_t openSocketServer(uint8_t socketId, + bool protocol, + uint16_t local_port, + uint8_t keep_alive); + + + + /*! + \brief This function configures and opens a socket SSL + \param uint8_t socketId: number of the socket Id + \param char* remote_IP: address of the remote host (IPv6 allowed) + \param uint16_t remote_port: remote host port to contact + \return 0 if OK + 1 not registered, ME is not currently searching for a new operator to register to + 2 not registered, but ME is currently searching for a new operator to register to + 3 registration denied + 4 unknown + 6 not registered, ME is not currently searching for a new operator to register to + 8 not registered, but ME is currently searching for a new operator to register to + 9 registration denied + 10 unknown + 12 if error setting APN + 13 if error setting login + 14 if error setting password + 15 if error activating GPRS connection + 16 if error getting SSL Socket Status + 17 if socket disabled + 19 if socket already open + 20 if error opening the socket + 21 if no response from module + */ + uint8_t openSocketSSL( uint8_t socketId, + char* remote_IP, + uint16_t remote_port); + + + /*! + \brief This function closes a socket previously opened + \param uint8_t socketId: number of the socket Id + \return 0 Socket Closed + 1 if error sending the command + 2 if timeout shutting down the socket + */ + uint8_t closeSocketClient(uint8_t socketId); + uint8_t closeSocketServer(uint8_t socketId, uint8_t protocol); + + + /*! + \brief This function closes a SSL socket previously opened + \param uint8_t socketId: number of the socket Id + \return 0 Socket Closed + 1 if error sending the command + 2 if timeout shutting down the socket + */ + uint8_t closeSocketSSL(uint8_t socketId); + + + /*! + \brief This function gets the status of a TCP or UDP socket + \param uint8_t socketId: number of the socket Id + \return 0 if OK; 1 if error + */ + uint8_t getSocketStatus(uint8_t socketId); + uint8_t getAllSocketStatus(); + uint8_t getSocketStatusSSL(uint8_t socketId); + + /*! + \brief This function manages the TCP/UDP socket profiles. If there is an + incoming connection, it is accepted + \param uint32_t wait_time: time to wait for incoming connections + */ + uint8_t manageSockets(); + uint8_t manageSockets(uint32_t wait_time); + + /*! + \brief This function gets info from a TCP or UDP socket + \param uint8_t socketId: number of the socket Id + \return 0 if ok; 1 if error + */ + uint8_t getSocketInfo(uint8_t socketId); + + + /*! + \brief This function sends data through a socket previously opened + \param uint8_t socketId: number of the socket Id + \param uint8_t* data: string with the data + \return 0 if OK + 1 if error checking socket status + 2 if incorrect socket status + 3 if error sending data + 4 if error waiting confirmation from module + 5 if error getting socket status + 6 if timeout getting socket status + */ + uint8_t send(uint8_t socketId, char* data); + + /*! + \brief This function sends data through a socket previously opened + \param uint8_t socketId: number of the socket Id + \param uint8_t* data: buffer with the data + \param uint16_t data_length: length of the data buffer + \return 0 if OK + 1 if error checking socket status + 2 if incorrect socket status + 3 if error sending data + 4 if error waiting confirmation from module + 5 if error getting socket status + 6 if timeout getting socket status + */ + uint8_t send(uint8_t socketId, uint8_t* data, uint16_t data_length); + + /*! + \brief This function sends data through a SSL socket previously opened + \param uint8_t socketId: number of the socket Id + \param uint8_t* data: string with the data + \return 0 if OK + 1 if error checking socket status + 2 if incorrect socket status + 3 if error sending data + 4 if no response from module + 5 if error getting socket status + 6 if timeout waiting for correct socket status + */ + uint8_t sendSSL(uint8_t socketId, char* data); + + + /*! + \brief This function sends data through a SSL socket previously opened + \param uint8_t socketId: number of the socket Id + \param uint8_t* data: buffer with the data + \param uint16_t data_length: length of the data buffer + \return 0 if OK + 1 if error checking socket status + 2 if incorrect socket status + 3 if error sending data + 4 if no response from module + 5 if error getting socket status + 6 if timeout waiting for correct socket status + */ + uint8_t sendSSL(uint8_t socketId, uint8_t* data, uint16_t data_length); + + + /*! + \brief This function read data received in the module + \param uint8_t socketId: number of the socket Id + \return 0 if data received + 1 if no data received + 2 if error getting socket info + 3 if timeout waiting for data + 4 if error receiving data from module + 5 if error parsing length of data + 6 if error reading incoming bytes + */ + uint8_t receive(uint8_t socketId); + + /*! + \brief This function read data received in the module + \param uint8_t socketId: number of the socket Id + \param uint32_t timeout: timeout in ms to wait for response + \return 0 if data received + 1 if no data received + 2 if error getting socket info + 3 if timeout waiting for data + 4 if error receiving data from module + 5 if error parsing length of data + 6 if error reading incoming bytes + */ + uint8_t receive(uint8_t socketId, uint32_t timeout); + + /*! + \brief This function reads data received in the module through SSL socket + \param uint8_t socketId: number of the socket Id + \return 0 if ok + 1 if no answer from module + 2 if SSL socket disconnected + 3 if error code from module + 4 if no response from module + 5 if error parsing length of received data + 6 if error getting received data + 7 if error waiting module confirmation + */ + uint8_t receiveSSL(uint8_t socketId); + + /*! + \brief This function reads data received in the module through SSL socket + \param uint8_t socketId: number of the socket Id + \param uint32_t timeout: timeout in ms to wait for response + \return '0' if ok; 'x' if error + */ + uint8_t receiveSSL(uint8_t socketId, uint32_t timeout); + + + + /*! + \brief This function allows to store, delete and read security data + (Certificate, CAcertificate, private key) into the non-volatile + memory of the module + \param socketId: Secure Socket Identifier (must be 1) + \param action: Action to do: + 0 – Delete data from NVM + 1 – Store data into NVM + 2 – Read data from NVM + \param dataType: + 0 – Certificate + 1 – CA certificate + 2 – RSA Private key + \param data: string with the security data + \return 0 if OK + 1 if error setting security data + 2 if error waiting module confirmation + 3 if error getting security data + 4 if error deleting security data + 5 if invalid action input + */ + uint8_t manageSSL( uint8_t socketId, + uint8_t action, + uint8_t dataType); + + uint8_t manageSSL( uint8_t socketId, + uint8_t action, + uint8_t dataType, + char *data); + + //! Latitude + char _latitude[11]; + + //! Variable : it stores the latitude indicator N: North; S: South + char _latitudeNS; //NS_indicator + + char _longitude[12]; //longitude + + //! Variable : it stores the longitude indicator E: East; W: West + char _longitudeEW; //EW_indicator + + float _altitude; // altitude + char _time[7]; // hhmmss + char _date[7]; // ddmmyy + uint8_t _numSatellites; // satellites in use + uint8_t _fixMode; // satellites in use + float _speedOG; // speed over ground (Km/hr) + char _courseOG[7]; // course over ground ddd.mm + float _hdop; // Horizontal Diluition of Precision + + /*! + \brief Starts the GPS engine with hot start and stand alone mode + \param uint8_t gps_mode: + 0: Pure MS Assisted - Location estimate from the network (MS Assisted mode). + 1: MS Based - Assistance Data from the network (MS Based mode). + 2: MS Assisted Based - Combination of MS-A and MS-B modes, location + estimate computed both at UE and Network. + 3: Autonomous – Autonomous GPS mode of operation. + \param uint8_t reset_mode: + 1 Coldstart + 2 Warmstart + 3 Hotstart + \return 0 if OK + 1 if error setting the reset mode + 2 if error checking current GPS status + 3 if error starting the GPS engine in standalone mode + 4 if error setting NETWORK_UTRAN mode + 5 if error defining the PDP context + 6 if error setting authentication user ID + 7 if error setting authentication password + 8 if error setting socket configuration + 9 if error setting quality of service + 10 if error setting the SLP server + 11 if error setting the supported SUPL version + 12 if error updating terminal information + 13 if error enabling unsolicited response + 14 if error locking context for LCS use + 15 if error enabling GNSS (or GLONASS) + 16 if error in GPS Start Location Service Request + 17 if error checking data connection + 18 if incorrect GPS mode + */ + uint8_t gpsStart(); + uint8_t gpsStart(uint8_t gps_mode); + uint8_t gpsStart(uint8_t gps_mode, uint8_t reset_mode); + + /*! + \brief Stops the GPS engine + \return 0 if OK; 1 if error + */ + uint8_t gpsStop(); + + /*! + \brief Checks GPS signal + \return '1' if GPS status is unknown + '2' if GPS status is not fixed + '3' if GPS status is fixed in 2D mode + '4' if GPS status is fixed in 3D mode + */ + int8_t checkGPS(); + + //! It converts from the NMEA message and indicator to degrees + float convert2Degrees(char* input, char indicator); + + + /*! + \brief It checks if receiver is connected to some satellite until time out + \return '0' if OK; '1' if error + */ + uint8_t waitForSignal(); + + /*! + \brief It checks if receiver is connected to some satellite until time out + \param uint32_t timeout: timeout to fix the satellites defined in seconds + \return '0' if OK; '1' if error + */ + uint8_t waitForSignal(uint32_t timeout); + + + /*! + \brief It checks if receiver is connected to some satellite until time out + \param uint32_t timeout: timeout to fix the satellites defined in seconds + \param float desired_HDOP: Desired HDOP accuracy to wait for signal + \return '0' if OK; '1' if error + */ + uint8_t waitForSignal(uint32_t timeout, float desired_HDOP); + + //! It gets the NMEA string + bool getNMEAString(uint8_t NMEA); + + //! It sets the quality of service of GPS + uint8_t gpsSetQualityOfService( uint32_t horiz_accuracy, + uint16_t vertic_accuracy, + uint16_t rsp_time, + uint32_t age_of_location_info, + uint8_t location_type, + uint8_t nav_profile, + uint8_t velocity_request); + + /*! + \brief This function gets the temperature interval or the temperature value + \return If interval mode selected + -2 Extreme temperature lower bound. + -1 Operating temperature lower bound. + 0 normal temperature. + 1 Operating temperature upper bound. + 2 Extreme temperature upper bound. + -1000 if error + + If temperature value selected return temperature in Celsius + -1000 if error + */ + uint8_t getTemp(); + + /*! + \brief This function gets the RSSI level + \return the value in dBm + 0 if error + */ + uint8_t getRSSI(); + + + /*! + \brief This function gets the packet service network type + \return 0 for GPRS network + 1 for EGPRS network + 2 for WCDMA network + 3 for HSDPA network + 4 for LTE network + 5 for unknown or not registered + -1 if error + */ + uint8_t getNetworkType(); + + //! This function gets the Operator name + uint8_t getOperator(char* answer_storage); + + /*! + \brief This function selects the Wireless Network + \param uint8_t n: it is the WDS-Side Stack used by the TA: + Wasp4G::NETWORK_GSM + Wasp4G::NETWORK_UTRAN + Wasp4G::NETWORK_3GPP + Wasp4G::NETWORK_EUTRAN_ONLY + Wasp4G::NETWORK_GERAN_UTRAN + Wasp4G::NETWORK_GERAN_EUTRAN + Wasp4G::NETWORK_UTRAN_EUTRAN + */ + uint8_t setWirelessNetwork(uint8_t n); + + + /*! + \brief This function gets info from the module + \param uint8_t info_req: + Wasp4G::INFO_HW + Wasp4G::INFO_MANUFACTURER_ID + Wasp4G::INFO_MODEL_ID + Wasp4G::INFO_REV_ID + Wasp4G::INFO_IMEI + Wasp4G::INFO_IMSI + Wasp4G::INFO_ICCID + \return 0 if OK + 1 if error + */ + int8_t getInfo(uint8_t info_req); + + /*! + \brief This function sets the RTC time from 4G network info + \return '0' if OK; '1' if error + */ + uint8_t setTimeFrom4G(); + + /*! + \brief This function sets the apn from operator + \param char* apn: apn from operator + \return void + */ + void set_APN( char* apn); + + /*! + \brief This function sets the apn, login and password from operator + \param char* apn: apn from operator + \param char* login: login from operator + \param char* password: password from operator + \return void + */ + void set_APN( char* apn, char* login, char* password); + + /*! + \brief This function shows the apn, login and password constants + \return '1' on success, '0' if error + */ + void show_APN(); + + //! Print current _errorCode value + void printErrorCode(); + + //! Print error code given as input + void printErrorCode(uint16_t error); + + + /*! + \brief This function sets the SMTP server address, used for E-mail sending. + \param char* address: SMTP server address, string type. This parameter can be either: + - Any valid IP address in the format: xxx.xxx.xxx.xxx + - Any host name to be solved with a DNS query + \return '0' if OK; 'x' if error + */ + uint8_t emailSetServerSMTP(char* address); + + /*! + \brief This function sets the email sender parameters + \param char* address: sender's email address + \param char* user: sender's user address + \param char* password: sender's email password + \return 0 if OK + 1 if error setting the sender address + 2 if error setting the sender user + 3 if error setting the sender password + */ + uint8_t emailSetSender(char* address, char* user, char* password); + + /*! + \brief This function activates context + \param char* user: APN user + \param char* password: APN password + \return '0' if OK; 'x' if error + */ + uint8_t emailActivateContext(char* user, char* password); + + /*! + \brief This function sets the SMTP security and port + \param uint8_t security: Wasp4G::EMAIL_SSL + Wasp4G::EMAIL_NONSSL + \param uint16_t port: port number + \return '0' if OK; 'x' if error + */ + uint8_t emailConfigureSMTP(uint8_t security, uint16_t port); + + /*! + \brief This function sends the email + \param char* address: receiver's email address + \param char* subject: subject of the email + \param char* body: main text message of the email + \return 0 if OK + 1 if error sending mail + 2 if error waiting for module confirmation + */ + uint8_t emailSend(char* address, char* subject, char* body); + + /*! + \brief This function resets the actual e-mail parameters in the NVM of + the module to the default ones. The values reset are: + E-mail User Name + E-mail Password + E-mail Sender Address + E-mail SMTP server + \return '0' if OK; 'x' if error + */ + uint8_t emailReset(); + + /*! + \brief This function saves the actual e-mail parameters in the NVM of the + device. The values reset are: + E-mail User Name + E-mail Password + E-mail Sender Address + E-mail SMTP server + \return '0' if OK; 'x' if error + */ + uint8_t emailSave(); +}; + +extern Wasp4G _4G; + +#endif diff --git a/libraries/Wasp4G/keywords.txt b/libraries/Wasp4G/keywords.txt new file mode 100644 index 0000000..db0c85e --- /dev/null +++ b/libraries/Wasp4G/keywords.txt @@ -0,0 +1,176 @@ +# _4G keywords # + +_4G KEYWORD1 +Wasp4G KEYWORD2 + + +# functions #### +enterPIN KEYWORD2 +checkPIN KEYWORD2 +getInfo KEYWORD2 +checkConnection KEYWORD2 +checkDataConnection KEYWORD2 +getNetworkType KEYWORD2 +getOperator KEYWORD2 +setTimeFrom4G KEYWORD2 +configureSMS KEYWORD2 +http KEYWORD2 +ftpOpenSession KEYWORD2 +ftpUpload KEYWORD2 +ftpCloseSession KEYWORD2 +ftpGetWorkingDirectory KEYWORD2 +ftpChangeWorkingDirectory KEYWORD2 +ftpDelete KEYWORD2 +openSocketClient KEYWORD2 +openSocketSSL KEYWORD2 +openSocketServer KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +manageSSL KEYWORD2 +socketInfo KEYWORD2 +socketStatus KEYWORD2 +sendSSL KEYWORD2 +receiveSSL KEYWORD2 +closeSocketClient KEYWORD2 +closeSocketSSL KEYWORD2 +closeSocketServer KEYWORD2 +gpsStart KEYWORD2 +gpsStop KEYWORD2 +manageSocketData KEYWORD2 +getSocketInfo KEYWORD2 +manageSockets KEYWORD2 +readNewSMS KEYWORD2 +emailReset KEYWORD2 +emailSetServerSMTP KEYWORD2 +emailConfigureSMTP KEYWORD2 +emailSetSender KEYWORD2 +emailSave KEYWORD2 +emailSend KEYWORD2 + + +# attributes #### +_temp KEYWORD2 +_tempInterval KEYWORD2 +_rssi KEYWORD2 +_networkType KEYWORD2 +_incomingType KEYWORD2 +_smsIndex KEYWORD2 +_socketIndex KEYWORD2 +_httpCode KEYWORD2 +_latitude KEYWORD2 +_latitudeNS KEYWORD2 +_longitude KEYWORD2 +_longitudeEW KEYWORD2 +_time KEYWORD2 +_date KEYWORD2 +_numSatellites KEYWORD2 +_hdop KEYWORD2 +_smsStatus KEYWORD2 +_smsNumber KEYWORD2 +_smsDate KEYWORD2 +_smsTime KEYWORD2 +_ftpWorkingDirectory KEYWORD2 +id KEYWORD2 +localIp KEYWORD2 +localPort KEYWORD2 +remoteIp KEYWORD2 +remotePort KEYWORD2 +setWirelessNetwork KEYWORD2 +socketStatusSSL KEYWORD2 +checkConnectionEPS KEYWORD2 +getSocketStatusSSL KEYWORD2 +_altitude KEYWORD2 +_fixMode KEYWORD2 +_speedOG KEYWORD2 +_courseOG KEYWORD2 +getNMEAString KEYWORD2 +gpsSetQualityOfService KEYWORD2 +emailActivateContext KEYWORD2 + + +# Constants #### +UDP LITERAL1 +TCP LITERAL1 +INCOMING_SMS LITERAL1 +INCOMING_IP LITERAL1 +HTTP_GET LITERAL1 +HTTP_HEAD LITERAL1 +HTTP_DELETE LITERAL1 +HTTP_POST LITERAL1 +HTTP_PUT LITERAL1 +HTTP_POST_FRAME LITERAL1 +LE910_INCOMING_SMS LITERAL1 +LE910_INCOMING_IP LITERAL1 +SSL_ACTION_DELETE LITERAL1 +SSL_ACTION_STORE LITERAL1 +SSL_ACTION_READ LITERAL1 +SSL_TYPE_CERT LITERAL1 +SSL_TYPE_CA_CERT LITERAL1 +SSL_TYPE_RSA LITERAL1 +STATUS_CLOSED LITERAL1 +STATUS_CLOSED LITERAL1 +STATUS_SUSPENDED LITERAL1 +STATUS_SUSPENDED_DATA LITERAL1 +STATUS_LISTENING LITERAL1 +STATUS_INCOMING LITERAL1 +STATUS_OPENING LITERAL1 +NETWORK_GSM LITERAL1 +NETWORK_UTRAN LITERAL1 +NETWORK_3GPP LITERAL1 +NETWORK_EUTRAN_ONLY LITERAL1 +NETWORK_GERAN_UTRAN LITERAL1 +NETWORK_GERAN_EUTRAN LITERAL1 +NETWORK_UTRAN_EUTRAN LITERAL1 +GPS_MS_ASSISTED LITERAL1 +GPS_MS_BASED LITERAL1 +GPS_AUTONOMOUS LITERAL1 +INFO_HW LITERAL1 +INFO_MANUFACTURER_ID LITERAL1 +INFO_MODEL_ID LITERAL1 +INFO_REV_ID LITERAL1 +INFO_IMEI LITERAL1 +INFO_IMSI LITERAL1 +INFO_ICCID LITERAL1 +SMS_DELETE_MESSAGE LITERAL1 +SMS_DELETE_ALL_1 LITERAL1 +SMS_DELETE_ALL_2 LITERAL1 +SMS_DELETE_ALL_3 LITERAL1 +SMS_DELETE_ALL_4 LITERAL1 +NETWORK_GPRS LITERAL1 +NETWORK_EGPRS LITERAL1 +NETWORK_WCDMA LITERAL1 +NETWORK_HSDPA LITERAL1 +NETWORK_LTE LITERAL1 +NETWORK_UNKNOWN LITERAL1 +EMAIL_NONSSL LITERAL1 +EMAIL_SSL LITERAL1 +LE910_CHECK_VERSION LITERAL1 +PRINT_LE910 LITERAL1 +LE910_GPRS_APN LITERAL1 +LE910_GPRS_LOGIN LITERAL1 +LE910_GPRS_PASSW LITERAL1 +LE910_ERROR_CME LITERAL1 +LE910_ERROR_CMS LITERAL1 +LE910_ERROR_CODE LITERAL1 +LE910_ERROR LITERAL1 +LE910_OK LITERAL1 +LE910_OTA_FILE LITERAL1 +LE910_RATE LITERAL1 +LE910_GGA LITERAL1 +LE910_GSA LITERAL1 +LE910_GLL LITERAL1 +LE910_VTG LITERAL1 +LE910_RMC LITERAL1 +LE910_GSV LITERAL1 +LE910_DATA_TO_MODULE LITERAL1 +LE910_DATA_FROM_MODULE LITERAL1 +LE910_MAX_DL_PAYLOAD LITERAL1 +STATUS_ACTIVE LITERAL1 + +CONNECTION_1 LITERAL1 +CONNECTION_2 LITERAL1 +CONNECTION_3 LITERAL1 +CONNECTION_4 LITERAL1 +CONNECTION_5 LITERAL1 +CONNECTION_6 LITERAL1 + diff --git a/libraries/Wasp4G/utility/Wasp4G_constants.h b/libraries/Wasp4G/utility/Wasp4G_constants.h new file mode 100755 index 0000000..5403189 --- /dev/null +++ b/libraries/Wasp4G/utility/Wasp4G_constants.h @@ -0,0 +1,482 @@ +/*! \file Wasp4G_contants.h + \brief Header file with constant definitions and flash strings + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascon + Implementation: Alejandro Gállego + + */ + + +#ifndef flash_4g_constants_h +#define flash_4g_constants_h + +/****************************************************************************** + * Includes + *****************************************************************************/ + +#include +#include "Wasp4G_error_codes.h" + + +/****************************************************************************** + * COMMANDS (FLASH Definitions) + ******************************************************************************/ + + +/// table_4G ////////////////////////////////////////////////////////////////// + +const char LE910_string_00[] PROGMEM = "AT+CREG?\r"; //0 +const char LE910_string_01[] PROGMEM = "+CREG: 0,"; //1 +const char LE910_string_02[] PROGMEM = "AT+CGREG?\r"; //2 +const char LE910_string_03[] PROGMEM = "+CGREG: 0,"; //3 +const char LE910_string_04[] PROGMEM = "+CGDCONT=1,"; //4 +const char LE910_string_05[] PROGMEM = "AT#USERID=\"%s\"\r"; //5 +const char LE910_string_06[] PROGMEM = "AT#PASSW=\"%s\"\r"; //6 +const char LE910_string_07[] PROGMEM = "#GPRS"; //7 +const char LE910_string_08[] PROGMEM = "AT#TEMPMON=1\r"; //8 +const char LE910_string_09[] PROGMEM = "#TEMPMEAS: "; //9 +const char LE910_string_10[] PROGMEM = "AT+CSQ\r\n: ,"; //10 +const char LE910_string_11[] PROGMEM = "AT#PSNT?\r"; //11 +const char LE910_string_12[] PROGMEM = "AT#HWREV\r"; //12 +const char LE910_string_13[] PROGMEM = "AT#CGMI\r"; //13 +const char LE910_string_14[] PROGMEM = "AT#CGMM\r"; //14 +const char LE910_string_15[] PROGMEM = "AT#CGMR\r"; //15 +const char LE910_string_16[] PROGMEM = "AT#CGSN\r"; //16 +const char LE910_string_17[] PROGMEM = "AT#CIMI\r"; //17 +const char LE910_string_18[] PROGMEM = "AT#CCID\r"; //18 +const char LE910_string_19[] PROGMEM = "AT+CMEE=1\r"; //19 +const char LE910_string_20[] PROGMEM = "ATE0\r"; //20 +const char LE910_string_21[] PROGMEM = "AT#NITZ=7\r"; //21 +const char LE910_string_22[] PROGMEM = "+CMTI"; //22 +const char LE910_string_23[] PROGMEM = "SRING: "; //23 +const char LE910_string_24[] PROGMEM = "AT+COPS?\r"; //24 +const char LE910_string_25[] PROGMEM = "AT+CCLK?\r"; //25 +const char LE910_string_26[] PROGMEM = "AT#GPRS?\r"; //26 +const char LE910_string_27[] PROGMEM = "GPRS: 1"; //27 +const char LE910_string_28[] PROGMEM = "GPRS: 0"; //28 +const char LE910_string_29[] PROGMEM = "AT+CGDCONT=1,\"IP\",\"%s\"\r"; //29 +const char LE910_string_30[] PROGMEM = "AT%s\"%s\"\r"; //30 +const char LE910_string_31[] PROGMEM = "AT#GPRS=1\r"; //31 +const char LE910_string_32[] PROGMEM = "+IP: \"\r\n"; //32 +const char LE910_string_33[] PROGMEM = "AT+CSQ\r\n: ,"; //33 +const char LE910_string_34[] PROGMEM = "AT#PSNT?: ,\r\n"; //34 +const char LE910_string_35[] PROGMEM = "%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%*c%2hhu%hhd\"";//35 +const char LE910_string_36[] PROGMEM = "AT+CMGL=\"REC UNREAD\"\r"; //36 +const char LE910_string_37[] PROGMEM = "AT#SA=%u,1\r"; //37 +const char LE910_string_38[] PROGMEM = "AT+WS46=%u\r"; //38 +const char LE910_string_39[] PROGMEM = "+CMGL: "; //39 +const char LE910_string_40[] PROGMEM = "+CMGR: "; //40 +const char LE910_string_41[] PROGMEM = "AT+CEREG?\r"; //41 +const char LE910_string_42[] PROGMEM = "+CEREG: 0,"; //42 + +const char* const table_4G[] PROGMEM = +{ + LE910_string_00, //0 + LE910_string_01, //1 + LE910_string_02, //2 + LE910_string_03, //3 + LE910_string_04, //4 + LE910_string_05, //5 + LE910_string_06, //6 + LE910_string_07, //7 + LE910_string_08, //8 + LE910_string_09, //9 + LE910_string_10, //10 + LE910_string_11, //11 + LE910_string_12, //12 + LE910_string_13, //13 + LE910_string_14, //14 + LE910_string_15, //15 + LE910_string_16, //16 + LE910_string_17, //17 + LE910_string_18, //18 + LE910_string_19, //19 + LE910_string_20, //20 + LE910_string_21, //21 + LE910_string_22, //22 + LE910_string_23, //23 + LE910_string_24, //24 + LE910_string_25, //25 + LE910_string_26, //26 + LE910_string_27, //27 + LE910_string_28, //28 + LE910_string_29, //29 + LE910_string_30, //30 + LE910_string_31, //31 + LE910_string_32, //32 + LE910_string_33, //33 + LE910_string_34, //34 + LE910_string_35, //35 + LE910_string_36, //36 + LE910_string_37, //37 + LE910_string_38, //38 + LE910_string_39, //39 + LE910_string_40, //40 + LE910_string_41, //41 + LE910_string_42, //42 +}; + + + + +/// table_PIN ///////////////////////////////////////////////////////////////// + +const char LE910_PIN_00[] PROGMEM = "AT+CPIN?\r"; //0 +const char LE910_PIN_01[] PROGMEM = "READY"; //1 +const char LE910_PIN_02[] PROGMEM = "SIM PIN"; //2 +const char LE910_PIN_03[] PROGMEM = "SIM PUK"; //3 +const char LE910_PIN_04[] PROGMEM = "PH-SIM PIN"; //4 +const char LE910_PIN_05[] PROGMEM = "PH-FSIM PIN"; //5 +const char LE910_PIN_06[] PROGMEM = "PH-FSIM PUK"; //6 +const char LE910_PIN_07[] PROGMEM = "SIM PIN2"; //7 +const char LE910_PIN_08[] PROGMEM = "SIM PUK2"; //8 +const char LE910_PIN_09[] PROGMEM = "PH-NET PIN"; //9 +const char LE910_PIN_10[] PROGMEM = "PH-NET PUK"; //10 +const char LE910_PIN_11[] PROGMEM = "PH-NETSUB PIN"; //11 +const char LE910_PIN_12[] PROGMEM = "PH-NETSUB PUK"; //12 +const char LE910_PIN_13[] PROGMEM = "PH-SP PIN"; //13 +const char LE910_PIN_14[] PROGMEM = "PH-SP PUK"; //14 +const char LE910_PIN_15[] PROGMEM = "PH-CORP PIN"; //15 +const char LE910_PIN_16[] PROGMEM = "PH-CORP PUK"; //16 +const char LE910_PIN_17[] PROGMEM = "+CPIN:"; //17 +const char LE910_PIN_18[] PROGMEM = "AT+CPIN=\"%s\"\r"; //18 +const char LE910_PIN_19[] PROGMEM = "AT+CPIN=\"%s\",\"%s\"\r"; //19 + +const char* const table_PIN[] PROGMEM = +{ + LE910_PIN_00, //0 + LE910_PIN_01, //1 + LE910_PIN_02, //2 + LE910_PIN_03, //3 + LE910_PIN_04, //4 + LE910_PIN_05, //5 + LE910_PIN_06, //6 + LE910_PIN_07, //7 + LE910_PIN_08, //8 + LE910_PIN_09, //9 + LE910_PIN_10, //10 + LE910_PIN_11, //11 + LE910_PIN_12, //12 + LE910_PIN_13, //13 + LE910_PIN_14, //14 + LE910_PIN_15, //15 + LE910_PIN_16, //16 + LE910_PIN_17, //17 + LE910_PIN_18, //18 + LE910_PIN_19, //19 +}; + + +/// table_SMS ///////////////////////////////////////////////////////////////// + +const unsigned long LE910_SMS_TIMEOUT = 60000; // Timeout for SMS functions in miliseconds + +const char LE910_SMS_00[] PROGMEM = "AT+CMGF=1\r"; //0 +const char LE910_SMS_01[] PROGMEM = "AT+CPMS=\"SM\",\"SM\",\"SM\"\r"; //1 +const char LE910_SMS_02[] PROGMEM = "AT+CNMI=2,1,0,0,0\r"; //2 +const char LE910_SMS_03[] PROGMEM = "AT+CMGR=%u\r"; //3 +const char LE910_SMS_04[] PROGMEM = "AT+CMGS=\"%s\"\r"; //4 +const char LE910_SMS_05[] PROGMEM = "AT+CMGD=%u\r"; //5 +const char LE910_SMS_06[] PROGMEM = "AT+CMGD=%u,%u\r"; //6 + +const char* const table_SMS[] PROGMEM = +{ + LE910_SMS_00, //0 + LE910_SMS_01, //1 + LE910_SMS_02, //2 + LE910_SMS_03, //3 + LE910_SMS_04, //4 + LE910_SMS_05, //5 + LE910_SMS_06, //6 +}; + + + +/// table_HTTP //////////////////////////////////////////////////////////////// + +const unsigned long LE910_HTTP_TIMEOUT = 60000; // Timeout for HTTP and HTTPS functions in miliseconds +const unsigned long LE910_HTTP_CONF_TIMEOUT = 15000; // Timeout for HTTP and HTTPS functions in miliseconds + +const char LE910_HTTP_00[] PROGMEM = "AT#HTTPCFG=0,\"%s\",%u\r"; //0 +const char LE910_HTTP_01[] PROGMEM = "AT#HTTPQRY=0,%u,\"%s\"\r"; //1 +const char LE910_HTTP_02[] PROGMEM = "AT#HTTPSND=0,%u,\"%s\",%u\r"; //2 +const char LE910_HTTP_03[] PROGMEM = "#HTTPRING: 0,"; //3 +const char LE910_HTTP_04[] PROGMEM = "AT#HTTPRCV=%u,%u\r"; //4 +const char LE910_HTTP_05[] PROGMEM = "/getpost_frame_parser.php"; //5 +const char LE910_HTTP_06[] PROGMEM = "frame="; //6 + +const char* const table_HTTP[] PROGMEM = +{ + LE910_HTTP_00, //0 + LE910_HTTP_01, //1 + LE910_HTTP_02, //2 + LE910_HTTP_03, //3 + LE910_HTTP_04, //4 + LE910_HTTP_05, //5 + LE910_HTTP_06, //6 +}; + + + +/// table_FTP ///////////////////////////////////////////////////////////////// + +const uint32_t LE910_FTP_TIMEOUT = 60000; // Timeout for FTP and FTPS functions in miliseconds +const uint32_t LE910_FTP_CONF_TIMEOUT = 15000; // Timeout for FTP and FTPS functions in miliseconds + +const char LE910_FTP_00[] PROGMEM = "AT#FTPOPEN=\"%s:%u\",\"%s\",\"%s\",1\r"; // 0 +const char LE910_FTP_01[] PROGMEM = "AT#FTPCLOSE\r"; // 1 +const char LE910_FTP_02[] PROGMEM = "AT#FTPPUT=\"%s\",0\r"; // 2 +const char LE910_FTP_03[] PROGMEM = "AT#FTPGETPKT=\"%s\"\r"; // 3 +const char LE910_FTP_04[] PROGMEM = "AT#FTPTYPE=0\r"; // 4 +const char LE910_FTP_05[] PROGMEM = "AT#FTPFSIZE=\"%s\"\r"; // 5 +const char LE910_FTP_06[] PROGMEM = "AT#FTPRECV=%u\r"; // 6 +const char LE910_FTP_07[] PROGMEM = "#FTPMSG"; // 7 +const char LE910_FTP_08[] PROGMEM = "AT#FTPGETPKT?\r"; // 8 +const char LE910_FTP_09[] PROGMEM = "AT#FTPAPPEXT=%u\r"; // 9 +const char LE910_FTP_10[] PROGMEM = "#FTPGETPKT: %s,0,"; // 10 +const char LE910_FTP_11[] PROGMEM = "+++"; // 11 +const char LE910_FTP_12[] PROGMEM = "NO CARRIER"; // 12 +const char LE910_FTP_13[] PROGMEM = "#FTPRECV: "; // 13 +const char LE910_FTP_14[] PROGMEM = "AT#FTPDELE=\"%s\"\r"; // 14 +const char LE910_FTP_15[] PROGMEM = "AT#FTPPWD\r"; // 15 +const char LE910_FTP_16[] PROGMEM = "AT#FTPLIST\r"; // 16 +const char LE910_FTP_17[] PROGMEM = "AT#FTPCWD=\"%s\"\r"; // 17 + +const char* const table_FTP[] PROGMEM = +{ + LE910_FTP_00, //0 + LE910_FTP_01, //1 + LE910_FTP_02, //2 + LE910_FTP_03, //3 + LE910_FTP_04, //4 + LE910_FTP_05, //5 + LE910_FTP_06, //6 + LE910_FTP_07, //7 + LE910_FTP_08, //8 + LE910_FTP_09, //9 + LE910_FTP_10, //10 + LE910_FTP_11, //11 + LE910_FTP_12, //12 + LE910_FTP_13, //13 + LE910_FTP_14, //14 + LE910_FTP_15, //15 + LE910_FTP_16, //16 + LE910_FTP_17, //17 +}; + + + + +/// table_IP ////////////////////////////////////////////////////////////////// + +const uint32_t LE910_IP_TIMEOUT = 10000; // Timeout for IP functions in miliseconds +const uint32_t LE910_IP_CONF_TIMEOUT = 15000; // Timeout for IP functions in miliseconds + +const char LE910_IP_SOCKET_00[] PROGMEM = "AT#SS=%u\r"; //0 +const char LE910_IP_SOCKET_01[] PROGMEM = "AT#SI=%u\r"; //1 +const char LE910_IP_SOCKET_02[] PROGMEM = "AT#SCFG=%u,%u,%u,%u,%u,%u\r"; //2 +const char LE910_IP_SOCKET_03[] PROGMEM = "AT#SCFGEXT=%u,%u,%u,%u\r"; //3 +const char LE910_IP_SOCKET_04[] PROGMEM = "#SCFGEXT2="; //4 +const char LE910_IP_SOCKET_05[] PROGMEM = "AT#SCFGEXT3=%u,1\r"; //5 +const char LE910_IP_SOCKET_06[] PROGMEM = "AT#SD=%u,%d,%u,\"%s\",0,%u,1\r"; //6 +const char LE910_IP_SOCKET_07[] PROGMEM = "AT#SH=%u\r"; //7 +const char LE910_IP_SOCKET_08[] PROGMEM = "AT#SSENDEXT=%u,%u\r"; //8 +const char LE910_IP_SOCKET_09[] PROGMEM = "#SRECV: %u,"; //9 +const char LE910_IP_SOCKET_10[] PROGMEM = "AT#SSLSECDATA=%u,%u,%u,%u\r"; //10 +const char LE910_IP_SOCKET_11[] PROGMEM = "AT#SSLSECDATA=%u,%u,%u\r"; //11 +const char LE910_IP_SOCKET_12[] PROGMEM = "AT#SSLD=1,%u,\"%s\",0,1\r"; //12 +const char LE910_IP_SOCKET_13[] PROGMEM = "AT#SSLS=%u\r"; //13 +const char LE910_IP_SOCKET_14[] PROGMEM = "AT#SSLSEND=%u\r"; //14 +const char LE910_IP_SOCKET_15[] PROGMEM = "AT#SSLRECV=%u,%u\r"; //15 +const char LE910_IP_SOCKET_16[] PROGMEM = "#SSLRECV: "; //16 +const char LE910_IP_SOCKET_17[] PROGMEM = "TIMEOUT\r\n"; //17 +const char LE910_IP_SOCKET_18[] PROGMEM = "DISCONNECTED\r\n"; //18 +const char LE910_IP_SOCKET_19[] PROGMEM = "AT#SSLH=%u\r"; //19 +const char LE910_IP_SOCKET_20[] PROGMEM = "#SS: "; //20 +const char LE910_IP_SOCKET_21[] PROGMEM = "#SS: ,\r\n"; //21 +const char LE910_IP_SOCKET_22[] PROGMEM = "#SSLS: "; //22 +const char LE910_IP_SOCKET_23[] PROGMEM = "#SSLS: ,\r\n"; //23 +const char LE910_IP_SOCKET_24[] PROGMEM = "#SI: "; //24 +const char LE910_IP_SOCKET_25[] PROGMEM = "#SI: ,\r\n"; //25 +const char LE910_IP_SOCKET_26[] PROGMEM = "AT#SRECV=%u,%u\r"; //26 +const char LE910_IP_SOCKET_27[] PROGMEM = "#SSLSECDATA: "; //27 +const char LE910_IP_SOCKET_28[] PROGMEM = "AT#SCFGEXT=%u,%u,%u,%u,%u\r"; //28 +const char LE910_IP_SOCKET_29[] PROGMEM = "AT#SL=%u,%u,%u,%u\r"; //29 +const char LE910_IP_SOCKET_30[] PROGMEM = "AT#SLUDP=%u,%u,%u\r"; //30 +const char LE910_IP_SOCKET_31[] PROGMEM = "AT#SS\r"; //31 +const char LE910_IP_SOCKET_32[] PROGMEM = "#SS: %u,"; //32 +const char LE910_IP_SOCKET_33[] PROGMEM = "AT#SSLEN=%u,%u\r"; //33 + +const char* const table_IP[] PROGMEM = +{ + LE910_IP_SOCKET_00, //0 + LE910_IP_SOCKET_01, //1 + LE910_IP_SOCKET_02, //2 + LE910_IP_SOCKET_03, //3 + LE910_IP_SOCKET_04, //4 + LE910_IP_SOCKET_05, //5 + LE910_IP_SOCKET_06, //6 + LE910_IP_SOCKET_07, //7 + LE910_IP_SOCKET_08, //8 + LE910_IP_SOCKET_09, //9 + LE910_IP_SOCKET_10, //10 + LE910_IP_SOCKET_11, //11 + LE910_IP_SOCKET_12, //12 + LE910_IP_SOCKET_13, //13 + LE910_IP_SOCKET_14, //14 + LE910_IP_SOCKET_15, //15 + LE910_IP_SOCKET_16, //16 + LE910_IP_SOCKET_17, //17 + LE910_IP_SOCKET_18, //18 + LE910_IP_SOCKET_19, //19 + LE910_IP_SOCKET_20, //20 + LE910_IP_SOCKET_21, //21 + LE910_IP_SOCKET_22, //22 + LE910_IP_SOCKET_23, //23 + LE910_IP_SOCKET_24, //24 + LE910_IP_SOCKET_25, //25 + LE910_IP_SOCKET_26, //26 + LE910_IP_SOCKET_27, //27 + LE910_IP_SOCKET_28, //28 + LE910_IP_SOCKET_29, //29 + LE910_IP_SOCKET_30, //30 + LE910_IP_SOCKET_31, //31 + LE910_IP_SOCKET_32, //32 + LE910_IP_SOCKET_33, //33 +}; + + + + +/// table_GPS ///////////////////////////////////////////////////////////////// + +const char LE910_GPS_00[] PROGMEM = "AT$GPSP=%u\r"; //0 +const char LE910_GPS_01[] PROGMEM = "AT$GPSSLSR=%u,%u,,,,,%u\r"; //1 +const char LE910_GPS_02[] PROGMEM = "AT$GPSR=%u\r"; //2 +const char LE910_GPS_03[] PROGMEM = "$GPSGLO"; //3 +const char LE910_GPS_04[] PROGMEM = "AT$GPSACP\r"; //4 +const char LE910_GPS_05[] PROGMEM = "$GPSNMUN=3,"; //5 +const char LE910_GPS_06[] PROGMEM = "CONNECT\r\n"; //6 +const char LE910_GPS_07[] PROGMEM = "$GPGLL"; //7 +const char LE910_GPS_08[] PROGMEM = "$GPVTG"; //8 +const char LE910_GPS_09[] PROGMEM = "$GPGSA"; //9 +const char LE910_GPS_10[] PROGMEM = "$GPGGA"; //10 +const char LE910_GPS_11[] PROGMEM = "$GPRMC"; //11 +const char LE910_GPS_12[] PROGMEM = "$GPGSV"; //12 +const char LE910_GPS_13[] PROGMEM = "AT$GPSP?\r"; //13 +const char LE910_GPS_14[] PROGMEM = "GPSP: 1"; //14 +const char LE910_GPS_15[] PROGMEM = "$GPSACP: ,"; //15 +const char LE910_GPS_16[] PROGMEM = "\r\n$GPSACP: .,"; //16 +const char LE910_GPS_17[] PROGMEM = "AT$GPSNMUN=3,%u,%u,%u,%u,%u,%u\r"; //17 +const char LE910_GPS_18[] PROGMEM = "+++"; //18 +const char LE910_GPS_19[] PROGMEM = "AT$GPSQOS=%lu,%u,%u,%lu,%u,%u,%u\r"; //19 +const char LE910_GPS_20[] PROGMEM = "AT$SUPLV=%u\r"; //20 +const char LE910_GPS_21[] PROGMEM = "AT$SLP=1,\"supl.nokia.com:7275\"\r"; //21 +const char LE910_GPS_22[] PROGMEM = "AT$LCSTER=1,,,1\r"; //22 +const char LE910_GPS_23[] PROGMEM = "AT$LICLS=1\r"; //23 +const char LE910_GPS_24[] PROGMEM = "AT$LCSLK=1,1\r"; //24 +const char LE910_GPS_25[] PROGMEM = "AT$GPSGLO=1\r"; //25 + +const char* const table_GPS[] PROGMEM = +{ + LE910_GPS_00, //0 + LE910_GPS_01, //1 + LE910_GPS_02, //2 + LE910_GPS_03, //3 + LE910_GPS_04, //4 + LE910_GPS_05, //5 + LE910_GPS_06, //6 + LE910_GPS_07, //7 + LE910_GPS_08, //8 + LE910_GPS_09, //9 + LE910_GPS_10, //10 + LE910_GPS_11, //11 + LE910_GPS_12, //12 + LE910_GPS_13, //13 + LE910_GPS_14, //14 + LE910_GPS_15, //15 + LE910_GPS_16, //16 + LE910_GPS_17, //17 + LE910_GPS_18, //18 + LE910_GPS_19, //19 + LE910_GPS_20, //20 + LE910_GPS_21, //21 + LE910_GPS_22, //22 + LE910_GPS_23, //23 + LE910_GPS_24, //24 + LE910_GPS_25, //25 +}; + + + + +/// table_OTA_LE910 //////////////////////////////////////////////////////////// + +const char LE910_OTA_00[] PROGMEM = "/UPGRADE.TXT"; //0 +const char LE910_OTA_01[] PROGMEM = "NO_FILE"; //1 +const char LE910_OTA_02[] PROGMEM = "FILE:"; //2 +const char LE910_OTA_03[] PROGMEM = "PATH:"; //3 +const char LE910_OTA_04[] PROGMEM = "SIZE:"; //4 +const char LE910_OTA_05[] PROGMEM = "VERSION:"; //5 + +const char* const table_OTA_LE910[] PROGMEM = +{ + LE910_OTA_00, //0 + LE910_OTA_01, //1 + LE910_OTA_02, //2 + LE910_OTA_03, //3 + LE910_OTA_04, //4 + LE910_OTA_05, //5 +}; + + +/// table_EMAIL_LE910 //////////////////////////////////////////////////////////// + +const char LE910_EMAIL_00[] PROGMEM = "AT#ESMTP=\"%s\"\r"; //0 +const char LE910_EMAIL_01[] PROGMEM = "AT#EADDR=\"%s\"\r"; //1 +const char LE910_EMAIL_02[] PROGMEM = "AT#EUSER=\"%s\"\r"; //2 +const char LE910_EMAIL_03[] PROGMEM = "AT#EPASSW=\"%s\"\r"; //3 +const char LE910_EMAIL_04[] PROGMEM = "AT#EMAILD=\"%s\"\r"; //4 +const char LE910_EMAIL_05[] PROGMEM = "AT#SGACT=1,1,\"%s\",\"%s\"\r"; //5 +const char LE910_EMAIL_06[] PROGMEM = "#SGACT: "; //6 +const char LE910_EMAIL_07[] PROGMEM = "AT#SMTPCFG=%u,%i\r"; //7 +const char LE910_EMAIL_08[] PROGMEM = "AT#EMAILD=\"%s\",\"%s\"\r"; //8 +const char LE910_EMAIL_09[] PROGMEM = "AT#ERST\r"; //9 +const char LE910_EMAIL_10[] PROGMEM = "AT#ESAV\r"; //10 + + +const char* const table_EMAIL_LE910[] PROGMEM = +{ + LE910_EMAIL_00, //0 + LE910_EMAIL_01, //1 + LE910_EMAIL_02, //2 + LE910_EMAIL_03, //3 + LE910_EMAIL_04, //4 + LE910_EMAIL_05, //5 + LE910_EMAIL_06, //6 + LE910_EMAIL_07, //7 + LE910_EMAIL_08, //8 + LE910_EMAIL_09, //9 + LE910_EMAIL_10 //10 +}; + + + +#endif diff --git a/libraries/Wasp4G/utility/Wasp4G_error_codes.h b/libraries/Wasp4G/utility/Wasp4G_error_codes.h new file mode 100644 index 0000000..29daf7b --- /dev/null +++ b/libraries/Wasp4G/utility/Wasp4G_error_codes.h @@ -0,0 +1,177 @@ +/*! \file Wasp4G_WASP4G_CME_ERROR_CODEs.h + \brief Definition of the possible error codes + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http:// www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascon + Implementation: Yuri Carmona + + */ + +#ifndef WASP4G_ERRORCODE_H_ +#define WASP4G_ERRORCODE_H_ + +//! ERROR CODES for the Wasp4G library + +//////////////////////////////////////////////////////////////////////////////// +// Syntax: +CME ERROR: +//////////////////////////////////////////////////////////////////////////////// + +// General errors: +#define WASP4G_CME_ERROR_0000 0 // phone failure +#define WASP4G_CME_ERROR_0001 1 // No connection to phone +#define WASP4G_CME_ERROR_0002 2 // phone-adaptor link reserved +#define WASP4G_CME_ERROR_0003 3 // operation not allowed +#define WASP4G_CME_ERROR_0004 4 // operation not supported +#define WASP4G_CME_ERROR_0005 5 // PH-SIM PIN required +#define WASP4G_CME_ERROR_0010 10 // SIM not inserted +#define WASP4G_CME_ERROR_0011 11 // SIM PIN required +#define WASP4G_CME_ERROR_0012 12 // SIM PUK required +#define WASP4G_CME_ERROR_0013 13 // SIM failure +#define WASP4G_CME_ERROR_0014 14 // SIM busy +#define WASP4G_CME_ERROR_0015 15 // SIM wrong +#define WASP4G_CME_ERROR_0016 16 // incorrect password +#define WASP4G_CME_ERROR_0017 17 // SIM PIN2 required +#define WASP4G_CME_ERROR_0018 18 // SIM PUK2 required +#define WASP4G_CME_ERROR_0020 20 // memory full +#define WASP4G_CME_ERROR_0021 21 // invalid index +#define WASP4G_CME_ERROR_0022 22 // not found +#define WASP4G_CME_ERROR_0023 23 // memory failure +#define WASP4G_CME_ERROR_0024 24 // text string too long +#define WASP4G_CME_ERROR_0025 25 // invalid characters in text string +#define WASP4G_CME_ERROR_0026 26 // dial string too long +#define WASP4G_CME_ERROR_0027 27 // invalid characters in dial string +#define WASP4G_CME_ERROR_0030 30 // no network service +#define WASP4G_CME_ERROR_0031 31 // network time-out +#define WASP4G_CME_ERROR_0032 32 // network not allowed - emergency calls only +#define WASP4G_CME_ERROR_0040 40 // network personalization PIN required +#define WASP4G_CME_ERROR_0041 41 // network personalization PUK required +#define WASP4G_CME_ERROR_0042 42 // network subset personalization PIN required +#define WASP4G_CME_ERROR_0043 43 // network subset personalization PUK required +#define WASP4G_CME_ERROR_0044 44 // service provider personalization PIN required +#define WASP4G_CME_ERROR_0045 45 // Service provider personalization PUK required +#define WASP4G_CME_ERROR_0046 46 // corporate personalization PIN required +#define WASP4G_CME_ERROR_0047 47 // corporate personalization PUK required + +// General purpose error: +#define WASP4G_CME_ERROR_0100 100 // unknown +#define WASP4G_CME_ERROR_0770 770 // SIM invalid + +// GPRS related errors to a failure to perform an Attach: +#define WASP4G_CME_ERROR_0103 103 // Illegal MS (#3)* +#define WASP4G_CME_ERROR_0106 106 // Illegal ME (#6)* +#define WASP4G_CME_ERROR_0107 107 // GPRS service not allowed (#7)* +#define WASP4G_CME_ERROR_0111 111 // PLMN not allowed (#11)* +#define WASP4G_CME_ERROR_0112 112 // Location area not allowed (#12)* +#define WASP4G_CME_ERROR_0113 113 // Roaming not allowed in this location area (#13)* + +// GPRS related errors to a failure to Activate a Context and others: +#define WASP4G_CME_ERROR_0132 132 // service option not supported (#32)* +#define WASP4G_CME_ERROR_0133 133 // requested service option not subscribed (#33)* +#define WASP4G_CME_ERROR_0134 134 // service option temporarily out of order (#34)* +#define WASP4G_CME_ERROR_0148 148 // unspecified GPRS error +#define WASP4G_CME_ERROR_0149 149 // PDP authentication failure +#define WASP4G_CME_ERROR_0150 150 // invalid mobile class + +// Easy GPRS® related errors: +#define WASP4G_CME_ERROR_0550 550 // generic undocumented error +#define WASP4G_CME_ERROR_0551 551 // wrong state +#define WASP4G_CME_ERROR_0552 552 // wrong mode +#define WASP4G_CME_ERROR_0553 553 // context already activated +#define WASP4G_CME_ERROR_0554 554 // stack already active +#define WASP4G_CME_ERROR_0555 555 // activation failed +#define WASP4G_CME_ERROR_0556 556 // context not opened +#define WASP4G_CME_ERROR_0557 557 // cannot setup socket +#define WASP4G_CME_ERROR_0558 558 // cannot resolve DN +#define WASP4G_CME_ERROR_0559 559 // time-out in opening socket +#define WASP4G_CME_ERROR_0560 560 // cannot open socket +#define WASP4G_CME_ERROR_0561 561 // remote disconnected or time-out +#define WASP4G_CME_ERROR_0562 562 // connection failed +#define WASP4G_CME_ERROR_0563 563 // tx error +#define WASP4G_CME_ERROR_0564 564 // already listening +#define WASP4G_CME_ERROR_0568 568 // wrong PDP + +// FTP related errors +#define WASP4G_CME_ERROR_0615 615 // FTP not connected +#define WASP4G_CME_ERROR_0623 623 // FTP write data closed +#define WASP4G_CME_ERROR_0643 643 // FTP communication timeout + +// Network survey errors: +#define WASP4G_CME_ERROR_0657 657 // Network survey error (No Carrier)* +#define WASP4G_CME_ERROR_0658 658 // Network survey error (Busy)* +#define WASP4G_CME_ERROR_0659 659 // Network survey error (Wrong request)* +#define WASP4G_CME_ERROR_0660 660 // Network survey error (Aborted)* + +// Supplementary service related error: +#define WASP4G_CME_ERROR_0257 257 // network rejected request +#define WASP4G_CME_ERROR_0258 258 // retry operation +#define WASP4G_CME_ERROR_0259 259 // invalid deflected to number +#define WASP4G_CME_ERROR_0260 260 // deflected to own number +#define WASP4G_CME_ERROR_0261 261 // unknown subscriber +#define WASP4G_CME_ERROR_0262 262 // service not available +#define WASP4G_CME_ERROR_0263 263 // unknown class specified +#define WASP4G_CME_ERROR_0264 264 // unknown network message + +// AT+COPS test command related error: +#define WASP4G_CME_ERROR_0680 680 // LU processing +#define WASP4G_CME_ERROR_0681 681 // Network search aborted +#define WASP4G_CME_ERROR_0682 682 // PTM mode + +// AT+WS46 test command related error: +#define WASP4G_CME_ERROR_0683 683 // Active call state +#define WASP4G_CME_ERROR_0684 684 // SSL already activated + + + +//////////////////////////////////////////////////////////////////////////////// +// Syntax: +CMS ERROR: +//////////////////////////////////////////////////////////////////////////////// +#define WASP4G_CMS_ERROR_0300 300 // ME failure +#define WASP4G_CMS_ERROR_0301 301 // SMS service of ME reserved +#define WASP4G_CMS_ERROR_0302 302 // operation not allowed +#define WASP4G_CMS_ERROR_0303 303 // operation not supported +#define WASP4G_CMS_ERROR_0304 304 // invalid PDU mode parameter +#define WASP4G_CMS_ERROR_0305 305 // invalid text mode parameter +#define WASP4G_CMS_ERROR_0310 310 // SIM not inserted +#define WASP4G_CMS_ERROR_0311 311 // SIM PIN required +#define WASP4G_CMS_ERROR_0312 312 // PH-SIM PIN required +#define WASP4G_CMS_ERROR_0313 313 // SIM failure +#define WASP4G_CMS_ERROR_0314 314 // SIM busy +#define WASP4G_CMS_ERROR_0315 315 // SIM wrong +#define WASP4G_CMS_ERROR_0316 316 // SIM PUK required +#define WASP4G_CMS_ERROR_0317 317 // SIM PIN2 required +#define WASP4G_CMS_ERROR_0318 318 // SIM PUK2 required +#define WASP4G_CMS_ERROR_0320 320 // memory failure +#define WASP4G_CMS_ERROR_0321 321 // invalid memory index +#define WASP4G_CMS_ERROR_0322 322 // memory full +#define WASP4G_CMS_ERROR_0330 330 // SMSC address unknown +#define WASP4G_CMS_ERROR_0331 331 // no network service +#define WASP4G_CMS_ERROR_0332 332 // network time-out +#define WASP4G_CMS_ERROR_0340 340 // no +CNMA acknowledgement expected +#define WASP4G_CMS_ERROR_0500 500 // unknown error + +#define WASP4G_CME_ERROR_1000 1000 // SSL not activated +#define WASP4G_CME_ERROR_1001 1001 // SSL certs and keys wrong or not stored +#define WASP4G_CME_ERROR_1003 1003 // SSL already activated +#define WASP4G_CME_ERROR_1008 1008 // SSL not connected + +#define WASP4G_ERROR_TIMEOUT 65534 // Timeout error when running a command +#define WASP4G_ERROR_MESSAGE 65535 // "ERROR" + + +#endif /* ATI_ERRORCODE_H_ */ diff --git a/libraries/WaspAES/WaspAES.cpp b/libraries/WaspAES/WaspAES.cpp index aba9435..65340e9 100755 --- a/libraries/WaspAES/WaspAES.cpp +++ b/libraries/WaspAES/WaspAES.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.0 * Design: David Gascón * Implementation: Alvaro Gonzalez, Yuri Carmona * diff --git a/libraries/WaspAES/WaspAES.h b/libraries/WaspAES/WaspAES.h index 3a04ffc..06e39c9 100755 --- a/libraries/WaspAES/WaspAES.h +++ b/libraries/WaspAES/WaspAES.h @@ -1,7 +1,7 @@ /*! \file WaspAES.h \brief Library for managing the encryption - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.3 + Version: 3.0 Design: David Gascón Implementation: Alvaro Gonzalez, Yuri Carmona diff --git a/libraries/WaspAES/keywords.txt b/libraries/WaspAES/keywords.txt index 65f8979..25c45ac 100644 --- a/libraries/WaspAES/keywords.txt +++ b/libraries/WaspAES/keywords.txt @@ -15,7 +15,7 @@ printMessage KEYWORD2 sizeOfBlocks KEYWORD2 encrypt KEYWORD2 -AES KEYWORD3 +AES KEYWORD1 #keyschedule# diff --git a/libraries/WaspHash/WaspHash.cpp b/libraries/WaspHash/WaspHash.cpp index ddd4847..f637358 100755 --- a/libraries/WaspHash/WaspHash.cpp +++ b/libraries/WaspHash/WaspHash.cpp @@ -1,7 +1,7 @@ /*! * Library for managing the HASH encryption library * - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Alvaro Gonzalez, Yuri Carmona * diff --git a/libraries/WaspHash/WaspHash.h b/libraries/WaspHash/WaspHash.h index ab6ff6c..e968045 100755 --- a/libraries/WaspHash/WaspHash.h +++ b/libraries/WaspHash/WaspHash.h @@ -1,7 +1,7 @@ /*! \file WaspHash.h \brief Library for managing the HASH encryption library - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alvaro Gonzalez, Yuri Carmona diff --git a/libraries/WaspHash/keywords.txt b/libraries/WaspHash/keywords.txt index 745dc2d..75bdd9f 100644 --- a/libraries/WaspHash/keywords.txt +++ b/libraries/WaspHash/keywords.txt @@ -11,7 +11,7 @@ printMessageDigest KEYWORD2 md5 KEYWORD2 sha KEYWORD2 -HASH KEYWORDS3 +HASH KEYWORD1 #md5# diff --git a/libraries/WaspRSA/WaspRSA.cpp b/libraries/WaspRSA/WaspRSA.cpp index b14d5bd..1b61f31 100755 --- a/libraries/WaspRSA/WaspRSA.cpp +++ b/libraries/WaspRSA/WaspRSA.cpp @@ -1,7 +1,7 @@ /*! \file WaspRSA.cpp * \brief Library for encrypting messages using the RSA algorithm * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Alvaro Gonzalez, Yuri Carmona */ diff --git a/libraries/WaspRSA/WaspRSA.h b/libraries/WaspRSA/WaspRSA.h index 2939633..972f73e 100755 --- a/libraries/WaspRSA/WaspRSA.h +++ b/libraries/WaspRSA/WaspRSA.h @@ -1,7 +1,7 @@ /*! \file WaspRSA.h * \brief Library for encrypting messages using the RSA algorithm * - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Alvaro Gonzalez, Yuri Carmona */ diff --git a/libraries/WaspRSA/keywords.txt b/libraries/WaspRSA/keywords.txt index 0743646..e89a622 100644 --- a/libraries/WaspRSA/keywords.txt +++ b/libraries/WaspRSA/keywords.txt @@ -4,7 +4,7 @@ WaspRSA KEYWORD2 encrypt KEYWORD2 printMessage KEYWORD2 -RSA KEYWORD3 +RSA KEYWORD1 #bignum# diff --git a/libraries/WaspStackEEPROM/WaspStackEEPROM.cpp b/libraries/WaspStackEEPROM/WaspStackEEPROM.cpp index c71ad5f..cb2aac0 100755 --- a/libraries/WaspStackEEPROM/WaspStackEEPROM.cpp +++ b/libraries/WaspStackEEPROM/WaspStackEEPROM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Gustavo Maratuech, Alejandro Gallago */ diff --git a/libraries/WaspStackEEPROM/WaspStackEEPROM.h b/libraries/WaspStackEEPROM/WaspStackEEPROM.h index 1cf8094..7f4b207 100755 --- a/libraries/WaspStackEEPROM/WaspStackEEPROM.h +++ b/libraries/WaspStackEEPROM/WaspStackEEPROM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Author: Gustavo Maratuech, Alejandro Gállego */ diff --git a/libraries/WaspStackEEPROM/keywords.txt b/libraries/WaspStackEEPROM/keywords.txt index c2383e0..55bf60f 100644 --- a/libraries/WaspStackEEPROM/keywords.txt +++ b/libraries/WaspStackEEPROM/keywords.txt @@ -19,4 +19,4 @@ isEmpty KEYWORD2 getStoredFrames KEYWORD2 getMaxFrames KEYWORD2 -stack KEYWORD3 +stack KEYWORD1 diff --git a/libraries/XBee802/WaspXBee802.cpp b/libraries/XBee802/WaspXBee802.cpp index c7ce3f9..71f0120 100755 --- a/libraries/XBee802/WaspXBee802.cpp +++ b/libraries/XBee802/WaspXBee802.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Yuri Carmona */ @@ -81,13 +81,6 @@ void WaspXBee802::init( uint8_t uart_used ) // set protocol and socket used for XBee module protocol=XBEE_802_15_4; uart=uart_used; - - // in the case the XBee is plugged to SOCKET0 it is necessary to make sure - // that the multiplexor is selecting teh XBee module - if(uart_used==SOCKET0) - { - Utils.setMuxSocket0(); - } pos=0; discoveryOptions=0x00; diff --git a/libraries/XBee802/WaspXBee802.h b/libraries/XBee802/WaspXBee802.h index 6e82726..5c1c71e 100755 --- a/libraries/XBee802/WaspXBee802.h +++ b/libraries/XBee802/WaspXBee802.h @@ -1,7 +1,7 @@ /*! \file WaspXBee802.h \brief Library for managing XBee 802.15.4 modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Yuri Carmona diff --git a/libraries/XBee802/keywords.txt b/libraries/XBee802/keywords.txt index a852eaf..0a70ed5 100644 --- a/libraries/XBee802/keywords.txt +++ b/libraries/XBee802/keywords.txt @@ -24,4 +24,4 @@ counterACK KEYWORD2 _payload KEYWORD2 _length KEYWORD2 -xbee802 KEYWORD3 +xbee802 KEYWORD1 diff --git a/libraries/XBee868/WaspXBee868.cpp b/libraries/XBee868/WaspXBee868.cpp index af6a13f..4c9f183 100755 --- a/libraries/XBee868/WaspXBee868.cpp +++ b/libraries/XBee868/WaspXBee868.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Yuri Carmona */ @@ -88,13 +88,6 @@ void WaspXBee868::init( uint8_t uart_used ) protocol=XBEE_868; uart=uart_used; - // in the case the XBee is plugged to SOCKET0 it is necessary to make sure - // that the multiplexor is selecting the XBee module - if(uart_used==SOCKET0) - { - Utils.setMuxSocket0(); - } - pos=0; discoveryOptions=0x00; @@ -596,7 +589,6 @@ uint8_t WaspXBee868::sendXBeePriv(struct packetXBee* packet) // Local variables uint8_t TX[120]; uint8_t counter=0; - uint16_t aux=0; uint8_t protegido=0; uint8_t tipo=0; int8_t error=2; @@ -622,9 +614,7 @@ uint8_t WaspXBee868::sendXBeePriv(struct packetXBee* packet) if( (packet->mode==BROADCAST) || (packet->mode==UNICAST) ) { // set packet length - TX[2]=14+packet->data_length; - - aux=0; + TX[2]=14+packet->data_length; // set Frame Type TX[3]=0x10; diff --git a/libraries/XBee868/WaspXBee868.h b/libraries/XBee868/WaspXBee868.h index 967ac81..9205fdd 100755 --- a/libraries/XBee868/WaspXBee868.h +++ b/libraries/XBee868/WaspXBee868.h @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Yuri Carmona diff --git a/libraries/XBee868/keywords.txt b/libraries/XBee868/keywords.txt index 9f865f0..02d5c9a 100644 --- a/libraries/XBee868/keywords.txt +++ b/libraries/XBee868/keywords.txt @@ -33,4 +33,4 @@ resetReason KEYWORD2 _payload KEYWORD2 _length KEYWORD2 -xbee868 KEYWORD3 +xbee868 KEYWORD1 diff --git a/libraries/XBee868LP/WaspXBee868LP.cpp b/libraries/XBee868LP/WaspXBee868LP.cpp new file mode 100644 index 0000000..c60226b --- /dev/null +++ b/libraries/XBee868LP/WaspXBee868LP.cpp @@ -0,0 +1,979 @@ +/* + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.1 + * Design: David Gascón + * Implementation: Yuri Carmona + */ + + +#ifndef __WPROGRAM_H__ + #include +#endif + +#include "WaspXBee868LP.h" + +/****************************************************************************** + * AT COMMANDS (FLASH Definitions) + ******************************************************************************/ + +/// table_868LP ///////////////////////////////////////////////////////////////// + +const char get_RF_errors_868[] PROGMEM = "7E0004085245520E"; // AT+ER +const char get_good_pack_868[] PROGMEM = "7E0004085247441A"; // AT+GD +const char get_trans_errors_868[] PROGMEM = "7E000408525452FF"; // AT+TR +const char get_availablefreq_868[] PROGMEM = "7E0004085241461E"; // AT+AF +const char set_channelmask_868[] PROGMEM = "7E00080852434D0000000000"; // AT+CM +const char get_channelmask_868[] PROGMEM = "7E00040852434D15"; // AT+CM +const char set_preambleid_868[] PROGMEM = "7E0005085248500000"; // AT+HP +const char get_preambleid_868[] PROGMEM = "7E0004085248500D"; // AT+HP +const char set_to_868[] PROGMEM = "7E00050852544F0000"; // AT+TO +const char get_to_868[] PROGMEM = "7E00040852544F02"; // AT+TO +const char set_network_hops_DM[] PROGMEM = "7E000508524E480000"; // AT+NH +const char get_network_hops_DM[] PROGMEM = "7E000408524E480F"; // AT+NH +const char set_network_delay_DM[] PROGMEM = "7E000508524E4E0000"; // AT+NN +const char get_network_delay_DM[] PROGMEM = "7E000408524E4E09"; // AT+NN +const char set_network_retries_DM[] PROGMEM = "7E000508524D520000"; // AT+MR +const char get_network_retries_DM[] PROGMEM = "7E000408524D5206"; // AT+MR +const char set_retries_DM[] PROGMEM = "7E0005085252520000"; // AT+RR +const char get_retries_DM[] PROGMEM = "7E00040852525201"; // AT+RR +const char set_mult_broadcast[] PROGMEM = "7E000508524D540000"; // AT+MT +const char get_mult_broadcast[] PROGMEM = "7E000408524D5404"; // AT+MT +const char get_channel_RSSI[] PROGMEM = "7E0005085252430000"; // AT+RC +const char get_payload_bytes[] PROGMEM = "7E000408524E5007"; // AT+NP + + +const char* const table_868LP[] PROGMEM= +{ + get_RF_errors_868, // 0 + get_good_pack_868, // 1 + get_trans_errors_868, // 2 + get_availablefreq_868, // 3 + set_channelmask_868, // 4 + get_channelmask_868, // 5 + set_preambleid_868, // 6 + get_preambleid_868, // 7 + set_to_868, // 8 + get_to_868, // 9 + set_network_hops_DM, // 10 + get_network_hops_DM, // 11 + set_network_delay_DM, // 12 + get_network_delay_DM, // 13 + set_network_retries_DM, // 14 + get_network_retries_DM, // 15 + set_retries_DM, // 16 + get_retries_DM, // 17 + set_mult_broadcast, // 18 + get_mult_broadcast, // 19 + get_channel_RSSI, // 20 + get_payload_bytes // 21 +}; + + +/****************************************************************************** + * Class methods + ******************************************************************************/ + +/* + * Function: It initalizes all the necessary variables including its parent's + * variables + * + * Parameters: + * 'protocol_used' : specifies the protocol used in the XBee module + * 'uart_used' : specifies the UART where the data are sent to (SOCKET0 or SOCKET1) + * Returns: void +*/ +void WaspXBee868LP::init( uint8_t uart_used ) +{ + protocol = XBEE_868LP; + uart = uart_used; + + // in the case the XBee is plugged to SOCKET0 it is necessary to make sure + // that the multiplexer is selecting the XBee module + if( uart_used == SOCKET0) + { + Utils.setMuxSocket0(); + } + + // init class variables + data_length = 0; + it = 0; + rxFrameType = 0; + pos=0; + discoveryOptions = 0x00; + + scanTime[0] = SCAN_TIME_DIGIMESH_H; + scanTime[1] = SCAN_TIME_DIGIMESH_L; + encryptMode = 0; + timeRSSI = TIME_RSSI_DIGIMESH; + + frameNext = 0; + replacementPolicy = XBEE_OUT; + + // init flags + error_AT = 2; + error_RX = 2; + error_TX = 2; + + // clear buffers + clearFinishArray(); + clearCommand(); +} + +/* + Function: Read the number of times the RF receiver detected a CRC or length error + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_errorsRF" variable number of times CRC or length error +*/ +uint8_t WaspXBee868LP::getRFerrors() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // get_RF_errors_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[0]))); + + gen_data(buffer); + error=gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _errorsRF + memcpy( &_errorsRF, data, 2 ); + } + return error; +} + +/* + Function: Read the number of good frames with valid MAC headers that are + received on the RF interface + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_goodPackets" variable the number of good frames received +*/ +uint8_t WaspXBee868LP::getGoodPackets() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // get_good_pack_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[1]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _goodPackets + memcpy( &_goodPackets, data, 2 ); + } + return error; +} + + +/* + Function: Read the number of MAC frames that exhaust MAC retries without ever + receiving a MAC acknowledgement message from the adjacent node + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_transmisionErrors" variable the number of MAC frames + that exhaust +*/ +uint8_t WaspXBee868LP::getTransmisionErrors() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + //get_trans_errors_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[2]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _transmisionErrors + memcpy( &_transmisionErrors, data, 2 ); + } + return error; +} + + +/* + * + * name: getAvailableFreq + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::getAvailableFreq() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + //get_availablefreq_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[3]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // module provides a 9-byte payload + // the first byte is 0x00 + // the rest of the bytes are the contents of the command answer: + _availableFreq[0] = data[1]; + _availableFreq[1] = data[2]; + _availableFreq[2] = data[3]; + _availableFreq[3] = data[4]; + _availableFreq[4] = data[5]; + _availableFreq[5] = data[6]; + _availableFreq[6] = data[7]; + _availableFreq[7] = data[8]; + } + return error; +} + + + + +/* + * + * name: setChannelMask + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::setChannelMask( uint8_t* mask ) +{ + int8_t error=2; + error_AT=2; + char buffer[50]; + + // set_channelmask_868LP + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[4]))); + + gen_data(buffer, mask); + gen_checksum(buffer); + error = gen_send(buffer); + + + if( error == 0 ) + { + _channelMask[0] = mask[0]; + _channelMask[1] = mask[1]; + _channelMask[2] = mask[2]; + _channelMask[3] = mask[3]; + } + return error; +} + + +/* + * + * name: getChannelMask + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::getChannelMask() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_channelmask_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[5]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _channelMask[0] = data[0]; + _channelMask[1] = data[1]; + _channelMask[2] = data[2]; + _channelMask[3] = data[3]; + } + return error; +} + + +/* + * + * name: setPreambleID + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::setPreambleID( uint8_t preambleID ) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_preambleid_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[6]))); + + gen_data(buffer, preambleID); + gen_checksum(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _preambleID = preambleID; + } + return error; +} + + +/* + * + * name: getPreambleID + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::getPreambleID() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_preambleid_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[7]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _preambleID = data[0]; + } + return error; +} + + + +/* + * + * name: setTransmitOptions + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::setTransmitOptions( uint8_t newTransmitOption ) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_to_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[8]))); + + gen_data(buffer, newTransmitOption); + gen_checksum(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _transmitOptions = newTransmitOption; + } + return error; +} + + +/* + * + * name: getTransmitOptions + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee868LP::getTransmitOptions() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_to_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[9]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _transmitOptions = data[0]; + } + return error; +} + + + + + +/* + * Function: Send a packet from one XBee to another XBee in API mode + * + * Parameters: + * packet : A struct of packetXBee type + * + * Returns: Integer that determines if there has been any error + * error=2 --> The command has not been executed + * error=1 --> There has been an error while executing the command + * error=0 --> The command has been executed with no errors + * + * --> DIGI's XBee Packet inner structure: + * + * StartDelimiter(1B) + Length(2B) + Frame Data(variable) + Checksum(1B) + * ______________ ___________ __________________ __________ + * | | | | | | | | | + * | 0x7E | + | MSB | LSB | + | Frame Data | + | 1 Byte | + * |______________| |_____|_____| |__________________| |__________| + * +*/ +uint8_t WaspXBee868LP::sendXBeePriv(struct packetXBee* packet) +{ + // Local variables + uint8_t TX[400]; + uint16_t counter = 0; + uint8_t protegido = 0; + uint8_t tipo = 0; + int8_t error = 2; + + clearCommand(); + + // clear TX variable where the frame is going to be filled + memset( TX, 0x00, sizeof(TX) ); + + /* Create the XBee frame */ + TX[0] = 0x7E; + TX[1] = 0x00; + + // set frame ID as 0x01, so response message will be sent + TX[4] = 0x01; + + // init variables + it = 0; + error_AT = 2; + error_TX = 2; + + + if( (packet->mode==BROADCAST) || (packet->mode==UNICAST) ) + { + // set fragment length for 'Transmit Request' frames (0x10) + TX[1] = ((14+packet->data_length)>>8)&0xFF; + TX[2] = (14+packet->data_length)&0xFF; + + TX[3] = 0x10; // frame Type + tipo = 18; // number of header bytes + + // set 64-Destination Address + if(packet->mode == BROADCAST) + { + // set BROADCAST address + TX[5] = 0x00; + TX[6] = 0x00; + TX[7] = 0x00; + TX[8] = 0x00; + TX[9] = 0x00; + TX[10] = 0x00; + TX[11] = 0xFF; + TX[12] = 0xFF; + } + else if(packet->mode==UNICAST) + { + // set chosen address in setDestinationParams function + TX[5] = packet->macDH[0]; + TX[6] = packet->macDH[1]; + TX[7] = packet->macDH[2]; + TX[8] = packet->macDH[3]; + TX[9] = packet->macDL[0]; + TX[10] = packet->macDL[1]; + TX[11] = packet->macDL[2]; + TX[12] = packet->macDL[3]; + } + + // set frame bytes + TX[13] = 0xFF; + TX[14] = 0xFE; + TX[15] = 0x00; // if set to 0, the BH parameter will be set + TX[16] = 0x00; // if the this field is 0, then the TO parameter will be used + it = 0; + + // generate RF Data payload which is composed by [Api header]+[Data] + genDataPayload(packet,TX,17); + + // set checksum + TX[packet->data_length+17] = getChecksum(TX); + } + else // CLUSTER Type (Explicit Addressing Command Frame) + { + // set fragment length for 'Explicit Addressing Command' frames (0x11) + TX[1] = ((20+packet->data_length)>>8)&0xFF; + TX[2] = (20+packet->data_length)&0xFF; + + // set frame ID + TX[3] = 0x11; + + tipo = 24; // number of header bytes + TX[5] = packet->macDH[0]; + TX[6] = packet->macDH[1]; + TX[7] = packet->macDH[2]; + TX[8] = packet->macDH[3]; + TX[9] = packet->macDL[0]; + TX[10] = packet->macDL[1]; + TX[11] = packet->macDL[2]; + TX[12] = packet->macDL[3]; + + TX[13] = 0xFF; + TX[14] = 0xFE; + TX[15] = packet->SD; + TX[16] = packet->DE; + TX[17] = 0x00; + TX[18] = packet->CID[0]; + TX[19] = packet->PID[0]; + TX[20] = packet->PID[1]; + TX[21] = 0x00; + TX[22] = 0x00; + it = 0; + + // generate RF Data payload which is composed by [Api header]+[Data] + genDataPayload(packet,TX,23); + + // set checksum + TX[packet->data_length+23] = getChecksum(TX); + } + + // Generate the escaped API frame (it is necessary because AP=2) + gen_frame_ap2( packet, TX, protegido, tipo); + + // switch MUX in case SOCKET1 is used + if( uart==SOCKET1 ) + { + Utils.setMuxSocket1(); + } + + // send frame through correspondent UART + counter = 0; + while( counter < ( packet->data_length + tipo + protegido ) ) + { + // print byte through correspondent UART + printByte( TX[counter], uart); + counter++; + } + + counter = 0; + + // read XBee's answer to TX request + error_TX = txZBStatusResponse(); + error = error_TX; + + packet->deliv_status = delivery_status; + packet->discov_status = discovery_status; + packet->true_naD[0] = true_naD[0]; + packet->true_naD[1] = true_naD[1]; + packet->retries = retries_sending; + + return error; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// DigiMesh methods +//////////////////////////////////////////////////////////////////////////////// + + +/* + Function: Set the maximum number of hops expected to be seen in a network route + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the NH command + Parameters: + nhops: maximum number of hops (1-0xFF) +*/ +uint8_t WaspXBee868LP::setNetworkHops(uint8_t nhops) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_hops_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[10]))); + + gen_data(buffer,nhops); + gen_checksum(buffer); + error=gen_send(buffer); + + if(!error) + { + _networkHops = nhops; + } + return error; +} + +/* + Function: Read the maximum number of hops expected to be seen in a network route + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "networkHops" variable max number of hops +*/ +uint8_t WaspXBee868LP::getNetworkHops() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_hops_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[11]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _networkHops = data[0]; + } + return error; +} + + + +/* + Function: Set the maximum random number of network delay slots before + rebroadcasting a network packet + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the NN command + Parameters: + dslots: maximum number of delay slots (0-0x0A) +*/ +uint8_t WaspXBee868LP::setNetworkDelaySlots(uint8_t dslots) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_delay_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[12]))); + gen_data(buffer,dslots); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + _netDelaySlots = dslots; + } + return error; +} + +/* + Function: Read the maximum random number of network delay slots before + rebroadcasting a network packet + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "netDelaySlots" variable max random number of net + delay slots +*/ +uint8_t WaspXBee868LP::getNetworkDelaySlots() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_delay_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[13]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _netDelaySlots = data[0]; + } + return error; +} + + + +/* + Function: Set the maximum number of network packet delivery attempts + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the MR command + Parameters: + mesh: maximum number of attempts (0-7) +*/ +uint8_t WaspXBee868LP::setMeshNetworkRetries(uint8_t mesh) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[14]))); + gen_data(buffer,mesh); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + _meshNetRetries = mesh; + } + return error; +} + +/* + Function: Read the maximum number of network packet delivery attempts + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "meshNetRetries" variable max number of net packet + delivery attempts +*/ +uint8_t WaspXBee868LP::getMeshNetworkRetries() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[15]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _meshNetRetries = data[0]; + } + return error; +} + + + + +/* + * setRetries + * + * Set the maximum number of MAC level packet delivery attempts for unicasts. + * If RR is non-zero packets sent from the radio will request an acknowledgement, + * and can be resent up to RR times if no acknowledgements are received. + * + * Returns: Integer that determines if there has been any error + * error=2 --> The command has not been executed + * error=1 --> There has been an error while executing the command + * error=0 --> The command has been executed with no errors + * + * Values: Change the RR command + * Parameters: + * retry: number of retries (0x00-0x0F). Default=0x0A +*/ +uint8_t WaspXBee868LP::setRetries(uint8_t retry) +{ + int8_t error = 2; + error_AT = 2; + + // set_retries_DM + char buffer[20]; + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[16]))); + + gen_data(buffer,retry); + gen_checksum(buffer); + error = gen_send(buffer); + + if(!error) + { + _retries = retry; + } + return error; +} + +/* + Function: Get the retries that specifies the RR command + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "retries" variable the number of retries +*/ +uint8_t WaspXBee868LP::getRetries() +{ + int8_t error = 2; + char buffer[20]; + error_AT = 2; + + //get_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[17]))); + if( buffer == NULL ) return 1; + + gen_data(buffer); + error = gen_send(buffer); + + + if(!error) + { + _retries = data[0]; + } + return error; +} + + +/* + Function: Specifies the number of additional broadcast retransmissions + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the MT command + Parameters: + mtrans: number of additional broadcast retransmissions (Range: 0x00-0x0F). + Default: 0x03 +*/ +uint8_t WaspXBee868LP::setMultipleBroadcast(uint8_t mtrans) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_mult_broadcast_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[18]))); + + gen_data(buffer,mtrans); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + multipleBroadcast=mtrans; + } + return error; +} + +/* + Function: Gets the number of additional broadcast retransmissions + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Executes the MT command +*/ +uint8_t WaspXBee868LP::getMultipleBroadcast() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_mult_broadcast_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[19]))); + + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + multipleBroadcast=data[0]; + } + return error; +} + + +/* + Function: Reads the DBM level of the designated channel + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "channelRSSI" variable the DBM level of the designated channel + Parameters: + channel --> The channel to get the DBM value +*/ +uint8_t WaspXBee868LP::getChannelRSSI(uint8_t channel) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_channel_RSSI_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[20]))); + + gen_data(buffer,channel); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + channelRSSI=data[1]; + } + return error; +} + + +/* + Function: Get the bytes that can be used in the payload + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Executes the NP command. Stores in global "maxPayloadBytes" variable + the max Payload +*/ +uint8_t WaspXBee868LP::getPayloadBytes() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_payload_bytes_868 + strcpy_P(buffer, (char*)pgm_read_word(&(table_868LP[21]))); + + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + maxPayloadBytes[0]=data[0]; + maxPayloadBytes[1]=data[1]; + } + return error; +} + + + +/// Pre-instantiate object +WaspXBee868LP xbee868LP = WaspXBee868LP(); diff --git a/libraries/XBee868LP/WaspXBee868LP.h b/libraries/XBee868LP/WaspXBee868LP.h new file mode 100644 index 0000000..07e1fd9 --- /dev/null +++ b/libraries/XBee868LP/WaspXBee868LP.h @@ -0,0 +1,385 @@ +/*! \file WaspXBee868LP.h + \brief Library for managing XBee 868LP modules + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.1 + Design: David Gascón + Implementation: Yuri Carmona + */ + +#ifndef WaspXBee868LP_h +#define WaspXBee868LP_h + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Definitions + ******************************************************************************/ + +//! Transmit Options +#define TO_DIGIMESH 0xC0 // (only 80k firmware) +#define TO_POINT_TO_MULTIPOINT 0x40 + + +/****************************************************************************** + * Class + ******************************************************************************/ + +//! WaspXBee868LP Class +/*! + WaspXBee868LP Class defines all the variables and functions used to manage + XBee-PRO 868LP modules. It inherits from 'WaspXBeeCore' class + the necessary functions, variables and definitions + */ +class WaspXBee868LP : public WaspXBeeCore +{ + +public: + + //! class constructor + /*! It does nothing + \param void + \return void + */ + WaspXBee868LP() + { + // clear library buffers + memset( nodeID, 0x00, sizeof(nodeID) ); + memset( linkKey, 0x00, sizeof(linkKey) ); + }; + + + ///////////////////////////// Methods /////////////////////////////////// + + //! It initializes the necessary variables + /*! It initalizes all the necessary variables + \param uint8_t uart_used : specifies the UART to be used: SOCKET0 or SOCKET1 + \return void + */ + void init( uint8_t uart_used ); + + //! It gets the REceived Error Count + /*! This count is incremented whenever a packet is received which contained + * integrity errors of some sort. Once the number reaches 0xFFFF, further + * events will not be counted. The counter can be reset to any 16-bit value + * by appending a hexadecimal parameter to the command. + * + * It stores in global 'errorsRF' variable the number of times the RF + * receiver detected a CRC or length error + \return '0' on success, '1' otherwise + */ + uint8_t getRFerrors(); + + //! It gets Good Packets Received + /*! This count is incremented whenever a good frame with a valid MAC header + * is received on the RF interface. Once the number reaches 0xFFFF, further + * events will not be counted. The counter can be reset to any 16-bit value + * by appending a hexadecimal parameter to the command. + * It stores in global '_goodPackets' variable the number of good frames with + * valid MAC headers that are received on the RF interface + \return '0' on success, '1' otherwise + */ + uint8_t getGoodPackets(); + + + //! It gets the Transmission Errors (AT+TR) + /*! This count is incremented whenever a MAC transmission attempt exhausts + * all MAC retries without ever receiving a MAC acknowledgment message from + * the destination node. Once the number reaches 0xFFFF, further events will + * not be counted. The counter can be reset to any 16-bit value by appending + * a hexadecimal parameter to the command. + * The value is stored in '_transmisionErrors' variable + \return '0' on success, '1' otherwise + */ + uint8_t getTransmisionErrors(); + + + //! It gets the available frequencies (AT+AF) + /*! This read only command can be queried to return a bitfield of the + * frequencies that are available in the module’s region of operation + * This command returns a bitfield. Each bit corresponds to a physical + * channel. Channels are spaced 400 kHz apart: + * Bit 0 – 902.400 MHZ + * Bit 1 – 902.800 MHZ + * ... + * Bit 31 – 914.800 MHZ + * ... + * Bit 63 – 927.600 MHZ + * + * Range: + * 0x1FFFFFF to 0x00FFFFFFFFFFFFFFFF + * + * Default: + * USA/Canada: 0x00FFFFFFFFFFFFFFFF (channels 0 – 63) + * Australia: 0x00FFFFFFFE00000000 (channels 33 – 63) + * Brazil: 0x00FFFFFFFE00000FFF (channels 0-11, 33 – 63) + * Singapore: 0x00FFE00000000000 + * + * The value read from the module is stored in _availableFreq + \return '0' on success, '1' otherwise + */ + uint8_t getAvailableFreq(); + + + //! It allows channels to be selectively enabled or disabled (AT+CM) + /*! This is useful to avoid using frequencies that experience unacceptable + * levels of RF interference. + * This command is a bitfield. Each bit in the bitfield corresponds to a + * frequency as defined in the Available Frequencies (AF) command. When a + * bit in the Channel Mask and the corresponding bit in the Available + * Frequencies are both set to 1 then that physical channel may be chosen by + * the module as an active channel for communication. + * + * Range: + * 0x1FFFFFF to 0x00FFFFFFFFFFFFFFFF + * Default: + * 0xFFFFFFFFFFF7FFFF (Channel 19: 910.000MHZ is disabled by default) + \parameter uint32_t mask: new mask value to be set + \return '0' on success, '1' otherwise + */ + uint8_t setChannelMask( uint8_t mask[8] ); + uint8_t getChannelMask(); + + + //! It gets the Minimum Frequency Count (AT+MF) + /*! This read only command can be queried to determine the minimum number + * of channels that must be enabled with the CM command for proper operation + * in the modules region of operation. + * Range: + * 1 to 50 + * Default: + * USA/Canada: 25 + * Australia: 25 + * Brazil: 25 + * Singapore: 11 + * + \return '0' on success, '1' otherwise + */ + uint8_t getMinFreqCount(); + + + //! It set/gets the Preamble ID (AT+HP) + /*! The preamble ID for which module communicates. Only modules with + * matching preamble IDs can communicate with each other. Different preamble + * IDs minimize interference between multiple sets of modules operating in + * the same vicinity. When receiving a packet this is checked before the + * network ID, as it is encoded in the preamble, and the network ID is + * encoded in the MAC header. + * The value set/get is stored in _preambleID attribute + * Range: 0 to 7 + * Default: 0 + \return '0' on success, '1' otherwise + */ + uint8_t setPreambleID( uint8_t preambleID ); + uint8_t getPreambleID(); + + + + //! It set/gets the Transmit Options (AT+TO) + /*! This command defines transmission options for all packets originating + * from this radio. These options can be overridden on a packet-by-packet + * basis by using the TxOptions field of the API TxRequest frames. + * The value set/get is stored in _transmitOptions attribute + * Bitmap: + * Bit 6,7: Delivery Method -> b'00 + * b'01 - Point-Multipoint + * b’11 - DigiMesh (N/A on 10k product) + * Bit 5: reserved + * Bit 4: reserved + * Bit 3: Trace Route -> Enable a Trace Route on all DigiMesh API packets + * Bit 2: NACK -> Enable a NACK messages on all DigiMesh API packets + * Bit 1: Disable RD -> Disable Route Discovery on all DigiMesh unicasts + * Bit 0: Disable ACK -> Disable acknowledgments on all unicasts + * Default: + * 0x40 (10k firmware) + * 0xC0 (200k firmware) + * + \return '0' on success, '1' otherwise + */ + uint8_t setTransmitOptions( uint8_t newTransmitOption ); + uint8_t getTransmitOptions(); + + + //! It sends a packet to other XBee modules + /*! + \param struct packetXBee* packet : the function gets the needed information + to send the packet from it + \return '0' on success, '1' otherwise + */ + uint8_t sendXBeePriv(struct packetXBee* packet); + + + //! It sets/gets Network Hops (AT+NH) + /*! The maximum number of hops expected to be seen in a network route. This + * value doesn't limit the number of hops allowed, but it is used to + * calculate timeouts waiting for network acknowledgments + \param uint8_t nhops: parameter to set + \return '0' on success, '1' otherwise + */ + uint8_t setNetworkHops(uint8_t nhops); + uint8_t getNetworkHops(); + + + //! It sets/gets the Network Delay Slots (AT+NN) + /*! Set or read the maximum random number of network delay slots before + * rebroadcasting a network packet + \param uint8_t dslots: range [0-0x0A] + \return '0' on success, '1' otherwise + */ + uint8_t setNetworkDelaySlots(uint8_t dslots); + uint8_t getNetworkDelaySlots(); + + + //! It sets/gets Mesh Unicast Retries (AT+MR) + /*! The maximum number of network packet delivery attempts. If MR is + * non-zero, packets sent will request a network acknowledgment, and can be + * resent up to MR+1 times if no acknowledgments are received. We recommend + * setting this value to 1. If this parameter is set to 0, then network ACKs + * are disabled. Routes can be found initially, but will never be repaired + * if a route fails. + \remarks supported in the 200k variant only. + \param uint8_t mesh : the maximum number of network packet delivery attempts + (range [0-7]) + \return '0' on success, '1' otherwise + */ + uint8_t setMeshNetworkRetries(uint8_t mesh); + uint8_t getMeshNetworkRetries(); + + + //!It sets/gets teh Unicast Mac Retries (AT+RR) + /*! The maximum number of MAC level packet delivery attempts for unicasts. + * If RR is non-zero packets sent from the radio will request an + * acknowledgment, and can be resent up to RR times if no acknowledgments + * are received. + \param uint8_t retry: the number of retries to be set (0 to 7) + \return '0' on success, '1' otherwise + */ + uint8_t setRetries(uint8_t retry); + uint8_t getRetries(); + + //! It sets the number of additional broadcast retransmissions + /*! + \param uint8_t mtrans : specifies the number of additional broadcast + retransmissions (range [0x00-0x0F]) + \return '0' on success, '1' otherwise + */ + uint8_t setMultipleBroadcast(uint8_t mtrans); + + //! It gets the number of additional broadcast retransmissions + /*! + It stores in global 'multipleBroadcast' variable the number of additional + broadcast retransmissions + \return '0' on success, '1' otherwise + */ + uint8_t getMultipleBroadcast(); + + //! It gets the DBM level of the designated channel + /*! + It stores in global 'channelRSSI' variable the DBM level of the designated + channel + \param uint8_t channel : the channel where to get the DBM level (range [0-11]) + \return '0' on success, '1' otherwise + */ + uint8_t getChannelRSSI(uint8_t channel); + + //! It gets the bytes that can be used in the payload + /*! + It stores in global 'maxPayloadBytes' variable the bytes that can be used + in the payload + \return '0' on success, '1' otherwise + */ + uint8_t getPayloadBytes(); + + + ///////////////////////////// Attributes /////////////////////////////////// + + //! Variable: the number of times the RF receiver detected a CRC or length error + uint16_t _errorsRF; + + //! Variable: the number of good frames with valid MAC headers that are + //! received on the RF interface + uint16_t _goodPackets; + + //! Variable: the number of MAC frames that exhaust MAC retries without + //! ever receiving a MAC acknowledgement message from the adjacent node + uint16_t _transmisionErrors; + + //! Variable: frequencies that are available in the module’s region of + //! operation + uint8_t _availableFreq[8]; + + //! Variable: Channel mask + uint8_t _channelMask[4]; + + //! Variable: Minimum Frequency Count + uint8_t _minFreqCount; + + //! Variable: Minimum Frequency Count + uint8_t _preambleID; + + //! Variable: Transmit Options + uint8_t _transmitOptions; + + //! Variable : the maximum number of hops expected to be seen in a network + //! route (range [1-0xFF]) + uint8_t _networkHops; + + //! Variable : the maximum random number of network delay slots before + //! rebroadcasting a network packet (range [0-0x0A]) + uint8_t _netDelaySlots; + + //! Variable : the maximum number of network packet delivery attempts (range [0-7]) + uint8_t _meshNetRetries; + + /*! Variable : the maximum number of MAC level packet deliveryn attempts for + * unicasts. + */ + uint8_t _retries; + + //! Variable : the number of additional broadcast retransmissions (range [0x00-0x0F]) + /*! + */ + uint8_t multipleBroadcast; + + //! Variable : the DBM level of the designated channel + /*! + */ + uint8_t channelRSSI; + + //! Variable : Max payload to be used for transmission + /*! + */ + uint8_t maxPayloadBytes[2]; + + +}; + + +// define the extern object (it is defined in cpp) +extern WaspXBee868LP xbee868LP; + +#endif diff --git a/libraries/XBee868LP/keywords.txt b/libraries/XBee868LP/keywords.txt new file mode 100644 index 0000000..2186640 --- /dev/null +++ b/libraries/XBee868LP/keywords.txt @@ -0,0 +1,46 @@ +_errorsRF KEYWORD2 +_goodPackets KEYWORD2 +_transmisionErrors KEYWORD2 +_availableFreq KEYWORD2 +_channelMask KEYWORD2 +_minFreqCount KEYWORD2 +_preambleID KEYWORD2 +_transmitOptions KEYWORD2 +_networkHops KEYWORD2 +_netDelaySlots KEYWORD2 +_meshNetRetries KEYWORD2 +_retries KEYWORD2 +multipleBroadcast KEYWORD2 +channelRSSI KEYWORD2 +maxPayloadBytes KEYWORD2 + +getAvailableFreq KEYWORD2 +getChannelMask KEYWORD2 +getChannelRSSI KEYWORD2 +getGoodPackets KEYWORD2 +getMeshNetworkRetries KEYWORD2 +getMultipleBroadcast KEYWORD2 +getNetworkDelaySlots KEYWORD2 +getPayloadBytes KEYWORD2 +getNetworkHops KEYWORD2 +getPreambleID KEYWORD2 +getRetries KEYWORD2 +getRFerrors KEYWORD2 +getTransmisionErrors KEYWORD2 +getTransmitOptions KEYWORD2 +init KEYWORD2 +sendXBeePriv KEYWORD2 +setMeshNetworkRetries KEYWORD2 +setChannelMask KEYWORD2 +setNetworkDelaySlots KEYWORD2 +setMultipleBroadcast KEYWORD2 +setNetworkHops KEYWORD2 +setPreambleID KEYWORD2 +setRetries KEYWORD2 +setTransmitOptions KEYWORD2 +WaspXBee868LP KEYWORD2 + +xbee868LP KEYWORD1 + +TO_DIGIMESH LITERAL1 +TO_POINT_TO_MULTIPOINT LITERAL1 diff --git a/libraries/XBee900/WaspXBee900.cpp b/libraries/XBee900/WaspXBee900.cpp index 51644a3..d066d74 100755 --- a/libraries/XBee900/WaspXBee900.cpp +++ b/libraries/XBee900/WaspXBee900.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Yuri Carmona */ @@ -73,13 +73,6 @@ void WaspXBee900::init( uint8_t uart_used ) protocol=XBEE_900; uart=uart_used; - // in the case the XBee is plugged to SOCKET0 it is necessary to make sure - // that the multiplexor is selecting teh XBee module - if(uart_used==SOCKET0) - { - Utils.setMuxSocket0(); - } - data_length=0; it=0; rxFrameType=0; @@ -336,8 +329,7 @@ uint8_t WaspXBee900::sendXBeePriv(struct packetXBee* packet) { // Local variables uint8_t TX[120]; - uint8_t counter=0; - uint16_t aux=0; + uint8_t counter=0; uint8_t protegido=0; uint8_t tipo=0; int8_t error=2; @@ -364,8 +356,7 @@ uint8_t WaspXBee900::sendXBeePriv(struct packetXBee* packet) { // set fragment length for 'Transmit Request' frames (0x10) TX[2]=14+packet->data_length; - - aux=0; + TX[3]=0x10; // frame Type tipo=18; diff --git a/libraries/XBee900/WaspXBee900.h b/libraries/XBee900/WaspXBee900.h index 701c804..30816b2 100755 --- a/libraries/XBee900/WaspXBee900.h +++ b/libraries/XBee900/WaspXBee900.h @@ -1,7 +1,7 @@ /*! \file WaspXBee900.h \brief Library for managing 900MHz modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Yuri Carmona */ diff --git a/libraries/XBee900/keywords.txt b/libraries/XBee900/keywords.txt index 26a648f..49d32d2 100644 --- a/libraries/XBee900/keywords.txt +++ b/libraries/XBee900/keywords.txt @@ -22,4 +22,4 @@ supplyVoltage KEYWORD2 _payload KEYWORD2 _length KEYWORD2 -xbee900 KEYWORD3 +xbee900 KEYWORD1 diff --git a/libraries/XBee900HP/WaspXBee900HP.cpp b/libraries/XBee900HP/WaspXBee900HP.cpp new file mode 100755 index 0000000..7bfaa6b --- /dev/null +++ b/libraries/XBee900HP/WaspXBee900HP.cpp @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascón + * Implementation: Yuri Carmona + */ + + +#ifndef __WPROGRAM_H__ + #include +#endif + +#include "WaspXBee900HP.h" + +/****************************************************************************** + * AT COMMANDS (FLASH Definitions) + ******************************************************************************/ + +/// table_900HP ///////////////////////////////////////////////////////////////// + +const char get_RF_errors_900[] PROGMEM = "7E0004085245520E"; // AT+ER +const char get_good_pack_900[] PROGMEM = "7E0004085247441A"; // AT+GD +const char get_trans_errors_900[] PROGMEM = "7E000408525452FF"; // AT+TR +const char get_availablefreq_900[] PROGMEM = "7E0004085241461E"; // AT+AF +const char set_channelmask_900[] PROGMEM = "7E000C0852434D000000000000000000"; // AT+CM +const char get_channelmask_900[] PROGMEM = "7E00040852434D15"; // AT+CM +const char get_minFreqCount_900[] PROGMEM = "7E000408524D4612"; // AT+MF +const char set_preambleid_900[] PROGMEM = "7E0005085248500000"; // AT+HP +const char get_preambleid_900[] PROGMEM = "7E0004085248500D"; // AT+HP +const char set_to_900[] PROGMEM = "7E00050852544F0000"; // AT+TO +const char get_to_900[] PROGMEM = "7E00040852544F02"; // AT+TO +const char set_network_hops_DM[] PROGMEM = "7E000508524E480000"; // AT+NH +const char get_network_hops_DM[] PROGMEM = "7E000408524E480F"; // AT+NH +const char set_network_delay_DM[] PROGMEM = "7E000508524E4E0000"; // AT+NN +const char get_network_delay_DM[] PROGMEM = "7E000408524E4E09"; // AT+NN +const char set_network_retries_DM[] PROGMEM = "7E000508524D520000"; // AT+MR +const char get_network_retries_DM[] PROGMEM = "7E000408524D5206"; // AT+MR +const char set_retries_DM[] PROGMEM = "7E0005085252520000"; // AT+RR +const char get_retries_DM[] PROGMEM = "7E00040852525201"; // AT+RR + + +const char* const table_900HP[] PROGMEM= +{ + get_RF_errors_900, // 0 + get_good_pack_900, // 1 + get_trans_errors_900, // 2 + get_availablefreq_900, // 3 + set_channelmask_900, // 4 + get_channelmask_900, // 5 + get_minFreqCount_900, // 6 + set_preambleid_900, // 7 + get_preambleid_900, // 8 + set_to_900, // 9 + get_to_900, // 10 + set_network_hops_DM, // 11 + get_network_hops_DM, // 12 + set_network_delay_DM, // 13 + get_network_delay_DM, // 14 + set_network_retries_DM, // 15 + get_network_retries_DM, // 16 + set_retries_DM, // 17 + get_retries_DM, // 18 + +}; + + +/****************************************************************************** + * Class methods + ******************************************************************************/ + +/* + * Function: It initalizes all the necessary variables including its parent's + * variables + * + * Parameters: + * 'protocol_used' : specifies the protocol used in the XBee module + * 'uart_used' : specifies the UART where the data are sent to (SOCKET0 or SOCKET1) + * Returns: void +*/ +void WaspXBee900HP::init( uint8_t uart_used ) +{ + protocol = XBEE_900HP; + uart = uart_used; + + // in the case the XBee is plugged to SOCKET0 it is necessary to make sure + // that the multiplexer is selecting the XBee module + if( uart_used == SOCKET0) + { + Utils.setMuxSocket0(); + } + + // init class variables + data_length = 0; + it = 0; + rxFrameType = 0; + pos=0; + discoveryOptions = 0x00; + + scanTime[0] = SCAN_TIME_DIGIMESH_H; + scanTime[1] = SCAN_TIME_DIGIMESH_L; + encryptMode = 0; + timeRSSI = TIME_RSSI_DIGIMESH; + + frameNext = 0; + replacementPolicy = XBEE_OUT; + + // init flags + error_AT = 2; + error_RX = 2; + error_TX = 2; + + // clear buffers + clearFinishArray(); + clearCommand(); +} + +/* + Function: Read the number of times the RF receiver detected a CRC or length error + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_errorsRF" variable number of times CRC or length error +*/ +uint8_t WaspXBee900HP::getRFerrors() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // get_RF_errors_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[0]))); + + gen_data(buffer); + error=gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _errorsRF + memcpy( &_errorsRF, data, 2 ); + } + return error; +} + +/* + Function: Read the number of good frames with valid MAC headers that are + received on the RF interface + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_goodPackets" variable the number of good frames received +*/ +uint8_t WaspXBee900HP::getGoodPackets() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // get_good_pack_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[1]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _goodPackets + memcpy( &_goodPackets, data, 2 ); + } + return error; +} + + +/* + Function: Read the number of MAC frames that exhaust MAC retries without ever + receiving a MAC acknowledgement message from the adjacent node + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "_transmisionErrors" variable the number of MAC frames + that exhaust +*/ +uint8_t WaspXBee900HP::getTransmisionErrors() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + //get_trans_errors_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[2]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // copy data[0-1] to _transmisionErrors + memcpy( &_transmisionErrors, data, 2 ); + } + return error; +} + + +/* + * + * name: getAvailableFreq + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::getAvailableFreq() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + //get_availablefreq_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[3]))); + + gen_data(buffer); + error = gen_send(buffer); + + if(!error) + { + // module provides a 9-byte payload + // the first byte is 0x00 + // the rest of the bytes are the contents of the command answer: + _availableFreq[0] = data[1]; + _availableFreq[1] = data[2]; + _availableFreq[2] = data[3]; + _availableFreq[3] = data[4]; + _availableFreq[4] = data[5]; + _availableFreq[5] = data[6]; + _availableFreq[6] = data[7]; + _availableFreq[7] = data[8]; + } + return error; +} + + + + +/* + * + * name: setChannelMask + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::setChannelMask( uint8_t* mask ) +{ + int8_t error=2; + error_AT=2; + char buffer[50]; + + // set_channelmask_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[4]))); + + gen_data(buffer, mask); + gen_checksum(buffer); + error = gen_send(buffer); + + + if( error == 0 ) + { + _channelMask[0] = mask[0]; + _channelMask[1] = mask[1]; + _channelMask[2] = mask[2]; + _channelMask[3] = mask[3]; + _channelMask[4] = mask[4]; + _channelMask[5] = mask[5]; + _channelMask[6] = mask[6]; + _channelMask[7] = mask[7]; + } + return error; +} + + +/* + * + * name: getChannelMask + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::getChannelMask() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_channelmask_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[5]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + // module provides a 9-byte payload + // the first byte is 0x00 + // the rest of the bytes are the contents of the command answer: + _channelMask[0] = data[1]; + _channelMask[1] = data[2]; + _channelMask[2] = data[3]; + _channelMask[3] = data[4]; + _channelMask[4] = data[5]; + _channelMask[5] = data[6]; + _channelMask[6] = data[7]; + _channelMask[7] = data[8]; + } + return error; +} + + + + + +/* + * + * name: getMinFreqCount + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::getMinFreqCount() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_minFreqCount_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[6]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _minFreqCount = data[0]; + } + return error; +} + + + + + +/* + * + * name: setPreambleID + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::setPreambleID( uint8_t preambleID ) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_preambleid_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[7]))); + + gen_data(buffer, preambleID); + gen_checksum(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _preambleID = preambleID; + } + return error; +} + + +/* + * + * name: getPreambleID + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::getPreambleID() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_preambleid_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[8]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _preambleID = data[0]; + } + return error; +} + + + +/* + * + * name: setTransmitOptions + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::setTransmitOptions( uint8_t newTransmitOption ) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_to_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[9]))); + + gen_data(buffer, newTransmitOption); + gen_checksum(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _transmitOptions = newTransmitOption; + } + return error; +} + + +/* + * + * name: getTransmitOptions + * @param void + * @return '0' if ok, '1' otherwise + * + */ +uint8_t WaspXBee900HP::getTransmitOptions() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_to_900 + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[10]))); + + gen_data(buffer); + error = gen_send(buffer); + + if( error == 0 ) + { + _transmitOptions = data[0]; + } + return error; +} + + + + + +/* + * Function: Send a packet from one XBee to another XBee in API mode + * + * Parameters: + * packet : A struct of packetXBee type + * + * Returns: Integer that determines if there has been any error + * error=2 --> The command has not been executed + * error=1 --> There has been an error while executing the command + * error=0 --> The command has been executed with no errors + * + * --> DIGI's XBee Packet inner structure: + * + * StartDelimiter(1B) + Length(2B) + Frame Data(variable) + Checksum(1B) + * ______________ ___________ __________________ __________ + * | | | | | | | | | + * | 0x7E | + | MSB | LSB | + | Frame Data | + | 1 Byte | + * |______________| |_____|_____| |__________________| |__________| + * +*/ +uint8_t WaspXBee900HP::sendXBeePriv(struct packetXBee* packet) +{ + // Local variables + uint8_t TX[400]; + uint16_t counter = 0; + uint8_t protegido = 0; + uint8_t tipo = 0; + int8_t error = 2; + + clearCommand(); + + // clear TX variable where the frame is going to be filled + memset( TX, 0x00, sizeof(TX) ); + + /* Create the XBee frame */ + TX[0] = 0x7E; + TX[1] = 0x00; + + // set frame ID as 0x01, so response message will be sent + TX[4] = 0x01; + + // init variables + it = 0; + error_AT = 2; + error_TX = 2; + + + if( (packet->mode==BROADCAST) || (packet->mode==UNICAST) ) + { + // set fragment length for 'Transmit Request' frames (0x10) + TX[1] = ((14+packet->data_length)>>8)&0xFF; + TX[2] = (14+packet->data_length)&0xFF; + + TX[3] = 0x10; // frame Type + tipo = 18; // number of header bytes + + // set 64-Destination Address + if(packet->mode == BROADCAST) + { + // set BROADCAST address + TX[5] = 0x00; + TX[6] = 0x00; + TX[7] = 0x00; + TX[8] = 0x00; + TX[9] = 0x00; + TX[10] = 0x00; + TX[11] = 0xFF; + TX[12] = 0xFF; + } + else if(packet->mode==UNICAST) + { + // set chosen address in setDestinationParams function + TX[5] = packet->macDH[0]; + TX[6] = packet->macDH[1]; + TX[7] = packet->macDH[2]; + TX[8] = packet->macDH[3]; + TX[9] = packet->macDL[0]; + TX[10] = packet->macDL[1]; + TX[11] = packet->macDL[2]; + TX[12] = packet->macDL[3]; + } + + // set frame bytes + TX[13] = 0xFF; + TX[14] = 0xFE; + TX[15] = 0x00; // if set to 0, the BH parameter will be set + TX[16] = 0x00; // if the this field is 0, then the TO parameter will be used + it = 0; + + // generate RF Data payload which is composed by [Api header]+[Data] + genDataPayload(packet,TX,17); + + // set checksum + TX[packet->data_length+17] = getChecksum(TX); + } + else // CLUSTER Type (Explicit Addressing Command Frame) + { + // set fragment length for 'Explicit Addressing Command' frames (0x11) + TX[1] = ((20+packet->data_length)>>8)&0xFF; + TX[2] = (20+packet->data_length)&0xFF; + + // set frame ID + TX[3] = 0x11; + + tipo = 24; // number of header bytes + TX[5] = packet->macDH[0]; + TX[6] = packet->macDH[1]; + TX[7] = packet->macDH[2]; + TX[8] = packet->macDH[3]; + TX[9] = packet->macDL[0]; + TX[10] = packet->macDL[1]; + TX[11] = packet->macDL[2]; + TX[12] = packet->macDL[3]; + + TX[13] = 0xFF; + TX[14] = 0xFE; + TX[15] = packet->SD; + TX[16] = packet->DE; + TX[17] = 0x00; + TX[18] = packet->CID[0]; + TX[19] = packet->PID[0]; + TX[20] = packet->PID[1]; + TX[21] = 0x00; + TX[22] = 0x00; + it = 0; + + // generate RF Data payload which is composed by [Api header]+[Data] + genDataPayload(packet,TX,23); + + // set checksum + TX[packet->data_length+23] = getChecksum(TX); + } + + // Generate the escaped API frame (it is necessary because AP=2) + gen_frame_ap2( packet, TX, protegido, tipo); + + // switch MUX in case SOCKET1 is used + if( uart==SOCKET1 ) + { + Utils.setMuxSocket1(); + } + + // send frame through correspondent UART + counter = 0; + while( counter < ( packet->data_length + tipo + protegido ) ) + { + // print byte through correspondent UART + printByte( TX[counter], uart); + counter++; + } + + counter = 0; + + // read XBee's answer to TX request + error_TX = txZBStatusResponse(); + error = error_TX; + + packet->deliv_status = delivery_status; + packet->discov_status = discovery_status; + packet->true_naD[0] = true_naD[0]; + packet->true_naD[1] = true_naD[1]; + packet->retries = retries_sending; + + return error; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// DigiMesh methods +//////////////////////////////////////////////////////////////////////////////// + + +/* + Function: Set the maximum number of hops expected to be seen in a network route + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the NH command + Parameters: + nhops: maximum number of hops (1-0xFF) +*/ +uint8_t WaspXBee900HP::setNetworkHops(uint8_t nhops) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_hops_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[11]))); + + gen_data(buffer,nhops); + gen_checksum(buffer); + error=gen_send(buffer); + + if(!error) + { + _networkHops = nhops; + } + return error; +} + +/* + Function: Read the maximum number of hops expected to be seen in a network route + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "networkHops" variable max number of hops +*/ +uint8_t WaspXBee900HP::getNetworkHops() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_hops_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[12]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _networkHops = data[0]; + } + return error; +} + + + +/* + Function: Set the maximum random number of network delay slots before + rebroadcasting a network packet + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the NN command + Parameters: + dslots: maximum number of delay slots (0-0x0A) +*/ +uint8_t WaspXBee900HP::setNetworkDelaySlots(uint8_t dslots) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_delay_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[13]))); + gen_data(buffer,dslots); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + _netDelaySlots = dslots; + } + return error; +} + +/* + Function: Read the maximum random number of network delay slots before + rebroadcasting a network packet + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "netDelaySlots" variable max random number of net + delay slots +*/ +uint8_t WaspXBee900HP::getNetworkDelaySlots() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_delay_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[14]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _netDelaySlots = data[0]; + } + return error; +} + + + +/* + Function: Set the maximum number of network packet delivery attempts + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the MR command + Parameters: + mesh: maximum number of attempts (0-7) +*/ +uint8_t WaspXBee900HP::setMeshNetworkRetries(uint8_t mesh) +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // set_network_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[15]))); + gen_data(buffer,mesh); + gen_checksum(buffer); + error=gen_send(buffer); + + if(error==0) + { + _meshNetRetries = mesh; + } + return error; +} + +/* + Function: Read the maximum number of network packet delivery attempts + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "meshNetRetries" variable max number of net packet + delivery attempts +*/ +uint8_t WaspXBee900HP::getMeshNetworkRetries() +{ + int8_t error=2; + error_AT=2; + char buffer[20]; + + // get_network_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[16]))); + gen_data(buffer); + error=gen_send(buffer); + + if(error==0) + { + _meshNetRetries = data[0]; + } + return error; +} + + + + +/* + * setRetries + * + * Set the maximum number of MAC level packet delivery attempts for unicasts. + * If RR is non-zero packets sent from the radio will request an acknowledgement, + * and can be resent up to RR times if no acknowledgements are received. + * + * Returns: Integer that determines if there has been any error + * error=2 --> The command has not been executed + * error=1 --> There has been an error while executing the command + * error=0 --> The command has been executed with no errors + * + * Values: Change the RR command + * Parameters: + * retry: number of retries (0x00-0x0F). Default=0x0A +*/ +uint8_t WaspXBee900HP::setRetries(uint8_t retry) +{ + int8_t error = 2; + error_AT = 2; + + // set_retries_DM + char buffer[20]; + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[17]))); + + gen_data(buffer,retry); + gen_checksum(buffer); + error = gen_send(buffer); + + if(!error) + { + _retries = retry; + } + return error; +} + +/* + Function: Get the retries that specifies the RR command + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Stores in global "retries" variable the number of retries +*/ +uint8_t WaspXBee900HP::getRetries() +{ + int8_t error = 2; + char buffer[20]; + error_AT = 2; + + //get_retries_DM + strcpy_P(buffer, (char*)pgm_read_word(&(table_900HP[18]))); + if( buffer == NULL ) return 1; + + gen_data(buffer); + error = gen_send(buffer); + + + if(!error) + { + _retries = data[0]; + } + return error; +} + + + + + +/// Pre-instantiate object +WaspXBee900HP xbee900HP = WaspXBee900HP(); diff --git a/libraries/XBee900HP/WaspXBee900HP.h b/libraries/XBee900HP/WaspXBee900HP.h new file mode 100755 index 0000000..f9be659 --- /dev/null +++ b/libraries/XBee900HP/WaspXBee900HP.h @@ -0,0 +1,337 @@ +/*! \file WaspXBee900HP.h + \brief Library for managing XBee 900 HP modules + + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + http://www.libelium.com + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + Version: 3.0 + Design: David Gascón + Implementation: Yuri Carmona + */ + +#ifndef WaspXBee900HP_h +#define WaspXBee900HP_h + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Definitions + ******************************************************************************/ + +//! Transmit Options +#define TO_DIGIMESH 0xC0 // (only 200k firmware) +#define TO_POINT_TO_MULTIPOINT 0x40 + + +/****************************************************************************** + * Class + ******************************************************************************/ + +//! WaspXBee900HP Class +/*! + WaspXBee900 Class defines all the variables and functions used to manage + XBee 900MHz modules. It inherits from 'WaspXBeeCore' class + the necessary functions, variables and definitions + */ +class WaspXBee900HP : public WaspXBeeCore +{ + +public: + + //! class constructor + /*! It does nothing + \param void + \return void + */ + WaspXBee900HP() + { + // clear library buffers + memset( nodeID, 0x00, sizeof(nodeID) ); + memset( linkKey, 0x00, sizeof(linkKey) ); + }; + + + ///////////////////////////// Methods /////////////////////////////////// + + //! It initializes the necessary variables + /*! It initalizes all the necessary variables + \param uint8_t uart_used : specifies the UART to be used: SOCKET0 or SOCKET1 + \return void + */ + void init( uint8_t uart_used ); + + //! It gets the REceived Error Count + /*! This count is incremented whenever a packet is received which contained + * integrity errors of some sort. Once the number reaches 0xFFFF, further + * events will not be counted. The counter can be reset to any 16-bit value + * by appending a hexadecimal parameter to the command. + * + * It stores in global 'errorsRF' variable the number of times the RF + * receiver detected a CRC or length error + \return '0' on success, '1' otherwise + */ + uint8_t getRFerrors(); + + //! It gets Good Packets Received + /*! This count is incremented whenever a good frame with a valid MAC header + * is received on the RF interface. Once the number reaches 0xFFFF, further + * events will not be counted. The counter can be reset to any 16-bit value + * by appending a hexadecimal parameter to the command. + * It stores in global '_goodPackets' variable the number of good frames with + * valid MAC headers that are received on the RF interface + \return '0' on success, '1' otherwise + */ + uint8_t getGoodPackets(); + + + //! It gets the Transmission Errors (AT+TR) + /*! This count is incremented whenever a MAC transmission attempt exhausts + * all MAC retries without ever receiving a MAC acknowledgment message from + * the destination node. Once the number reaches 0xFFFF, further events will + * not be counted. The counter can be reset to any 16-bit value by appending + * a hexadecimal parameter to the command. + * The value is stored in '_transmisionErrors' variable + \return '0' on success, '1' otherwise + */ + uint8_t getTransmisionErrors(); + + + //! It gets the available frequencies (AT+AF) + /*! This read only command can be queried to return a bitfield of the + * frequencies that are available in the module’s region of operation + * This command returns a bitfield. Each bit corresponds to a physical + * channel. Channels are spaced 400 kHz apart: + * Bit 0 – 902.400 MHZ + * Bit 1 – 902.800 MHZ + * ... + * Bit 31 – 914.800 MHZ + * ... + * Bit 63 – 927.600 MHZ + * + * Range: + * 0x1FFFFFF to 0x00FFFFFFFFFFFFFFFF + * + * Default: + * USA/Canada: 0x00FFFFFFFFFFFFFFFF (channels 0 – 63) + * Australia: 0x00FFFFFFFE00000000 (channels 33 – 63) + * Brazil: 0x00FFFFFFFE00000FFF (channels 0-11, 33 – 63) + * Singapore: 0x00FFE00000000000 + * + * The value read from the module is stored in _availableFreq + \return '0' on success, '1' otherwise + */ + uint8_t getAvailableFreq(); + + + //! It allows channels to be selectively enabled or disabled (AT+CM) + /*! This is useful to avoid using frequencies that experience unacceptable + * levels of RF interference. + * This command is a bitfield. Each bit in the bitfield corresponds to a + * frequency as defined in the Available Frequencies (AF) command. When a + * bit in the Channel Mask and the corresponding bit in the Available + * Frequencies are both set to 1 then that physical channel may be chosen by + * the module as an active channel for communication. + * + * Range: + * 0x1FFFFFF to 0x00FFFFFFFFFFFFFFFF + * Default: + * 0xFFFFFFFFFFF7FFFF (Channel 19: 910.000MHZ is disabled by default) + \parameter uint32_t mask: new mask value to be set + \return '0' on success, '1' otherwise + */ + uint8_t setChannelMask( uint8_t mask[8] ); + uint8_t getChannelMask(); + + + //! It gets the Minimum Frequency Count (AT+MF) + /*! This read only command can be queried to determine the minimum number + * of channels that must be enabled with the CM command for proper operation + * in the modules region of operation. + * Range: + * 1 to 50 + * Default: + * USA/Canada: 25 + * Australia: 25 + * Brazil: 25 + * Singapore: 11 + * + \return '0' on success, '1' otherwise + */ + uint8_t getMinFreqCount(); + + + //! It set/gets the Preamble ID (AT+HP) + /*! The preamble ID for which module communicates. Only modules with + * matching preamble IDs can communicate with each other. Different preamble + * IDs minimize interference between multiple sets of modules operating in + * the same vicinity. When receiving a packet this is checked before the + * network ID, as it is encoded in the preamble, and the network ID is + * encoded in the MAC header. + * The value set/get is stored in _preambleID attribute + * Range: 0 to 7 + * Default: 0 + \return '0' on success, '1' otherwise + */ + uint8_t setPreambleID( uint8_t preambleID ); + uint8_t getPreambleID(); + + + + //! It set/gets the Transmit Options (AT+TO) + /*! This command defines transmission options for all packets originating + * from this radio. These options can be overridden on a packet-by-packet + * basis by using the TxOptions field of the API TxRequest frames. + * The value set/get is stored in _transmitOptions attribute + * Bitmap: + * Bit 6,7: Delivery Method -> b'00 + * b'01 - Point-Multipoint + * b’11 - DigiMesh (N/A on 10k product) + * Bit 5: reserved + * Bit 4: reserved + * Bit 3: Trace Route -> Enable a Trace Route on all DigiMesh API packets + * Bit 2: NACK -> Enable a NACK messages on all DigiMesh API packets + * Bit 1: Disable RD -> Disable Route Discovery on all DigiMesh unicasts + * Bit 0: Disable ACK -> Disable acknowledgments on all unicasts + * Default: + * 0x40 (10k firmware) + * 0xC0 (200k firmware) + * + \return '0' on success, '1' otherwise + */ + uint8_t setTransmitOptions( uint8_t newTransmitOption ); + uint8_t getTransmitOptions(); + + + //! It sends a packet to other XBee modules + /*! + \param struct packetXBee* packet : the function gets the needed information + to send the packet from it + \return '0' on success, '1' otherwise + */ + uint8_t sendXBeePriv(struct packetXBee* packet); + + + //! It sets/gets Network Hops (AT+NH) + /*! The maximum number of hops expected to be seen in a network route. This + * value doesn't limit the number of hops allowed, but it is used to + * calculate timeouts waiting for network acknowledgments + \param uint8_t nhops: parameter to set + \return '0' on success, '1' otherwise + */ + uint8_t setNetworkHops(uint8_t nhops); + uint8_t getNetworkHops(); + + + //! It sets/gets the Network Delay Slots (AT+NN) + /*! Set or read the maximum random number of network delay slots before + * rebroadcasting a network packet + \param uint8_t dslots: range [0-0x0A] + \return '0' on success, '1' otherwise + */ + uint8_t setNetworkDelaySlots(uint8_t dslots); + uint8_t getNetworkDelaySlots(); + + + //! It sets/gets Mesh Unicast Retries (AT+MR) + /*! The maximum number of network packet delivery attempts. If MR is + * non-zero, packets sent will request a network acknowledgment, and can be + * resent up to MR+1 times if no acknowledgments are received. We recommend + * setting this value to 1. If this parameter is set to 0, then network ACKs + * are disabled. Routes can be found initially, but will never be repaired + * if a route fails. + \remarks supported in the 200k variant only. + \param uint8_t mesh : the maximum number of network packet delivery attempts + (range [0-7]) + \return '0' on success, '1' otherwise + */ + uint8_t setMeshNetworkRetries(uint8_t mesh); + uint8_t getMeshNetworkRetries(); + + + //!It sets/gets teh Unicast Mac Retries (AT+RR) + /*! The maximum number of MAC level packet delivery attempts for unicasts. + * If RR is non-zero packets sent from the radio will request an + * acknowledgment, and can be resent up to RR times if no acknowledgments + * are received. + \param uint8_t retry: the number of retries to be set (0 to 7) + \return '0' on success, '1' otherwise + */ + uint8_t setRetries(uint8_t retry); + uint8_t getRetries(); + + + ///////////////////////////// Attributes /////////////////////////////////// + + //! Variable: the number of times the RF receiver detected a CRC or length error + uint16_t _errorsRF; + + //! Variable: the number of good frames with valid MAC headers that are + //! received on the RF interface + uint16_t _goodPackets; + + //! Variable: the number of MAC frames that exhaust MAC retries without + //! ever receiving a MAC acknowledgement message from the adjacent node + uint16_t _transmisionErrors; + + //! Variable: frequencies that are available in the module’s region of + //! operation + uint8_t _availableFreq[8]; + + //! Variable: Channel mask + uint8_t _channelMask[8]; + + //! Variable: Minimum Frequency Count + uint8_t _minFreqCount; + + //! Variable: Minimum Frequency Count + uint8_t _preambleID; + + //! Variable: Transmit Options + uint8_t _transmitOptions; + + //! Variable : the maximum number of hops expected to be seen in a network + //! route (range [1-0xFF]) + uint8_t _networkHops; + + //! Variable : the maximum random number of network delay slots before + //! rebroadcasting a network packet (range [0-0x0A]) + uint8_t _netDelaySlots; + + //! Variable : the maximum number of network packet delivery attempts (range [0-7]) + uint8_t _meshNetRetries; + + /*! Variable : the maximum number of MAC level packet deliveryn attempts for + * unicasts. + */ + uint8_t _retries; + + +}; + + +// define the extern object (it is defined in cpp) +extern WaspXBee900HP xbee900HP; + +#endif diff --git a/libraries/XBee900HP/keywords.txt b/libraries/XBee900HP/keywords.txt new file mode 100755 index 0000000..1ecd62c --- /dev/null +++ b/libraries/XBee900HP/keywords.txt @@ -0,0 +1,23 @@ + +# KEYWORD3 specifies objects +xbee900HP KEYWORD1 + +# KEYWORD2 specifies functions and attributes# +getRFerrors KEYWORD2 +_errorsRF KEYWORD2 +getAvailableFreq KEYWORD2 +_availableFreq KEYWORD2 +setChannelMask KEYWORD2 +getChannelMask KEYWORD2 +_channelMask KEYWORD2 +getMinFreqCount KEYWORD2 +_minFreqCount KEYWORD2 +setPreambleID KEYWORD2 +getPreambleID KEYWORD2 +_preambleID KEYWORD2 +setTransmitOptions KEYWORD2 +getTransmitOptions KEYWORD2 +_transmitOptions KEYWORD2 +writeValues KEYWORD2 + +WaspXBee900HP KEYWORD2 diff --git a/libraries/XBeeDM/WaspXBeeDM.cpp b/libraries/XBeeDM/WaspXBeeDM.cpp index 7ddcc4d..d6da540 100755 --- a/libraries/XBeeDM/WaspXBeeDM.cpp +++ b/libraries/XBeeDM/WaspXBeeDM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Yuri Carmona */ @@ -79,13 +79,6 @@ void WaspXBeeDM::init( uint8_t uart_used ) protocol=DIGIMESH; uart=uart_used; - // in the case the XBee is plugged to SOCKET0 it is necessary to make sure - // that the multiplexor is selecting teh XBee module - if(uart_used==SOCKET0) - { - Utils.setMuxSocket0(); - } - data_length=0; it=0; rxFrameType=0; diff --git a/libraries/XBeeDM/WaspXBeeDM.h b/libraries/XBeeDM/WaspXBeeDM.h index 27c1b66..5f471e0 100755 --- a/libraries/XBeeDM/WaspXBeeDM.h +++ b/libraries/XBeeDM/WaspXBeeDM.h @@ -2,7 +2,7 @@ \brief Library for managing XBee 802.15.4 and 900MHz modules with DIGIMESH firmware in them. - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Yuri Carmona */ diff --git a/libraries/XBeeDM/keywords.txt b/libraries/XBeeDM/keywords.txt index d321286..6b9a742 100644 --- a/libraries/XBeeDM/keywords.txt +++ b/libraries/XBeeDM/keywords.txt @@ -19,7 +19,10 @@ networkHops KEYWORD2 netDelaySlots KEYWORD2 meshNetRetries KEYWORD2 retries KEYWORD2 +setAwakeTime KEYWORD2 +setSleepTime KEYWORD2 +setSleepMode KEYWORD2 _payload KEYWORD2 _length KEYWORD2 -xbeeDM KEYWORD3 +xbeeDM KEYWORD1 diff --git a/libraries/XBeeZB/WaspXBeeZB.cpp b/libraries/XBeeZB/WaspXBeeZB.cpp index 79b00ec..395809b 100755 --- a/libraries/XBeeZB/WaspXBeeZB.cpp +++ b/libraries/XBeeZB/WaspXBeeZB.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, Yuri Carmona */ @@ -64,6 +64,8 @@ const char set_netwk_key_ZB[] PROGMEM = "7E001408524E4B000000000000000000000000 const char set_power_mode_ZB[] PROGMEM = "7E00050852504D0000"; // AT+PM const char get_power_mode_ZB[] PROGMEM = "7E00040852504D08"; // AT+PM const char get_supply_Volt_ZB[] PROGMEM = "7E0004085225562A"; // AT+%V +const char set_coordinator_ZB[] PROGMEM = "7E0005085243450000"; // AT+CE +const char get_coordinator_ZB[] PROGMEM = "7E00040852434500"; // AT+CE @@ -98,7 +100,9 @@ const char* const table_ZB[] PROGMEM = set_netwk_key_ZB, // 26 set_power_mode_ZB, // 27 get_power_mode_ZB, // 28 - get_supply_Volt_ZB // 29 + get_supply_Volt_ZB, // 29 + set_coordinator_ZB, // 30 + get_coordinator_ZB, // 31 }; @@ -117,14 +121,7 @@ void WaspXBeeZB::init( uint8_t uart_used ) { protocol=ZIGBEE; uart=uart_used; - - // in the case the XBee is plugged to SOCKET0 it is necessary to make sure - // that the multiplexor is selecting teh XBee module - if(uart_used==SOCKET0) - { - Utils.setMuxSocket0(); - } - + pos=0; discoveryOptions=0x00; awakeTime[0]=AWAKE_TIME_ZIGBEE_H; @@ -1324,4 +1321,66 @@ void WaspXBeeZB::setKnownDestination(packetXBee* paq, uint8_t* address) } + + +/* + Function: Set/read if this device is a coordinator (1) or not (0) + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Change the NJ command + Parameters: + input: if this device is a coordinator (1) or not (0) +*/ +uint8_t WaspXBeeZB::setCoordinator(uint8_t input) +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // set_coordinator_ZB + strcpy_P(buffer, (char*)pgm_read_word(&(table_ZB[30]))); + + gen_data(buffer,input); + gen_checksum(buffer); + error = gen_send(buffer); + + if (error == 0) + { + coordinatorEnable = input; + } + return error; +} + + + +/* + Function: Read the time that a Coordinator/Router allows nodes to join + Returns: Integer that determines if there has been any error + error=2 --> The command has not been executed + error=1 --> There has been an error while executing the command + error=0 --> The command has been executed with no errors + Values: Executes the NJ command. Stores in global "joinTime" variable the time allowing join +*/ +uint8_t WaspXBeeZB::getCoordinator() +{ + int8_t error = 2; + error_AT = 2; + char buffer[20]; + + // get_coordinator_ZB + strcpy_P(buffer, (char*)pgm_read_word(&(table_ZB[31]))); + + gen_data(buffer); + error = gen_send(buffer); + + if (error == 0) + { + coordinatorEnable = data[0]; + } + return error; +} + + WaspXBeeZB xbeeZB = WaspXBeeZB(); diff --git a/libraries/XBeeZB/WaspXBeeZB.h b/libraries/XBeeZB/WaspXBeeZB.h index f84e7d5..54e4be8 100755 --- a/libraries/XBeeZB/WaspXBeeZB.h +++ b/libraries/XBeeZB/WaspXBeeZB.h @@ -1,7 +1,7 @@ /*! \file WaspXBeeZB.h \brief Library for managing XBee ZigBee modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, Yuri Carmona @@ -330,103 +330,73 @@ class WaspXBeeZB : public WaspXBeeCore */ void setKnownDestination(packetXBee* paq, uint8_t* address); + //! + uint8_t setCoordinator(uint8_t input); + //! + uint8_t getCoordinator(); + /// Variables ///////////////////////////////////////////////////////////// //! Variable : the 16b parent´s network address - /*! - */ uint8_t parentNA[2]; //! Variable : the number of children which can still connect to the current device - /*! - */ uint8_t remainingChildren; //! Variable : the current device type - /*! - */ uint8_t deviceType[4]; //! Variable : the bytes that can be used in the payload - /*! - */ uint8_t maxPayloadBytes[2]; //! Variable : the operating 64-bit PAN ID - /*! - */ uint8_t operating64PAN[8]; //! Variable : the operating 16-bit PAN ID - /*! - */ uint8_t operating16PAN[2]; //! Variable : the maximum hops limit (range [0x00-0xFF]) - /*! - */ uint8_t maxUnicastHops; //! Variable : the maximum number of hops for each broadcast data transmission (range [0x00-0x20]) - /*! - */ uint8_t maxBroadcastHops; //! Variable : the ZigBee Stack profile (range [0-2]) - /*! - */ uint8_t stackProfile; //! Variable : the number of Sleep Periods to not assert XBee pin - /*! - */ uint8_t periodSleep[2]; //! Variable : the time that a Coordinator/Router allows nodes to join (range [0x00-0xFF]) - /*! - */ uint8_t joinTime; //! Variable : the channel verification parameter (range [0-1]) - /*! - */ uint8_t channelVerification; //! Variable : the join notification setting (range [0-1]) - /*! - */ uint8_t joinNotification; //! Variable : the time between consecutive aggregate route broadcast messages (range [0x00-0xFF]) - /*! - */ uint8_t aggregateNotification; //! Variable : information regarding last node join request - /*! - */ uint8_t associationIndication; //! Variable : options for encryption (range [0-2]) - /*! - */ uint8_t encryptOptions; //! Variable : the 128-bit AES encryption key (range [0-0xFFFFFFFFFFFFFFFF]) - /*! - */ uint8_t networkKey[16]; //! Variable : the power mode of the device (range [0-1]) - /*! - */ uint8_t powerMode; //! Variable : the voltage on the Vcc pin - /*! - */ - uint8_t supplyVoltage[2]; + uint8_t supplyVoltage[2]; + + //! Variable : if this device is a coordinator (1) or not (0) + uint8_t coordinatorEnable; }; extern WaspXBeeZB xbeeZB; diff --git a/libraries/XBeeZB/keywords.txt b/libraries/XBeeZB/keywords.txt index 9fc6675..43bbd28 100644 --- a/libraries/XBeeZB/keywords.txt +++ b/libraries/XBeeZB/keywords.txt @@ -54,7 +54,13 @@ encryptOptions KEYWORD2 networkKey KEYWORD2 powerMode KEYWORD2 supplyVoltage KEYWORD2 +setScanningChannels KEYWORD2 +setCoordinator KEYWORD2 +getCoordinator KEYWORD2 +setPAN KEYWORD2 _payload KEYWORD2 _length KEYWORD2 +error_AT KEYWORD2 +coordinatorEnable KEYWORD2 -xbeeZB KEYWORD3 +xbeeZB KEYWORD1 diff --git a/libraries/_3G/Wasp3G.cpp b/libraries/_3G/Wasp3G.cpp index 82d17e8..a128ff9 100644 --- a/libraries/_3G/Wasp3G.cpp +++ b/libraries/_3G/Wasp3G.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.8 + * Version: 3.1 * Design: David Gascón * Implementation: Alejandro Gállego */ @@ -113,6 +113,9 @@ const char XMODEM_SEND[] PROGMEM = "+CRXFILE="; //60 const char CHECK_GPRS[] PROGMEM = "+CGREG?"; //61 const char CHECK_GPRS_RES[] PROGMEM = "+CGREG: 0,"; //62 +const char GET_TIME[] PROGMEM = "+CCLK?"; //63 +const char GET_TIME_RES[] PROGMEM = "+CCLK: "; //64 + const char* const table_MISC[] PROGMEM = { @@ -196,7 +199,10 @@ const char* const table_MISC[] PROGMEM = XMODEM_SEND, //60 CHECK_GPRS, //61 - CHECK_GPRS_RES, //62 + CHECK_GPRS_RES, //62 + + GET_TIME, //63 + GET_TIME_RES, //64 }; @@ -525,6 +531,10 @@ const char HTTP_FRAME_3[] PROGMEM = "\r\nContent-Length: "; //15 const char HTTP_END_GET[] PROGMEM = "0\r\n\r\n"; //16 const char HTTP_END_POST[] PROGMEM = "\r\n\r\nframe="; //17 +const char HTP_SERVER[] PROGMEM = "+CHTPSERV="; //18 +const char HTP_UPDATE[] PROGMEM = "+CHTPUPDATE"; //19 +const char HTP_UPDATE_RES[] PROGMEM = "+CHTPUPDATE: "; //20 + const char* const table_HTTP[] PROGMEM = @@ -549,6 +559,10 @@ const char* const table_HTTP[] PROGMEM = HTTP_FRAME_3, //15 HTTP_END_GET, //16 HTTP_END_POST, //17 + + HTP_SERVER, //18 + HTP_UPDATE, //19 + HTP_UPDATE_RES, //20 }; #endif @@ -749,10 +763,10 @@ int8_t Wasp3G::check3Gconnection(unsigned long time){ if( millis() < previous) previous = millis(); }while (((answer == 2) || (answer == 4) || (answer == 0) || (answer == -1)) && ((millis() - previous) < (time * 1000))); - //#if _3G_debug_mode>0 + #if _3G_debug_mode>0 USB.print(F("Network status: ")); USB.println(answer, DEC); -// #endif + #endif if (((answer != 1) && (answer != 5) && (answer != -1)) || ((millis() - previous) > (time * 1000))) { @@ -894,16 +908,15 @@ int8_t Wasp3G::initHTTP() int8_t Wasp3G::sendHTTPrequest( const char* url, uint16_t port, uint8_t* data, - int length, + uint16_t length, uint8_t method ) { - int8_t answer; - int16_t count; + int8_t answer; char aux_conv[3]; memset( aux_conv, 0x00, sizeof(aux_conv) ); - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_HTTP[0]))); //HTTP_ACT snprintf(buffer_3G, sizeof(buffer_3G), "%s\"%s\",%u", str_aux1, url, port); @@ -1064,7 +1077,7 @@ int8_t Wasp3G::readHTTPresponse(int8_t parse) uint8_t len; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); count = 0; aux = serialRead(_socket); @@ -1099,7 +1112,7 @@ int8_t Wasp3G::readHTTPresponse(int8_t parse) aux = serialRead(_socket); if (aux != -1) { - if (count < BUFFER_SIZE) + if (count < _3G_BUFFER_SIZE) { buffer_3G[count] = aux; count++; @@ -1750,7 +1763,7 @@ void Wasp3G::begin(){ */ void Wasp3G::close(){ closeSerial(_socket); - Utils.setMux(MUX_TO_LOW, MUX_TO_LOW); + Utils.setMux(LOW, LOW); } /* OFF(void) - closes UART1 and powers off the SIM5218 module @@ -2089,7 +2102,7 @@ int8_t Wasp3G::getIMEI(){ int8_t answer,counter; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[13]))); //GET_IMEI strcpy_P(str_aux2, (char*)pgm_read_word(&(table_MISC[14]))); //GET_IMEI_R answer=sendCommand2(str_aux1, str_aux2, ERROR); @@ -2142,7 +2155,7 @@ int8_t Wasp3G::getIMSI(){ unsigned long previous; int8_t counter=0; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[15]))); //GET_IMSI sendCommand1(str_aux1, "\r\n"); previous = millis(); @@ -2196,7 +2209,7 @@ int8_t Wasp3G::manageIncomingData(unsigned long waiting_time){ int16_t a; //counter and auxiliar variable unsigned long previous = 0; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); a=0; strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[57]))); //INCOMING_CALL @@ -2208,7 +2221,7 @@ int8_t Wasp3G::manageIncomingData(unsigned long waiting_time){ // Wait for data serialFlush(_socket); previous = millis(); - while (((millis()-previous) < waiting_time) && (a < BUFFER_SIZE) && (a >= 0)) + while (((millis()-previous) < waiting_time) && (a < _3G_BUFFER_SIZE) && (a >= 0)) { if (serialAvailable(_socket) != 0) { @@ -2389,7 +2402,7 @@ int8_t Wasp3G::readCall(){ uint8_t a = 0; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); previous = millis(); @@ -2821,7 +2834,7 @@ int8_t Wasp3G::readSMS(uint8_t index){ previous = millis(); } - }while ((strstr(buffer_3G, "OK\r\n") == NULL) && ((millis() - previous) < 2000) && (counter < BUFFER_SIZE)); + }while ((strstr(buffer_3G, "OK\r\n") == NULL) && ((millis() - previous) < 2000) && (counter < _3G_BUFFER_SIZE)); buffer_3G[counter-6] = '\0'; #if _3G_debug_mode>0 USB.println(F("")); @@ -2933,7 +2946,7 @@ int8_t Wasp3G::incomingSMS(){ // Condition to avoid an overflow (DO NOT REMOVE) if( millis() < previous) previous = millis(); - }while ((buffer_3G[count-1] != '\r') && ((millis() - previous) < 1000) && (count < BUFFER_SIZE)); + }while ((buffer_3G[count-1] != '\r') && ((millis() - previous) < 1000) && (count < _3G_BUFFER_SIZE)); buffer_3G[count-1] = '\0'; @@ -3018,7 +3031,7 @@ int8_t Wasp3G::takePicture(){ int8_t count; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); digitalWrite(FILTER_ENABLE, LOW); delay(500); @@ -4181,7 +4194,7 @@ int8_t Wasp3G::downloadFile(const char* origin_path, uint8_t destination, unsign } - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Request the file and selects the destination location strcpy_P(str_aux1, (char*)pgm_read_word(&(table_FTP[6]))); //FTP_GET_FILE if (strchr(origin_path, '/') == strrchr(origin_path, '/')) @@ -4406,7 +4419,7 @@ unsigned long Wasp3G::getFTPsize(const char* FTP_file) answer = sendCommand2(buffer_3G, str_aux1, ERROR_CME, FTP_TIMEOUT, SEND_ONCE); previous = millis(); - memset( buffer_3G, '\0', BUFFER_SIZE); + memset( buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_FTP[28]))); //FTP_LIST_END if (answer == 1) { @@ -5299,7 +5312,7 @@ int8_t Wasp3G::getPOP3header(uint8_t index){ answer=sendCommand1(buffer_3G, "From:"); if (answer == 1) { - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); x=0; previous=millis(); @@ -5320,7 +5333,7 @@ int8_t Wasp3G::getPOP3header(uint8_t index){ }while (((buffer_3G[x-1] != 'K') && (buffer_3G[x-2] != 'O')) && ((millis()-previous) < POP3_TIMEOUT) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-4]='\0'; @@ -5415,7 +5428,7 @@ int8_t Wasp3G::getPOP3mail(uint8_t index){ }while ((buffer_3G[x-1] != '\r') && ((millis()-previous) < POP3_TIMEOUT) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-1] = '\0'; @@ -5551,7 +5564,7 @@ int16_t Wasp3G::readURL(const char* url, uint16_t port, const char* HTTP_request changeBaudrate(2400); getIfReady(); - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); delay(1000); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_HTTP[0]))); //HTTP_ACT snprintf(buffer_3G, sizeof(buffer_3G), "%s\"%s\",%u", str_aux1, url, port); @@ -5582,126 +5595,183 @@ int16_t Wasp3G::readURL(const char* url, uint16_t port, const char* HTTP_request return -3; } - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Reads the response from the server ('0' header and answer, '1' only answer from Meshlium) return readHTTPresponse(parse); } -/* setTimebyURL - Sets the time of Waspmote's RTC getting the time from an url +/* setTimebyURL - Sets the time of Waspmote's RTC getting the time from an HTP server * - * This function sets the time of Waspmote's RTC getting the time from an url + * This function sets the time of Waspmote's RTC getting the time from an HTP server * * Returns '1' on success, * '0' if no connection * '-1' if error setting APN, username and password, - * '-2' if error opening a HTTP session, - * '-3' if error receiving data or timeout waiting data, - * '-4' if error changing the baudrate (data received is OK), - * '-5' if unknown error for HTTP, - * '-6' if HTTP task is busy, - * '-7' if fail to resolve server address, - * '-8' if HTTP timeout, - * '-9' if fail to transfer data, - * '-10' if memory error, - * '-11' if invalid parameter, - * '-12' if network error, + * '-2' if error checking the connection + * '-3' if error adding the HTP server + * '-4' if error reading the time from 3G's RTC + * '-5' HTP Unknown error + * '-6' HTP Wrong parameter + * '-7' HTP Wrong date and time calculated + * '-8' HTP Network error * '-15' if error setting APN, username and password with CME_error code available - * '-16' if error opening a HTTP session with CME_error code available - * '-20' if error checking the connection - * '-21' if fail setting the time of the internal RTC of the 3G module */ -int16_t Wasp3G::setTimebyURL(){ +int16_t Wasp3G::setTimebyURL(const char* htp_server, uint16_t htp_port){ + int16_t answer; - uint16_t HTTP_data; char aux_str[20]; - uint8_t len; - char* aux_ptr; uint8_t year, month, date, day_week, hour, minute, second; + int8_t timezone; bool RTC_ant=false; - answer = readURL("pruebas.libelium.com", 80, "GET /rmarandom.php HTTP/1.1\r\nHost: pruebas.libelium.com\r\nContent-Length: 0\r\n\r\n"); - // gets URL from the solicited URL - if ( answer == 1) + uint16_t count=0; + unsigned long previous; + + // Checks the connection + answer = check3Gconnection(90); + if ((answer != 1) && (answer != -1)) { - // checks if the response is OK - if (strstr(buffer_3G, "200 ok") == NULL) - { - // url response its not OK - return -17; + return 0; + } + else if (answer == -1) + { + return -2; + } + + // Configures the operator parameters + answer = initHTTP(); + if (answer != 1) + { + return answer - 4; + } + + + // ADD the HTP server + strcpy_P(str_aux1, (char*)pgm_read_word(&(table_HTTP[18]))); //"+CHTPSERV=" + snprintf(buffer_3G, sizeof(buffer_3G), "%s\"ADD\",\"%s\",%u,1", str_aux1, htp_server, htp_port); + answer=sendCommand2(buffer_3G, OK_RESPONSE, ERROR); + if (answer != 1) + { + return -3; + } + + // Updating date and time using HTP protocol + strcpy_P(str_aux1, (char*)pgm_read_word(&(table_HTTP[19]))); //"+CHTPUPDATE" + strcpy_P(str_aux2, (char*)pgm_read_word(&(table_HTTP[20]))); //"+CHTPUPDATE: " + answer=sendCommand2(str_aux1, str_aux2, ERROR); + if (answer != 1) + { + return answer; + } + delay(100); + answer = serialRead(_socket) - 0x30; + if (answer != 0) + { + #if _3G_debug_mode>0 + USB.print(F("Error HTP: ")); + USB.println(answer, DEC); + #endif + return answer; + } + + strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[63]))); //"+CCLK?" + strcpy_P(str_aux2, (char*)pgm_read_word(&(table_MISC[64]))); //"+CCLK:" + answer=sendCommand2(str_aux1, str_aux2, ERROR); + if (answer != 1) + { + return -4; + } + + count = 0; + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); + previous = millis(); + do{ + while ((serialAvailable(_socket) == 0) && ((millis() - previous) < 5000)) + { + if (millis() < previous) + { + previous = millis(); + } } + buffer_3G[count]=serialRead(_socket); + count++; - // finds the data length - aux_ptr = strstr(buffer_3G, "\r\n\r\n"); - if (aux_ptr == NULL) + if (millis() < previous) { - // url response its not OK - return -18; + previous = millis(); } - - memset(aux_str, '\0', strlen(aux_str)); - aux_ptr += 4; - - strncpy(aux_str, aux_ptr, strchr(aux_ptr, '\r') - aux_ptr); - sscanf(aux_str, "%x", &len); - - aux_ptr = aux_ptr + 3; - - memset(aux_str, '\0', strlen(aux_str)); - strncpy(aux_str, aux_ptr, len); + }while ((buffer_3G[count-1] != '\r') && ((millis() - previous) < 5000) && (count < _3G_BUFFER_SIZE)); + + year = ((buffer_3G[1] - 0x30) * 10) + (buffer_3G[2] - 0x30); + month = ((buffer_3G[4] - 0x30) * 10) + (buffer_3G[5] - 0x30); + date = ((buffer_3G[7] - 0x30) * 10) + (buffer_3G[8] - 0x30); + hour = ((buffer_3G[10] - 0x30) * 10) + (buffer_3G[11] - 0x30); + minute = ((buffer_3G[13] - 0x30) * 10) + (buffer_3G[14] - 0x30); + second = ((buffer_3G[16] - 0x30) * 10) + (buffer_3G[17] - 0x30); + timezone = (((buffer_3G[19] - 0x30) * 10) + (buffer_3G[20] - 0x30)) / 4; + if(buffer_3G[18] == '-') + { + timezone *= -1; + } - //sscanf(aux_str, "%02u%02u%02u%02u%02u%02u%02u", &year, &year, &month, &date, &hour, &minute, &second); - year = ((aux_str[2] - 0x30) * 10) + (aux_str[3] - 0x30); - month = ((aux_str[4] - 0x30) * 10) + (aux_str[5] - 0x30); - date = ((aux_str[6] - 0x30) * 10) + (aux_str[7] - 0x30); - hour = ((aux_str[8] - 0x30) * 10) + (aux_str[9] - 0x30); - minute = ((aux_str[10] - 0x30) * 10) + (aux_str[11] - 0x30); - second = ((aux_str[12] - 0x30) * 10) + (aux_str[13] - 0x30); - - #if _3G_debug_mode>0 - USB.print(F("year ")); - USB.print(year, DEC); - USB.print(F("; month ")); - USB.print(month, DEC); - USB.print(F("; date ")); - USB.println(date, DEC); - USB.print(F("hour ")); - USB.print(hour, DEC); - USB.print(F("; minute ")); - USB.print(minute, DEC); - USB.print(F("; second ")); - USB.println(second, DEC); - #endif + #if _3G_debug_mode>0 + USB.print(F("year ")); + USB.print(year, DEC); + USB.print(F("; month ")); + USB.print(month, DEC); + USB.print(F("; date ")); + USB.println(date, DEC); + USB.print(F("hour ")); + USB.print(hour, DEC); + USB.print(F("; minute ")); + USB.print(minute, DEC); + USB.print(F("; second ")); + USB.print(second, DEC); + USB.print(F("; timezone ")); + USB.println((timezone), DEC); + #endif - if (RTC.isON == 0) // Checks if the RTC is on + if (timezone >= 0) + { + if(hour >= timezone) { - RTC_ant = true; - RTC.ON(); + hour = hour - timezone; } - - // Stes the RTC time - RTC.setTime(year, month, date, RTC.dow(year, month, date), hour, minute, second); //Gets time from RTC - - if (RTC_ant == 1) // Powers off the RTC if before it was off + else { - RTC.OFF(); + hour = hour - timezone + 24; } - - // Sets the RTC of the 3G too - strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[4]))); //SET_TIME - snprintf(buffer_3G, sizeof(buffer_3G), "%s\"%02u/%02u/%02u,%02u:%02u:%02u+00\"", str_aux1, RTC.year, RTC.month, RTC.date, RTC.hour, RTC.minute, RTC.second); - answer = sendCommand2( buffer_3G, OK_RESPONSE, ERROR); - - if (answer == 2) + } + else + { + if((hour - timezone) > 23) { - return -19; + hour = hour - timezone - 24; + } + else + { + hour = hour - timezone; } - return 1; } - - return answer; + + if (RTC.isON == 0) // Checks if the RTC is on + { + RTC_ant = true; + RTC.ON(); + } + + // Stes the RTC time + RTC.setTime(year, month, date, RTC.dow(year, month, date), hour, minute, second); //Gets time from RTC + + if (RTC_ant == 1) // Powers off the RTC if before it was off + { + RTC.OFF(); + } + + return 1; } @@ -5745,12 +5815,20 @@ int16_t Wasp3G::setTimebyMeshlium(const char* url, uint16_t port){ // read mote ID from EEPROM memory for(int i=0 ; i<16 ; i++ ) { - MID[i]=Utils.readEEPROM(i+MOTEID_ADDR); + MID[i]=Utils.readEEPROM(i+EEPROM_FRAME_MOTEID); } MID[16]='\0'; // Generates a frame - snprintf(frame_data, sizeof(frame_data), "<=>%c0#%lu#%s#0#", 155, _serial_id, MID); + snprintf(frame_data, + sizeof(frame_data), + "<=>%c0#%02x%02x%02x%02x#%s#0#", + 155, + _serial_id[4], + _serial_id[5], + _serial_id[6], + _serial_id[7], + MID); answer = sendHTTPframe( url, port, (uint8_t*) frame_data, strlen(frame_data), GET, 1); // gets URL from the solicited URL @@ -6055,7 +6133,7 @@ int8_t Wasp3G::readURLS(const char* url, uint16_t port, const char* HTTPS_reques return -15; } - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Receives data strcpy_P(str_aux1, (char*)pgm_read_word(&(table_HTTP[8]))); @@ -6105,7 +6183,7 @@ int8_t Wasp3G::readURLS(const char* url, uint16_t port, const char* HTTPS_reques aux = serialRead(_socket); if (aux != -1) { - if (count < BUFFER_SIZE) + if (count < _3G_BUFFER_SIZE) { buffer_3G[count] = aux; count++; @@ -6324,7 +6402,7 @@ int8_t Wasp3G::startGPS(int8_t mode, const char* GPS_url, const char* GPS_port){ do{ buffer_3G[count]=serialRead(_socket); count++; - }while ((serialAvailable(_socket) != 0) && (count < BUFFER_SIZE)); + }while ((serialAvailable(_socket) != 0) && (count < _3G_BUFFER_SIZE)); buffer_3G[count]='\0'; } else @@ -6409,7 +6487,7 @@ int8_t Wasp3G::getGPSinfo(){ // Gets GPS string count = 0; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); previous = millis(); do{ while ((serialAvailable(_socket) == 0) && ((millis() - previous) < 5000)) @@ -6427,7 +6505,7 @@ int8_t Wasp3G::getGPSinfo(){ previous = millis(); } - }while ((buffer_3G[count-1] != '\r') && ((millis() - previous) < 5000) && (count < BUFFER_SIZE)); + }while ((buffer_3G[count-1] != '\r') && ((millis() - previous) < 5000) && (count < _3G_BUFFER_SIZE)); buffer_3G[count] = '\0'; #if _3G_debug_mode>0 @@ -7477,9 +7555,9 @@ int16_t Wasp3G::readIPdata(){ if (data_length != 0) { - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); i = 0; - while ((data_length > i) && ((millis() - previous) < 30000) && (i < BUFFER_SIZE)){ + while ((data_length > i) && ((millis() - previous) < 30000) && (i < _3G_BUFFER_SIZE)){ while((serialAvailable(_socket) == 0) && ((millis() - previous) < 30000)) { // Condition to avoid an overflow (DO NOT REMOVE) @@ -7523,7 +7601,7 @@ int8_t Wasp3G::listClients(){ strcpy_P(str_aux2, (char*)pgm_read_word(&(table_IP[15]))); //SERVER_LIST_R answer = sendCommand2(str_aux1, str_aux2, ERROR_IP); - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); if (answer == 2) { @@ -7555,7 +7633,7 @@ int8_t Wasp3G::listClients(){ previous = millis(); } - }while ((answer == 1) && ((millis()-previous) < 3000) && (counter < BUFFER_SIZE)); + }while ((answer == 1) && ((millis()-previous) < 3000) && (counter < _3G_BUFFER_SIZE)); buffer_3G[counter] = '\0'; } @@ -7651,7 +7729,7 @@ int8_t Wasp3G::getIP(){ previous = millis(); } - }while ((buffer_3G[counter-1] != '\r') && ((millis()-previous) < 3000) && (counter < BUFFER_SIZE)); + }while ((buffer_3G[counter-1] != '\r') && ((millis()-previous) < 3000) && (counter < _3G_BUFFER_SIZE)); buffer_3G[counter] = '\0'; } @@ -7670,7 +7748,7 @@ int8_t Wasp3G::QueryDomainfromIP(const char* ip){ int8_t answer; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_IP[20]))); //DOMFROMIP snprintf(buffer_3G, sizeof(buffer_3G), "%s=\"%s\"", str_aux1, ip); answer = sendCommand2(buffer_3G, str_aux1, ERROR); @@ -7717,7 +7795,7 @@ int8_t Wasp3G::QueryDomainfromIP(const char* ip){ previous = millis(); } - }while ((buffer_3G[counter-1] != '"') && ((millis() - previous) < 1000) && (counter < BUFFER_SIZE)); + }while ((buffer_3G[counter-1] != '"') && ((millis() - previous) < 1000) && (counter < _3G_BUFFER_SIZE)); buffer_3G[counter-1] = '\0'; return 1; @@ -7742,7 +7820,7 @@ int8_t Wasp3G::QueryIPfromDomain(const char* domain){ int8_t answer; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); strcpy_P(str_aux1, (char*)pgm_read_word(&(table_IP[19]))); //IPFROMDOM snprintf(buffer_3G, sizeof(buffer_3G), "%s=\"%s\"", str_aux1, domain); answer=sendCommand2(buffer_3G, str_aux1, ERROR); @@ -8479,7 +8557,7 @@ int8_t Wasp3G::ls(int8_t type){ previous = millis(); } - }while ((counter < BUFFER_SIZE) + }while ((counter < _3G_BUFFER_SIZE) && !((buffer_3G[counter-2] == 'O') && (buffer_3G[counter-1] == 'K')) && ((millis()-previous) < 3000)); @@ -8594,7 +8672,7 @@ int8_t Wasp3G::getCellsysInfo(){ unsigned long previous; char command[15]; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // reduces the baudrate changeBaudrate(4800); @@ -8629,7 +8707,7 @@ int8_t Wasp3G::getCellsysInfo(){ }while ((buffer_3G[x-1] != '\r') && ((millis() - previous) < 5000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); if ((millis() - previous) < 5000) { @@ -8683,7 +8761,7 @@ int8_t Wasp3G::getCellchannel(){ int x; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Sends the command: strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[35]))); //CELL_CHN_INFO @@ -8715,7 +8793,7 @@ int8_t Wasp3G::getCellchannel(){ }while (!((buffer_3G[x-1] == 'K') && (buffer_3G[x-2] == 'O')) && ((millis() - previous) < 5000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-4] = '\0'; } @@ -8736,7 +8814,7 @@ int8_t Wasp3G::getCellradioparam(){ int x; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Sends the command: strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[36]))); //CELL_RADIO_PARAM answer = sendCommand1(str_aux1, str_aux1); @@ -8750,7 +8828,7 @@ int8_t Wasp3G::getCellradioparam(){ do{ // reads from socket 1 buffer_3G[x] = serialRead(_socket); - if ((buffer_3G[x] != -1) && (x < BUFFER_SIZE)) + if ((buffer_3G[x] != -1) && (x < _3G_BUFFER_SIZE)) { x++; } @@ -8838,7 +8916,7 @@ int8_t Wasp3G::scanNetworkchannels(int chn_start, int chn_end, bool mode){ }while ((buffer_3G[x-1] != 'N') && ((millis() - previous) < 10000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-3] = '\0'; } @@ -8887,7 +8965,7 @@ int8_t Wasp3G::getUEsysInfo(){ }while ((buffer_3G[x-1] != '\r') && ((millis() - previous) < 5000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-1]='\0'; } @@ -8946,7 +9024,7 @@ int8_t Wasp3G::WCDMAsysInfo(){ int8_t answer, x; unsigned long previous; - memset(buffer_3G, '\0', BUFFER_SIZE); + memset(buffer_3G, '\0', _3G_BUFFER_SIZE); // Sends the command: strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[37]))); //CELL_SET_SYS_INFO strcpy_P(str_aux2, (char*)pgm_read_word(&(table_MISC[38]))); //CELL_SET_SYS_INFO_R @@ -8975,7 +9053,7 @@ int8_t Wasp3G::WCDMAsysInfo(){ }while ((buffer_3G[x-1] != '\n') && ((millis() - previous) < 10000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); waitForData(str_aux2, 2000, millis(), 0); @@ -9023,7 +9101,7 @@ int8_t Wasp3G::WCDMAsysInfo(){ }while ((buffer_3G[x-1] != '\n') && ((millis() - previous) < 10000) - && (x < BUFFER_SIZE)); + && (x < _3G_BUFFER_SIZE)); buffer_3G[x-1]='\0'; } @@ -9157,7 +9235,7 @@ uint8_t Wasp3G::sendATCommand(const char* ATcommand){ uint16_t i; // Cleans 'buffer_3G': - memset (buffer_3G, '\0', BUFFER_SIZE); + memset (buffer_3G, '\0', _3G_BUFFER_SIZE); i = 0; @@ -9188,7 +9266,7 @@ uint8_t Wasp3G::sendATCommand(const char* ATcommand){ #endif delay(20); - if (i < BUFFER_SIZE) + if (i < _3G_BUFFER_SIZE) { i++; } @@ -9672,7 +9750,7 @@ int8_t Wasp3G::requestOTA(const char* FTP_server, const char* FTP_port, const ch SD.goRoot(); // Reads the file - strcpy(buffer_3G, SD.cat(OTA_ver_file, 0, BUFFER_SIZE)); + strcpy(buffer_3G, SD.cat(OTA_ver_file, 0, _3G_BUFFER_SIZE)); // Searchs the file name str_pointer = strstr(buffer_3G, "FILE:"); diff --git a/libraries/_3G/Wasp3G.h b/libraries/_3G/Wasp3G.h index 16bafed..99b8e72 100644 --- a/libraries/_3G/Wasp3G.h +++ b/libraries/_3G/Wasp3G.h @@ -1,7 +1,7 @@ /*! \file Wasp3G.h \brief Library for managing the SIM5218 module - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.4 + Version: 3.1 Design: David Gascón Implementation: Alejandro Gállego @@ -52,7 +52,7 @@ #define _3G_debug_mode 0 -#define BUFFER_SIZE 512 +#define _3G_BUFFER_SIZE 512 #define _3G_APN "apn" #define _3G_LOGIN "login" //comment this line if you don't need login @@ -288,7 +288,7 @@ class Wasp3G int8_t sendHTTPrequest( const char* url, uint16_t port, uint8_t* data, - int length, + uint16_t length, uint8_t method ); //! It reads the response from the server @@ -500,7 +500,7 @@ class Wasp3G uint16_t CME_CMS_code; //! Variable : - char buffer_3G[BUFFER_SIZE]; + char buffer_3G[_3G_BUFFER_SIZE]; //!Variables for GPS #if GPS_FUSE @@ -1339,31 +1339,21 @@ class Wasp3G */ int16_t readURL(const char* url, uint16_t port, const char* HTTP_request, bool parse); - //! Sets the time of Waspmote's RTC getting the time from an url + //! Sets the time of Waspmote's RTC getting the time from an HTP server /*! \return '1' on success '0' if no connection - '-1' if error setting APN, username and password - '-2' if error opening a HTTP session - '-3' if error receiving data or timeout waiting data - '-4' if error changing the baudrate (data received is OK) - '-5' if unknown error for HTTP - '-6' if HTTP task is busy - '-7' if fail to resolve server address - '-8' if HTTP timeout - '-9' if fail to transfer data - '-10' if memory error - '-11' if invalid parameter - '-12' if network error + '-1' if error setting APN, username and password, + '-2' if error checking the connection + '-3' if error adding the HTP server + '-4' if error reading the time from 3G's RTC + '-5' HTP Unknown error + '-6' HTP Wrong parameter + '-7' HTP Wrong date and time calculated + '-8' HTP Network error '-15' if error setting APN, username and password with CME_error code available - '-16' if error opening a HTTP session with CME_error code available - '-17' if url response its not OK (HTTP code 200) - '-18' if content-length field not found - '-19' if data field not found - '-20' if error checking the connection - '-21' if fail setting the time of the internal RTC of the 3G module */ - int16_t setTimebyURL(); + int16_t setTimebyURL(const char* htp_server, uint16_t htp_port); //! Sets the time of Waspmote's RTC getting the time from Meshlium /*! diff --git a/libraries/_3G/keywords.txt b/libraries/_3G/keywords.txt index 0f014ce..cba873a 100644 --- a/libraries/_3G/keywords.txt +++ b/libraries/_3G/keywords.txt @@ -41,8 +41,87 @@ WCDMA_800 LITERAL1 WCDMA_VII_2600 LITERAL1 WCDMA_VIII_900 LITERAL1 WCDMA_IX_1700 LITERAL1 -setPIN KEYWORD2 -check KEYWORD2 +CAMERA_FUSE LITERAL1 +MAIL_FUSE LITERAL1 +GPS_FUSE LITERAL1 +TRANSMISSION_FUSE LITERAL1 +_3G_debug_mode LITERAL1 +_3G_BUFFER_SIZE LITERAL1 +_3G_APN LITERAL1 +_3G_LOGIN LITERAL1 +_3G_PASSW LITERAL1 +ERROR_IP LITERAL1 +XMODEM_ACK LITERAL1 +XMODEM_NAK LITERAL1 +XMODEM_SOH LITERAL1 +XMODEM_EOT LITERAL1 +XMODEM_CAN LITERAL1 +GPS_FUSE LITERAL1 +CAMERA_FUSE LITERAL1 +MAIL_FUSE LITERAL1 +TRANSMISSION_FUSE LITERAL1 + +n_connection KEYWORD2 +tlfNumber KEYWORD2 +IP_flags KEYWORD2 +autoAnswer KEYWORD2 +answerCall KEYWORD2 +generateTone KEYWORD2 +ringerLevel KEYWORD2 +startCamera KEYWORD2 +stopCamera KEYWORD2 +takePicture KEYWORD2 +startVideo KEYWORD2 +pauseVideo KEYWORD2 +resumeVideo KEYWORD2 +stopVideo KEYWORD2 +analogCameraConfig KEYWORD2 +cameraRotation KEYWORD2 +cameraBrightness KEYWORD2 +cameraResolution KEYWORD2 +cameraFPS KEYWORD2 +pictureName KEYWORD2 +pictureTimeStamp KEYWORD2 +autoLevel KEYWORD2 +powerIRLED KEYWORD2 +autoLight KEYWORD2 +selectFilter KEYWORD2 +makeVideoCall KEYWORD2 +hangVideoCall KEYWORD2 +VideoCallQuality KEYWORD2 +VideoCallDMTF KEYWORD2 +downloadFileSecure KEYWORD2 +logoutFPTS KEYWORD2 +getPOP3header KEYWORD2 +deletePOP3mail KEYWORD2 +setTimebyURL KEYWORD2 +setTimebyMeshlium KEYWORD2 +startGPScold KEYWORD2 +startGPShot KEYWORD2 +stopGPS KEYWORD2 +enableAutoGPS KEYWORD2 +disableAutoGPS KEYWORD2 +setTimebyGPS KEYWORD2 +readIPdata KEYWORD2 +QueryDomainfromIP KEYWORD2 +QueryIPfromDomain KEYWORD2 +getXModemFile KEYWORD2 +sendXModemFile KEYWORD2 +getCellchannel KEYWORD2 +getCellradioparam KEYWORD2 +setPreferedServiceDomain KEYWORD2 +scanNetworkchannels KEYWORD2 +setNetworkBand KEYWORD2 +modeAcquisitionsOrder KEYWORD2 +changeBaudrate KEYWORD2 +selectAudioOutput KEYWORD2 +micGain KEYWORD2 +loudspeakerLevel KEYWORD2 +sendFiletoWiFiFTP KEYWORD2 +sendFileto3GFTP KEYWORD2 +sendFileto3Gemail KEYWORD2 +setPIN KEYWORD2 KEYWORD2 +check KEYWORD2 KEYWORD2 makeCall KEYWORD2 hangUp KEYWORD2 sendSMS KEYWORD2 @@ -108,5 +187,7 @@ altitude KEYWORD2 speedOG KEYWORD2 course KEYWORD2 Wasp3G KEYWORD2 +enablePIRInterrupt KEYWORD2 +disablePIRInterrupt KEYWORD2 -_3G KEYWORD3 +_3G KEYWORD1 diff --git a/libraries/_4_20mA/currentLoop.cpp b/libraries/_4_20mA/currentLoop.cpp index 024fb99..6641acf 100755 --- a/libraries/_4_20mA/currentLoop.cpp +++ b/libraries/_4_20mA/currentLoop.cpp @@ -1,7 +1,7 @@ /*! \file currentLoop.cpp \brief Library for managing the 4-20mA Board - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 + Version: 3.0 Implementation: Ahmad Saad */ diff --git a/libraries/_4_20mA/currentLoop.h b/libraries/_4_20mA/currentLoop.h index 6839b13..91f971d 100755 --- a/libraries/_4_20mA/currentLoop.h +++ b/libraries/_4_20mA/currentLoop.h @@ -1,7 +1,7 @@ /*! \file currentLoop.h \brief Library for managing the 4-20mA - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.0 + Version: 3.0 Implementation: Ahmad Saad */ diff --git a/libraries/_4_20mA/keywords.txt b/libraries/_4_20mA/keywords.txt index e6875a8..0c232bd 100644 --- a/libraries/_4_20mA/keywords.txt +++ b/libraries/_4_20mA/keywords.txt @@ -6,7 +6,7 @@ CHANNEL3 LITERAL1 CHANNEL4 LITERAL1 SUPPLY12V LITERAL1 SUPPLY5V LITERAL1 -currentLoopBoard KEYWORD3 +currentLoopBoard KEYWORD1 readChannel KEYWORD2 readVoltage KEYWORD2 readCurrent KEYWORD2 diff --git a/waspmote-api/Printable.h b/waspmote-api/Printable.h index 6070686..a8bfd6d 100755 --- a/waspmote-api/Printable.h +++ b/waspmote-api/Printable.h @@ -1,6 +1,7 @@ /* Printable.h - Interface class that allows printing of complex types Copyright (c) 2011 Adrian McEwen. All right reserved. + Modified for Waspmote by Libelium, 2016 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -15,6 +16,9 @@ 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 + + Version: 3.0 + */ #ifndef Printable_h diff --git a/waspmote-api/WConstants.h b/waspmote-api/WConstants.h index ed87229..c783630 100755 --- a/waspmote-api/WConstants.h +++ b/waspmote-api/WConstants.h @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 0.1 + * Version: 3.0 * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa */ diff --git a/waspmote-api/WInterrupts.c b/waspmote-api/WInterrupts.c index 92e6816..b9b52e4 100755 --- a/waspmote-api/WInterrupts.c +++ b/waspmote-api/WInterrupts.c @@ -3,7 +3,7 @@ * * Copyright (c) 2004-05 Hernando Barragan * Modified 24 November 2006 by David A. Mellis - * Revised for Waspmote by Libelium, 2015 + * Revised for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -18,7 +18,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa, David A. Mellis, Hernando Barragan, Manuel Calahorra */ @@ -40,6 +40,7 @@ // definition of interrupt vectors volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; volatile static voidFuncPtr twiIntFunc; +extern volatile uint8_t _boot_version; #if defined(__AVR_ATmega168__) @@ -220,6 +221,7 @@ ISR(INT1_vect) ISR(INT2_vect) { + sleep_disable(); if(intFunc[EXTERNAL_INT_2]) intFunc[EXTERNAL_INT_2](); } @@ -227,6 +229,7 @@ ISR(INT2_vect) ISR(INT3_vect) { + sleep_disable(); if(intFunc[EXTERNAL_INT_3]) intFunc[EXTERNAL_INT_3](); } @@ -337,12 +340,25 @@ void onHAIwakeUP(void) if( intConf & PLV_INT ) { - // check monitorization pin - if( !(digitalRead(PLV_INT_PIN_MON))) + if (_boot_version >= 'G') + { + // check monitorization pin + if( !(digitalRead(PLV_INT_PIN_MON_V30))) + { + intCounter++; + intFlag |= PLV_INT; + intArray[PLV_POS]++; + } + } + else { - intCounter++; - intFlag |= PLV_INT; - intArray[PLV_POS]++; + if( !(digitalRead(PLV_INT_PIN_MON))) + { + intCounter++; + intFlag |= PLV_INT; + intArray[PLV_POS]++; + } + } } @@ -454,6 +470,7 @@ void enableInterrupts(uint32_t conf) { pinMode(RAD_INT_PIN_MON,INPUT); pinMode(MUX_TX, INPUT); + digitalWrite(MUX_TX, HIGH); attachInterrupt(TXD1_PIN, onLAIwakeUP, FALLING); } diff --git a/waspmote-api/WaspACC.cpp b/waspmote-api/WaspACC.cpp index a58e3cb..8d9cae4 100755 --- a/waspmote-api/WaspACC.cpp +++ b/waspmote-api/WaspACC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa, Marcos Yarza */ @@ -33,6 +33,8 @@ WaspACC::WaspACC() { // no interruption set at the beginning accInt=NO_INT; + // init attribute + isON = 0; // init default Full Scale mode to +/- 2G fsSelection = FS_2G; @@ -66,10 +68,10 @@ void WaspACC::ON(void) void WaspACC::ON(uint8_t FS_OPTION) { // join i2c bus (address optional for master) - if( !Wire.I2C_ON ) - { + if (!Wire.isON) + { Wire.begin(); - } + } accMode = ACC_ON; setMode(ACC_ON); @@ -130,11 +132,13 @@ void WaspACC::boot(void) */ void WaspACC::OFF(void) { - setMode(ACC_POWER_DOWN); - if( Wire.I2C_ON && RTC.isON!=1) + setMode(ACC_POWER_DOWN); + + // close I2C + if (Wire.isON && RTC.isON!=1) { - PWR.closeI2C(); - RTC.setMode(RTC_OFF, RTC_I2C_MODE); + PWR.closeI2C(); + RTC.setMode(RTC_OFF, RTC_I2C_MODE); } } @@ -473,6 +477,7 @@ uint8_t WaspACC::getMode() */ uint8_t WaspACC::setMode(uint8_t mode) { + uint8_t result = 0; accMode = mode; switch (mode) @@ -482,52 +487,54 @@ uint8_t WaspACC::setMode(uint8_t mode) // Normal mode is selected (PM2=0; PM1=0; PM0=1) // ODR is set to 50 Hz (DR1=0; DR0=0) // X-Y-Z axis are enabled - writeRegister(CTRL_REG1, B00100111); - isON = 1; + result = writeRegister(CTRL_REG1, B00100111); + isON = 1; + // Ton (Turn-on time)= 1/ODR+1ms + delay(21); break; case ACC_POWER_DOWN: // turn power off - writeRegister(CTRL_REG1,B00000000); + result = writeRegister(CTRL_REG1,B00000000); isON = 0; break; case ACC_LOW_POWER_1: // turn lo power mode. ODR=0.5 Hz - writeRegister(CTRL_REG1, B01000111); + result = writeRegister(CTRL_REG1, B01000111); isON = 1; break; case ACC_LOW_POWER_2: // turn lo power mode. ODR=1 Hz - writeRegister(CTRL_REG1, B01100111); + result = writeRegister(CTRL_REG1, B01100111); isON = 1; break; case ACC_LOW_POWER_3: // turn lo power mode. ODR=2 Hz - writeRegister(CTRL_REG1, B10000111); + result = writeRegister(CTRL_REG1, B10000111); isON = 1; break; case ACC_LOW_POWER_4: // turn lo power mode. ODR=5 Hz - writeRegister(CTRL_REG1, B10100111); + result = writeRegister(CTRL_REG1, B10100111); isON = 1; break; case ACC_LOW_POWER_5: // turn lo power mode. ODR=10 Hz - writeRegister(CTRL_REG1, B11000111); + result = writeRegister(CTRL_REG1, B11000111); isON = 1; break; - default: return 0; + default: + break; } - // go out with no error, leaves room to implement an error function - return 1; + return result; } /* diff --git a/waspmote-api/WaspACC.h b/waspmote-api/WaspACC.h index ebed749..99a7e58 100755 --- a/waspmote-api/WaspACC.h +++ b/waspmote-api/WaspACC.h @@ -1,7 +1,7 @@ /*! \file WaspACC.h \brief Library for managing the accelerometer LIS331DLH - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: David Cuartielles, Alberto Bielsa, Marcos Yarza diff --git a/waspmote-api/WaspClasses.h b/waspmote-api/WaspClasses.h index 9459b4c..bc49b3f 100755 --- a/waspmote-api/WaspClasses.h +++ b/waspmote-api/WaspClasses.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona */ @@ -53,6 +53,7 @@ #include "WaspPWR.h" #include "WaspXBeeCore.h" #include "MemoryFree.h" +#include "WaspEEPROM.h" // SPI library diff --git a/waspmote-api/WaspConstants.h b/waspmote-api/WaspConstants.h index ea9aa1c..5c582c9 100755 --- a/waspmote-api/WaspConstants.h +++ b/waspmote-api/WaspConstants.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com * This program is free software: you can redistribute it and/or modify @@ -14,10 +14,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . - - Version: 1.9 - Design: David Gascón - Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona + * + * Version: 3.1 + * Design: David Gascón + * Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona */ @@ -39,7 +39,7 @@ /*! \def WASPMOTE_API_VERSION \brief Waspmote API version number */ -#define WASPMOTE_API_VERSION 20 +#define WASPMOTE_API_VERSION 26 @@ -228,9 +228,6 @@ /*! \def ACC_INT_PIN_MON \brief Monitorization pin used for ACC interruptions */ - /*! \def BAT_INT_PIN_MON - \brief Monitorization pin used for BAT interruptions - */ /*! \def RTC_INT_PIN_MON \brief Monitorization pin used for RTC interruptions */ @@ -251,13 +248,14 @@ \brief Monitorization pin used for Pluviometer sensor interruptions */ #define ACC_INT_PIN_MON RDY_ACC // PE6 -#define BAT_INT_PIN_MON LOW_BAT_MON // PG0 #define RTC_INT_PIN_MON RST_RTC // PE7 #define WTD_INT_PIN_MON DIGITAL0 // PE4 #define XBEE_INT_PIN_MON XBEE_MON // PA7 #define RAD_INT_PIN_MON DIGITAL7 // PC4 #define PIR_3G_PIN_MON ANA4 // PF5 (ANALOG5) -#define PLV_INT_PIN_MON DIGITAL4 +#define PLV_INT_PIN_MON DIGITAL4 // v20 +#define PLV_INT_PIN_MON_V30 ANA3 // v30 + #define UART1_INT_PIN_MON GPRS_PIN // PC2 // Event Sensor Board @@ -351,27 +349,34 @@ /*! \def REG_DUST_GASES_PRO \brief Bit dedicated to the marking of the Dust sensor in Gases PRO Board */ -#define REG_5V 1 // bit 0 -#define REG_3V3 2 // bit 1 -#define REG_SOCKET0 4 // bit 2 -#define REG_SOCKET1 8 // bit 3 -#define REG_METERING 16 // bit 4 -#define REG_AGRICULTURE 32 // bit 5 -#define REG_GASES 64 // bit 6 -#define REG_EVENTS 128 // bit 7 -#define REG_CITIES_V14 256 // bit 8 -#define REG_CITIES_V15 512 // bit 9 -#define REG_RADIATION 1024 // bit 10 -#define REG_PROTOTYPING 2048 // bit 11 -#define REG_PARKING 4096 // bit 12 -#define REG_VIDEO_CAMERA 8192 // bit 13 -#define REG_WATER 16384 // bit 14 -#define REG_OTA 32768 // bit 15 -#define REG_SD 65536 // bit 16 -#define REG_SX 131072 // bit 17 -#define REG_DUST_GASES_PRO 262144 // bit 18 -#define REG_WATER_IONS 524288 // bit 19 -#define REG_RS485 1048576 // bit 20 + +// WaspRegister +static const uint16_t REG_5V = 1; // bit 0 +static const uint16_t REG_3V3 = 2; // bit 1 +static const uint16_t REG_SOCKET0 = 4; // bit 2 +static const uint16_t REG_SOCKET1 = 8; // bit 3 +static const uint16_t REG_SD = 16; // bit 4 +static const uint16_t REG_SX = 32; // bit 5 +static const uint16_t REG_RS485 = 64; // bit 6 +static const uint16_t REG_XBEE_SOCKET0 = 128; // bit 7 +static const uint16_t REG_OTA = 256; // bit 8 + + +// WaspRegisterSensor +static const uint16_t REG_METERING = 1; // bit 0 +static const uint16_t REG_AGRICULTURE = 2; // bit 1 +static const uint16_t REG_DUST_GASES_PRO = 4; // bit 2 +static const uint16_t REG_WATER_IONS = 8; // bit 3 +static const uint16_t REG_GASES = 16; // bit 4 +static const uint16_t REG_CITIES_PRO = 32; // bit 5 +static const uint16_t REG_EVENTS = 64; // bit 6 +static const uint16_t REG_CITIES_V14 = 128; // bit 7 +static const uint16_t REG_CITIES_V15 = 256; // bit 8 +static const uint16_t REG_RADIATION = 512; // bit 9 +static const uint16_t REG_PROTOTYPING = 1024; // bit 10 +static const uint16_t REG_PARKING = 2048; // bit 11 +static const uint16_t REG_VIDEO_CAMERA = 4096; // bit 12 +static const uint16_t REG_WATER = 8192; // bit 13 /******************************************************************************* @@ -391,14 +396,10 @@ /*! \def XBEE_ON \brief XBee Power Mode. OFF in this case */ -/*! \def XBEE_HIBERNATE - \brief XBee Power Mode. HIBERNATE in this case - */ /*! \def XBEE_OFF \brief XBee Power Mode. OFF in this case */ #define XBEE_ON 1 -#define XBEE_HIBERNATE 2 #define XBEE_OFF 3 @@ -448,18 +449,33 @@ #define ENABLED 1 -// Used EEPROM addresses -/*! \def AUTHKEY_ADDR - \brief Authentication key EEPROM address - */ -/*! \def MOTEID_ADDR - \brief MOTEID EEPROM address - */ -/*! \def SEQUENCE_ADDR - \brief Sequence EEPROM address - */ -#define MOTEID_ADDR 147 -#define SEQUENCE_ADDR 163 -#define AUTHKEY_ADDR 107 + +// Define the Voltage Reference Selections for ADC +#define EXTERNAL 0 +#define DEFAULT 1 +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 + +// Define of the sensor boards sockets +#define SOCKET_1 1 +#define SOCKET_2 2 +#define SOCKET_3 3 +#define SOCKET_4 4 +#define SOCKET_5 5 +#define SOCKET_6 6 +#define SOCKET_7 7 +#define SOCKET_8 8 +#define SOCKET_9 9 +#define SOCKET_10 10 + +// Define the Plug&Sense! +#define SOCKET_A 101 +#define SOCKET_B 102 +#define SOCKET_C 103 +#define SOCKET_D 104 +#define SOCKET_E 105 +#define SOCKET_F 106 + + #endif diff --git a/waspmote-api/WaspEEPROM.cpp b/waspmote-api/WaspEEPROM.cpp new file mode 100644 index 0000000..4c3e8e5 --- /dev/null +++ b/waspmote-api/WaspEEPROM.cpp @@ -0,0 +1,521 @@ +/* + * Based on library by Rob Tillaart + * URL: http://arduino.cc/playground/Main/LibraryForI2CEEPROM + * VERSION: 1.0.05 + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascon + * Implementation: Yuri Carmona + */ + + +#ifndef __WPROGRAM_H__ + #include "WaspClasses.h" +#endif + +#include + + +WaspEEPROM::WaspEEPROM() +{ + _deviceAddress = I2C_ADDRESS_EEPROM; + _lastWrite = 0; + TWBR = 12; // 12=400Khz 32=200 72=100 152=50 F_CPU/16+(2*TWBR) +} + +uint8_t WaspEEPROM::ON() +{ + uint8_t error; + + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } + + error = waitReady(); + + // check correct comm + error = readJEDEC(); + + if (error == 0) + { + if ((_response[0] == 0x00) && (_response[1] == 0x1F)) + { + return 0; + } + + return 1; + } + else + { + // set default I2C address + _deviceAddress = I2C_ADDRESS_EEPROM_DEFAULT; + + // generate new register value + uint8_t new_reg_value = 0; + new_reg_value = I2C_ADDRESS_EEPROM << 1; + new_reg_value++; + + // set new I2C address + eeprom.writeByte(0xF040, new_reg_value); + + // reset eeprom chip + reset(); + + // go back to current I2C address + _deviceAddress = I2C_ADDRESS_EEPROM; + return error; + } + + return error; +} + +int WaspEEPROM::writeByte(uint16_t address, uint8_t data) +{ + int rv = _WriteBlock(address, &data, 1); + return rv; +} + +int WaspEEPROM::setBlock(uint16_t address, uint8_t data, uint16_t length) +{ + uint8_t buffer[I2C_TWIBUFFERSIZE]; + for (uint8_t i =0; i< I2C_TWIBUFFERSIZE; i++) buffer[i] = data; + + int rv = _pageBlock(address, buffer, length, false); // todo check return value.. + return rv; +} + +int WaspEEPROM::writeBlock(uint16_t address, uint8_t* buffer, uint16_t length) +{ + int rv = _pageBlock(address, buffer, length, true); // todo check return value.. + return rv; +} + +uint8_t WaspEEPROM::readByte(uint16_t address) +{ + uint8_t rdata; + _ReadBlock(address, &rdata, 1); + return rdata; +} + +uint16_t WaspEEPROM::readBlock(uint16_t address, uint8_t* buffer, uint16_t length) +{ + uint16_t rv = 0; + while (length > 0) + { + uint8_t cnt = min(length, I2C_TWIBUFFERSIZE); + rv += _ReadBlock(address, buffer, cnt); + address += cnt; + buffer += cnt; + length -= cnt; + } + return rv; +} + +#ifdef I2C_EEPROM_EXTENDED +// returns 64, 32, 16, 8, 4, 2, 1, 0 +// 0 is smaller than 1K +uint8_t WaspEEPROM::determineSize() +{ + uint8_t rv = 0; // unknown + uint8_t orgValues[8]; + uint16_t addr; + + // remember old values, non destructive + for (uint8_t i=0; i<8; i++) + { + addr = (512 << i) + 1; + orgValues[i] = readByte(addr); + } + + // scan page folding + for (uint8_t i=0; i<8; i++) + { + rv = i; + uint16_t addr1 = (512 << i) + 1; + uint16_t addr2 = (512 << (i+1)) + 1; + writeByte(addr1, 0xAA); + writeByte(addr2, 0x55); + if (readByte(addr1) == 0x55) // folded! + { + break; + } + } + + // restore original values + for (uint8_t i=0; i<8; i++) + { + uint16_t addr = (512 << i) + 1; + writeByte(addr, orgValues[i]); + } + return 0x01 << (rv-1); +} +#endif + +//////////////////////////////////////////////////////////////////// +// +// PRIVATE +// + +// _pageBlock aligns buffer to page boundaries for writing. +// and to TWI buffer size +// returns 0 = OK otherwise error +int WaspEEPROM::_pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer) +{ + int rv = 0; + while (length > 0) + { + uint8_t bytesUntilPageBoundary = I2C_EEPROM_PAGESIZE - address%I2C_EEPROM_PAGESIZE; + uint8_t cnt = min(length, bytesUntilPageBoundary); + cnt = min(cnt, I2C_TWIBUFFERSIZE); + + int rv = _WriteBlock(address, buffer, cnt); // todo check return value.. + if (rv != 0) return rv; + + address += cnt; + if (incrBuffer) buffer += cnt; + length -= cnt; + } + return rv; +} + +// pre: length <= I2C_EEPROM_PAGESIZE && length <= I2C_TWIBUFFERSIZE; +// returns 0 = OK otherwise error +int WaspEEPROM::_WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length) +{ + waitReady(); + + Wire.beginTransmission(_deviceAddress); + Wire.send((int)(address >> 8)); + Wire.send((int)(address & 0xFF)); + for (uint8_t cnt = 0; cnt < length; cnt++) + Wire.send(buffer[cnt]); + int rv = Wire.endTransmission(); + _lastWrite = millis(); + return rv; +} + +// pre: buffer is large enough to hold length bytes +// returns bytes written +uint8_t WaspEEPROM::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length) +{ + waitReady(); + + Wire.beginTransmission(_deviceAddress); + Wire.send((int)(address >> 8)); + Wire.send((int)(address & 0xFF)); + + int rv = Wire.endTransmission(); + if (rv != 0) return 0; // error + + Wire.requestFrom(_deviceAddress, length); + uint8_t cnt = 0; + uint32_t before = millis(); + while ((cnt < length) && ((millis() - before) < I2C_EEPROM_TIMEOUT)) + { + if (Wire.available()) buffer[cnt++] = Wire.receive(); + } + return cnt; +} + + + +// pre: buffer is large enough to hold length bytes +// returns bytes written +uint8_t WaspEEPROM::readRegister(uint16_t address, uint8_t* buffer, uint8_t length) +{ + // wait until chip is ready + waitReady(); + + Wire.beginTransmission(_deviceAddress); + Wire.send((int)(address >> 8)); + Wire.send((int)(address & 0xFF)); + + Wire.requestFrom(_deviceAddress, length); + uint8_t cnt = 0; + uint32_t before = millis(); + while ((cnt < length) && ((millis() - before) < I2C_EEPROM_TIMEOUT)) + { + if (Wire.available()) buffer[cnt++] = Wire.receive(); + } + + uint8_t rv = Wire.endTransmission(); + delay(10); + + if (rv != 0) return 1; // error + + return 0; +} + + + + + +/************************************************************* + * + * + * + * + * + * + *************************************************************/ +uint8_t WaspEEPROM::sendCommand(uint8_t* command) +{ + int retries = 3; + int x; + uint8_t crc_tx[2]; + uint8_t crc_rx[2]; + uint8_t crc_aux[2]; + uint8_t length = command[0]-2; + uint8_t rx_length = 16; + + do + { + // calculate CRC + aes132c_calculate_crc(length, command, crc_tx); + + // wait until chip is ready + waitReady(); + + Wire.beginTransmission(_deviceAddress); + Wire.send(0xFE); // CMD REGISTER ADDRESS + Wire.send(0x00); + + for (uint8_t i = 0; i>8) & 0xFF; + I2C_EEPROM_BLOCK_READ[4] = address & 0xFF; + I2C_EEPROM_BLOCK_READ[6] = length; + + error = eeprom.sendCommand(I2C_EEPROM_BLOCK_READ); + + return error; +} + + + + + +WaspEEPROM eeprom = WaspEEPROM(); + + +// +// END OF FILE +// diff --git a/waspmote-api/WaspEEPROM.h b/waspmote-api/WaspEEPROM.h new file mode 100644 index 0000000..c9bc7f3 --- /dev/null +++ b/waspmote-api/WaspEEPROM.h @@ -0,0 +1,96 @@ +/* + * Based on library by Rob Tillaart + * URL: http://arduino.cc/playground/Main/LibraryForI2CEEPROM + * VERSION: 1.0.05 + * + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Version: 3.0 + * Design: David Gascon + * Implementation: Yuri Carmona + */ + +#ifndef I2C_EEPROM_H +#define I2C_EEPROM_H + + +#include +#include +#include + + +// I2C_EEPROM_PAGESIZE must be multiple of 2 e.g. 16, 32 or 64 +// 24LC256 -> 64 bytes +#define I2C_EEPROM_PAGESIZE 64 + +// TWI buffer needs max 2 bytes for address +#define I2C_TWIBUFFERSIZE 30 + +// to break blocking read/write +#define I2C_EEPROM_TIMEOUT 1000 + +// comment next line to keep lib small +#define I2C_EEPROM_EXTENDED + +// define registers +#define EEPROM_STATUS_REGISTER 0xFFF0 + + +class WaspEEPROM +{ +public: + WaspEEPROM(); + + uint8_t _buffer[32]; + uint8_t _response[32]; + uint8_t _length; + + uint8_t ON(); + int writeByte(uint16_t address, uint8_t value); + int writeBlock(uint16_t address, uint8_t* buffer, uint16_t length); + int setBlock(uint16_t address, uint8_t value, uint16_t length); + + uint8_t readByte(uint16_t address); + uint16_t readBlock(uint16_t address, uint8_t* buffer, uint16_t length); + +#ifdef I2C_EEPROM_EXTENDED + uint8_t determineSize(); +#endif + uint8_t readRegister(uint16_t address, uint8_t* buffer, uint8_t length); + uint8_t sendCommand(uint8_t* command); + uint8_t sleepCommand(); + uint8_t readSerialNumber(); + uint8_t blockRead(uint16_t address, uint8_t length); + uint8_t readJEDEC(); + uint8_t reset(); + +private: + uint8_t _deviceAddress; + uint32_t _lastWrite; // for waitReady + + int _pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer); + int _WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length); + uint8_t _ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length); + + uint8_t waitReady(); +}; + +extern WaspEEPROM eeprom; + + +#endif +// END OF FILE diff --git a/waspmote-api/WaspGPRS_Pro_core.cpp b/waspmote-api/WaspGPRS_Pro_core.cpp index 731bc5b..c729186 100755 --- a/waspmote-api/WaspGPRS_Pro_core.cpp +++ b/waspmote-api/WaspGPRS_Pro_core.cpp @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.3 + * Version: 3.1 * Design: David Gascón * Implementation: Alejandro Gállego */ @@ -780,7 +780,7 @@ uint8_t WaspGPRS_Pro_core::sendCommand1(const char* theText, int answer= waitForData( expectedAnswer, max_timeout, timeout, 0); #if GPRS_debug_mode>0 - USB.print(F("Answer: ")); + USB.print(F("Answer received: ")); USB.println(answer, DEC); #endif @@ -856,7 +856,7 @@ uint8_t WaspGPRS_Pro_core::sendCommand2( const char* theText, int answer= waitForData( expectedAnswer1, expectedAnswer2, max_timeout, timeout, 0, 2); #if GPRS_debug_mode>0 - USB.print(F("Answer: ")); + USB.print(F("Answer received: ")); USB.println(answer, DEC); #endif @@ -917,9 +917,9 @@ uint8_t WaspGPRS_Pro_core::waitForData( const char* expectedAnswer1, #if GPRS_debug_mode>1 - USB.print(F("Answer 1: ")); + USB.print(F("Excepted answer 1: ")); USB.println(expectedAnswer1); - USB.print(F("Answer 2: ")); + USB.print(F("Excepted answer 2: ")); USB.println(expectedAnswer2); #endif // Gets the maximum length and the minimum length of the 2 strings @@ -2691,7 +2691,7 @@ void WaspGPRS_Pro_core::begin(){ */ void WaspGPRS_Pro_core::close(){ closeSerial(_socket); - Utils.setMux(MUX_TO_LOW, MUX_TO_LOW); + Utils.setMux(LOW, LOW); } /* OFF(void) - closes UART1 and powers off the SIM900 module @@ -2818,22 +2818,21 @@ int8_t WaspGPRS_Pro_core::setMode(uint8_t pwrMode){ if (global_counter > 0) { // All versions - // Enables numeric error codes: AT+CMEE=1 strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[32]))); //NUMERIC_ERROR - sendCommand1(str_aux1,OK_RESPONSE); + sendCommand2(str_aux1,OK_RESPONSE, ERROR, 500, 1); // Disables command echoes: ATE0 strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[33]))); //NO_ECHO - sendCommand1(str_aux1,OK_RESPONSE); + sendCommand2(str_aux1,OK_RESPONSE, ERROR, 500, 1); // Disable slow clock: AT+CSCLK=0 strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[3]))); //POWER_NO_SLEEP - answer=sendCommand1(str_aux1, OK_RESPONSE); + answer=sendCommand2(str_aux1, OK_RESPONSE, ERROR, 500, 1); // Set Phone to Full Functionality: AT+CFUN=1 strcpy_P(str_aux1, (char*)pgm_read_word(&(table_MISC[0]))); //POWER_FULL - answer=sendCommand2(str_aux1, OK_RESPONSE, ERROR_CME); + answer=sendCommand2(str_aux1, OK_RESPONSE, ERROR_CME, 500, 1); if (battery_level < 30) { @@ -4555,8 +4554,7 @@ int8_t WaspGPRS_Pro_core::downloadFile( const char* file, { unsigned long previous=0; - int8_t answer=0; - uint8_t i=0; + int8_t answer=0; uint8_t count=10; long ftp_size=0; uint8_t ftp_retries; diff --git a/waspmote-api/WaspGPRS_Pro_core.h b/waspmote-api/WaspGPRS_Pro_core.h index 4f319bc..1956899 100755 --- a/waspmote-api/WaspGPRS_Pro_core.h +++ b/waspmote-api/WaspGPRS_Pro_core.h @@ -1,7 +1,7 @@ /*! \file WaspGPRS_Pro_core.h \brief Library for managing the SIM900 module - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 2.1 + Version: 3.0 Design: David Gascón Implementation: Alejandro Gállego diff --git a/waspmote-api/WaspOneWire.cpp b/waspmote-api/WaspOneWire.cpp index c12857a..981d27c 100644 --- a/waspmote-api/WaspOneWire.cpp +++ b/waspmote-api/WaspOneWire.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Design: David Gascón * Implementation: Jim Studt, Alberto Bielsa, Yuri Carmona ,David Marruedo * diff --git a/waspmote-api/WaspOneWire.h b/waspmote-api/WaspOneWire.h index 100ff2b..69fb4f9 100644 --- a/waspmote-api/WaspOneWire.h +++ b/waspmote-api/WaspOneWire.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,9 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Version: 1.1 - * Design: David Gascón - * Implementation: Jim Studt, Alberto Bielsa , David Marruedo + * Version: 3.0 + * Design: David Gascón + * Implementation: Jim Studt, Alberto Bielsa, David Marruedo */ #ifndef WaspOneWire_h #define WaspOneWire_h diff --git a/waspmote-api/WaspPWR.cpp b/waspmote-api/WaspPWR.cpp index ed9d16a..c50493b 100755 --- a/waspmote-api/WaspPWR.cpp +++ b/waspmote-api/WaspPWR.cpp @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.14 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, David Cuartielles, Yuri Carmona */ @@ -117,6 +117,7 @@ void WaspPWR::setSensorPower(uint8_t type, uint8_t mode) { digitalWrite(SENS_PW_5V,HIGH); WaspRegister |= REG_5V; + delay(1); } else if( mode == SENS_OFF ) { @@ -172,7 +173,50 @@ void WaspPWR::setWatchdog(uint8_t mode, uint8_t timer) * It switches off all Waspmote switches */ void WaspPWR::switchesOFF(uint8_t option) -{ +{ + // check if main 3V3 will be kept + // in that case sleep the eeprom memory + if (!((ACC.accInt == NO_INT) && (option == ALL_OFF))) + { + if (_boot_version >= 'G') + { + uint8_t error = 0; + uint8_t I2C_EEPROM_INFO[] = { 0x09, 0x0C, 0x00, 0x00, 0x0C, 0x00, 0x00}; + eeprom.ON(); + error += eeprom.sendCommand(I2C_EEPROM_INFO); + error += eeprom.sleepCommand(); + + if (error == 0) + { + Utils.setLED(LED0, LED_OFF); + } + else + { + Utils.setLED(LED0, LED_ON); + } + } + } + + // power down the accelerometer when ACC_INT is not used + if (ACC.accInt == NO_INT) + { + // switch on if neccesary + if (!ACC.isON) + { + ACC.ON(); + } + + // set power-down mode + ACC.setMode(ACC_POWER_DOWN); + } + + // Switch off both multiplexers in UART_0 and UART_1 + Utils.muxOFF(); + + // set the XBee monitorization pin to zero + pinMode(XBEE_MON, OUTPUT); + digitalWrite(XBEE_MON, LOW); + // set this pin LOW to decrease consumption // if hibernate is not used pinMode(RTC_SLEEP, OUTPUT); @@ -182,26 +226,26 @@ void WaspPWR::switchesOFF(uint8_t option) pinMode(I2C_SDA,OUTPUT); digitalWrite(I2C_SDA,LOW); pinMode(I2C_SCL,OUTPUT); - digitalWrite(I2C_SCL,LOW); + digitalWrite(I2C_SCL,LOW); + Wire.isON = false; // switch Analog to Digital Converter OFF - cbi(ADCSRA,ADEN); - - //pinMode(SERID_PW,OUTPUT); - //digitalWrite(SERID_PW,LOW); + cbi(ADCSRA,ADEN); // Disable MEM_PW and SS_PIN not to waste // battery from SD when Waspmote is asleep pinMode(SD_SS, OUTPUT); - digitalWrite(SD_SS, LOW); + digitalWrite(SD_SS, LOW); pinMode(MEM_PW,OUTPUT); digitalWrite(MEM_PW,LOW); + SPI.isSD = false; // Set down SOCKET0 SPI SS pin pinMode(SOCKET0_SS,OUTPUT); digitalWrite(SOCKET0_SS,LOW); - if( option & SENS_OFF ) + // Switch off sensor board power supply + if ((option == ALL_OFF) || (option == SENS_OFF) || (option == SOCKET0_ON)) { // switch OFF sensor boards PWR.setSensorPower(SENS_3V3, SENS_OFF); @@ -212,42 +256,42 @@ void WaspPWR::switchesOFF(uint8_t option) // close UART0 closeSerial(SOCKET0); - if( option & SOCKET0_OFF ) + // switch off SOCKET0 if needed + if ((option == ALL_OFF) || (option == SOCKET0_OFF) || (option == SENSOR_ON)) { // set SOCKET0 power supply off - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,LOW); + PWR.powerSocket(SOCKET0, LOW); // update Waspmote Register WaspRegister &= ~(REG_SOCKET0); - } + } // close UART1 - closeSerial(SOCKET1); + closeSerial(SOCKET1); + // set SOCKET1 power supply off + PWR.powerSocket(SOCKET1, LOW); // set Expansion board power supply off unless a // Smart Cities board remains powered on - if( ( option & SENS_OFF ) - && !(WaspRegister & REG_CITIES_V14) - && !(WaspRegister & REG_CITIES_V15) ) + if (((option == ALL_OFF) || (option == SENS_OFF) || (option == SOCKET0_ON)) + && !(WaspRegisterSensor & REG_CITIES_V14) + && !(WaspRegisterSensor & REG_CITIES_V15)) { pinMode(DIGITAL6, OUTPUT); digitalWrite(DIGITAL6, LOW); } - // switch off the RTC power supply - RTC.close(); - pinMode(RTC_PW,OUTPUT); - digitalWrite(RTC_PW,LOW); - closeI2C(); - // switch off the battery monitor power supply pinMode(BAT_MONITOR_PW,OUTPUT); digitalWrite(BAT_MONITOR_PW,LOW); + // switch off monitoring pin + pinMode(BAT_MONITOR,OUTPUT); + digitalWrite(BAT_MONITOR,LOW); + // check if a Smart Metering board has been switched and proceed to disable // the digital pins so as not to waste energy - if( WaspRegister & REG_METERING ) + if (WaspRegisterSensor & REG_METERING) { setSensorPower(SENS_3V3,SENS_ON); pinMode(DIGITAL3, OUTPUT); @@ -258,14 +302,14 @@ void WaspPWR::switchesOFF(uint8_t option) // check if a Gases Sensor Board is used. In this case, switch off the // digital pins so as not to waste energy - if( WaspRegister & REG_GASES ) + if (WaspRegisterSensor & REG_GASES) { digitalWrite(DIGITAL4,LOW); } // check if an Agriculture Sensor Board is used. In this case, // switch off the digital pins so as not to waste energy - if( WaspRegister & REG_AGRICULTURE ) + if (WaspRegisterSensor & REG_AGRICULTURE) { // switch off sensors power supply digitalWrite(DIGITAL7, LOW); @@ -278,7 +322,12 @@ void WaspPWR::switchesOFF(uint8_t option) // set the interruption line down pinMode(MUX_RX, INPUT); - digitalWrite(MUX_RX, LOW); + digitalWrite(MUX_RX, LOW); + + // set the interruption line high +//~ pinMode(MUX_TX, INPUT); +//~ digitalWrite(MUX_TX, HIGH); + } @@ -286,17 +335,18 @@ void WaspPWR::switchesOFF(uint8_t option) * * It switches on all Waspmote switches */ -void WaspPWR::switchesON(uint8_t option) +void WaspPWR::switchesON(uint8_t option) { // switch Analog to Digital Converter ON - sbi(ADCSRA,ADEN); - - if( option & SENS_OFF ) + sbi(ADCSRA, ADEN); + + if ((option == ALL_OFF) || (option == SENS_OFF) || (option == SOCKET0_ON)) { pinMode(SENS_PW_3V3,OUTPUT); digitalWrite(SENS_PW_3V3,HIGH); pinMode(SENS_PW_5V,OUTPUT); digitalWrite(SENS_PW_5V,HIGH); + delay(50); } } @@ -312,62 +362,18 @@ void WaspPWR::switchesON(uint8_t option) */ void WaspPWR::sleep(uint8_t option) { - uint8_t retries=0; - - // Switch off both multiplexers in UART_0 and UART_1 - Utils.muxOFF(); - - // set the XBee monitorization pin to zero - pinMode(XBEE_MON,OUTPUT); - digitalWrite(XBEE_MON,LOW); - - // switch on and off the RTC so as to unset RTC interruption signal - RTC.ON(); - RTC.OFF(); - - // switches off depending on the option selected - switchesOFF(option); - - // mandatory delay to wait for MUX_RX stabilization - // after switching off the sensor boards - delay(100); - - // make sure interruption pin is LOW before entering a low power state - // if not the interruption will never come - while(digitalRead(MUX_RX)==HIGH) - { - // clear all detected interruption signals - delay(1); - PWR.clearInterruptionPin(); - retries++; - if(retries>10) - { - return (void)0; - } - } - - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_enable(); - sleep_mode(); - sleep_disable(); - - if( intFlag & RTC_INT ) - { - RTC.ON(); - RTC.clearAlarmFlag(); - RTC.OFF(); - } - - //~ switchesON(option); + sleep(0xFF, option); } /* sleep(timer) - sets the microcontroller to the lowest consumption sleep mode * - * It sets the microcontroller to the lowest consumption sleep mode. It enables watchdog interruption to be able to - * wake up the microcontroller after 'timer' time. + * It sets the microcontroller to the lowest consumption sleep mode. It enables + * watchdog interruption to be able to wake up the microcontroller after 'timer' + * time * - * 'timer' --> it specifies the time before the watchdog activates the interruption. Possible values are: + * 'timer' --> it specifies the time before the watchdog activates the + * interruption. Possible values are: * WTD_16MS 0 * WTD_32MS 1 * WTD_64MS 2 @@ -384,20 +390,14 @@ void WaspPWR::sleep(uint8_t option) * It returns nothing. */ void WaspPWR::sleep(uint8_t timer, uint8_t option) -{ - uint8_t retries=0; - - // Switch off both multiplexers in UART_0 and UART_1 - Utils.muxOFF(); - - // set the XBee monitorization pin to zero - pinMode(XBEE_MON,OUTPUT); - digitalWrite(XBEE_MON,LOW); - - // switch on and off the RTC so as to unset RTC interruption signal +{ + // enable the microcontroller sleep mode + sleep_enable(); + + // Switch off RTC (Waspv12) RTC.ON(); - RTC.OFF(); - + RTC.OFF(); + // switches off depending on the option selected switchesOFF(option); @@ -405,89 +405,103 @@ void WaspPWR::sleep(uint8_t timer, uint8_t option) // after switching off the sensor boards delay(100); - // make sure interruption pin is LOW before entering a low power state - // if not the interruption will never come - while(digitalRead(MUX_RX)==HIGH) + // switch off main power supply when needed: + // -> ACC interruption is disabled + // -> Sensor interruption is disabled + // -> XBee interruption is disabled + if ((ACC.accInt == NO_INT) && (option == ALL_OFF)) { - // clear all detected interruption signals - delay(1); - PWR.clearInterruptionPin(); - retries++; - if(retries>10) + digitalWrite(POWER_3V3, LOW); + } + + // *** set sleep mode *** + // check interruption pins and register are ok + if (!digitalRead(MUX_RX)) + { + // set sleep mode + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + + if (timer != 0xFF) { - return (void)0; + // set watchdog timer to cause interruption for selected time + setWatchdog(WTD_ON, timer); } + sleep_mode(); } - - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_enable(); - - // set watchdog timer to cause interruption for selected time - setWatchdog(WTD_ON,timer); - sleep_mode(); + // wake up here sleep_disable(); - if( intFlag & RTC_INT ) + // switch on main power supply + digitalWrite(POWER_3V3,HIGH); + + if (intFlag & RTC_INT) { RTC.ON(); RTC.clearAlarmFlag(); RTC.OFF(); - } - //~ switchesON(option); - + } } -/* deepSleep(time2wake, offset, mode) - sets the microcontroller to the lowest consumption sleep mode + +/* + * deepSleep() * - * It sets the microcontroller to the lowest consumption sleep mode. It enables RTC interruption to be able to - * wake up the microcontroller when the RTC alarm is launched. + * It sets the microcontroller to the sleep mode. It enables RTC interruption to + * be able to wake up the microcontroller when the RTC alarm is generated. It + * uses Alarm1 on the RTC due to this Alarm. It switches off all the switches on + * the Waspmote board. + * + * Parameters: + * time2wake: it specifies the time at which the RTC alarm will activate. It + * must follow the next format:"DD:HH:MM:SS" + * offset: it specifies if 'time2wake' is added to the actual time or if + * this time is set as the alarm + * mode: it specifies the mode for RTC alarm * - * 'time2wake' --> it specifies the time at which the RTC alarm will activate. It must follow the next format: - * "DD:HH:MM:SS" - * 'offset' --> it specifies if 'time2wake' is added to the actual time or if this time is set as the alarm - * 'mode' --> it specifies the mode for RTC alarm + * + * Return: void + */ +void WaspPWR::deepSleep(const char* time2wake, + uint8_t offset, + uint8_t mode) +{ + return deepSleep(time2wake, offset, mode, ALL_OFF); +} + + +/* + * deepSleep() * - * It uses Alarm1 on the RTC due to this Alarm has more precision than Alarm2 + * It sets the microcontroller to the sleep mode. It enables RTC interruption to + * be able to wake up the microcontroller when the RTC alarm is generated. It + * uses Alarm1 on the RTC due to this Alarm. * - * It switches off all the switches on the Waspmote board. + * Parameters: + * time2wake: it specifies the time at which the RTC alarm will activate. It + * must follow the next format:"DD:HH:MM:SS" + * offset: it specifies if 'time2wake' is added to the actual time or if + * this time is set as the alarm + * mode: it specifies the mode for RTC alarm + * option: Option to switch off when entering deep sleep * - * It returns nothing. + * + * Return: void */ -void WaspPWR::deepSleep( const char* time2wake, - uint8_t offset, - uint8_t mode, - uint8_t option ) +void WaspPWR::deepSleep(const char* time2wake, + uint8_t offset, + uint8_t mode, + uint8_t option) { - uint8_t retries=0; - - // Switch off both multiplexers in UART_0 and UART_1 - Utils.muxOFF(); - - // set the XBee monitorization pin to zero - pinMode(XBEE_MON,OUTPUT); - digitalWrite(XBEE_MON,LOW); + // enable the microcontroller sleep mode + sleep_enable(); // switches off depending on the option selected switchesOFF(option); // mandatory delay to wait for MUX_RX stabilization // after switching off the sensor boards - delay(100); - - // make sure interruption pin is LOW before entering a low power state - // if not the interruption will never come - while(digitalRead(MUX_RX)==HIGH) - { - // clear all detected interruption signals - delay(1); - PWR.clearInterruptionPin(); - retries++; - if(retries>10) - { - return (void)0; - } - } + delay(100); // RTC ON RTC.ON(); @@ -508,19 +522,38 @@ void WaspPWR::deepSleep( const char* time2wake, { RTC.disableAlarm1(); RTC.OFF(); + USB.println("[PWR] deepSleep RTC error"); return (void)0; } - RTC.OFF(); + RTC.OFF(); - // set sleep mode - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_enable(); - sleep_mode(); + // switch off main power supply when needed: + // -> ACC interruption is disabled + // -> Sensor interruption is disabled + // -> XBee interruption is disabled + if ((ACC.accInt == NO_INT) && (option == ALL_OFF)) + { + digitalWrite(POWER_3V3, LOW); + } + + // *** set sleep mode *** + // check interruption pins and register are ok + if (!digitalRead(MUX_RX)) + { + // set sleep mode + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_mode(); + } + else + { + USB.ON(); + USB.println("[PWR] Noise in Interruption line"); + } + // wake up here sleep_disable(); - - // in the case SENS_OFF was an option is mandatory to turn on the - // sensor boards before setting up the I2C bus - switchesON(option); + + // switch on main power supply + digitalWrite(POWER_3V3,HIGH); // Switch on the RTC and clear the alarm signals // Disable RTC interruption after waking up @@ -529,15 +562,11 @@ void WaspPWR::deepSleep( const char* time2wake, RTC.clearAlarmFlag(); RTC.OFF(); - // Keep sensor supply powered down if selected - if( option & SENS_OFF ) - { - pinMode(SENS_PW_3V3,OUTPUT); - digitalWrite(SENS_PW_3V3,LOW); - pinMode(SENS_PW_5V,OUTPUT); - digitalWrite(SENS_PW_5V,LOW); - } + //SPI.setSPISlave(ALL_DESELECTED); } + + + /* * hibernate(time2wake, offset, mode) - enter a hibernate state * @@ -552,8 +581,9 @@ void WaspPWR::hibernate(const char* time2wake, uint8_t offset, uint8_t mode) // set EEPROM Hibernate flag eeprom_write_byte((unsigned char *) HIB_ADDR, HIB_VALUE); - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW, LOW); + // switch off socket power + PWR.powerSocket(SOCKET0, LOW); + //~ closeSerial(0); //~ while(digitalRead(GPS_PW)) //~ { @@ -613,45 +643,39 @@ void WaspPWR::hibernate(const char* time2wake, uint8_t offset, uint8_t mode) */ uint8_t WaspPWR::getBatteryLevel() { - float aux=0; - uint8_t resul=0; - pinMode(BAT_MONITOR_PW,OUTPUT); - digitalWrite(BAT_MONITOR_PW,HIGH); - - // delay in order to stabilize the measurement - delay(1); - - // read value - aux=analogRead(0); - + float volts = 0; + int bits; + float aux; + uint8_t percentage = 0; + + // read battery volts + volts = getBatteryVolts(); + + // convert from volts to bits + bits = volts*1023/3.3; + aux = (float)bits/2.0; // voltage divider + + // make conversion from bits to '%' units if (aux < 512) { - aux = 0; - resul=(uint8_t) aux; - digitalWrite(BAT_MONITOR_PW,LOW); - return resul; + percentage = 0; } - if (aux > 651) + else if (aux > 651) { - aux = 100; - resul=(uint8_t) aux; - digitalWrite(BAT_MONITOR_PW,LOW); - return resul; + percentage = 100; } - if ((aux <= 651)&&(aux > 543)) + else if (aux > 543) { aux = (aux * (90.0/108.0)) - 442.0; - resul=(uint8_t) aux; - digitalWrite(BAT_MONITOR_PW,LOW); - return resul; + percentage = (uint8_t) aux; } else { aux = ((10.0/(543.0-511.0)) * aux) - 160.0; - resul=(uint8_t) aux; - digitalWrite(BAT_MONITOR_PW,LOW); - return resul; - } + percentage = (uint8_t) aux; + } + + return percentage; } @@ -666,17 +690,147 @@ uint8_t WaspPWR::getBatteryLevel() */ float WaspPWR::getBatteryVolts() { - float aux_volts=0; - pinMode(BAT_MONITOR_PW,OUTPUT); - digitalWrite(BAT_MONITOR_PW,HIGH); - aux_volts=analogRead(0); - aux_volts=analogRead(0); - digitalWrite(BAT_MONITOR_PW,LOW); - return aux_volts*3.3*2.0/1023.0; -} + if (_boot_version < 'G') + { + float aux_volts=0; + pinMode(BAT_MONITOR, INPUT); + pinMode(BAT_MONITOR_PW, OUTPUT); + digitalWrite(BAT_MONITOR_PW, HIGH); + aux_volts = analogRead(0); + aux_volts = analogRead(0); + digitalWrite(BAT_MONITOR_PW, LOW); + return aux_volts*3.3*2.0/1023.0; + } + else + { + float result = 0; + int nSamples = 10; + int values[nSamples]; + + // change to REF 2.56V + analogReference(INTERNAL2V56); + + // enables the ADC + sbi(ADCSRA, ADEN); + + // power on the components + pinMode(BAT_MONITOR, INPUT); + PWR.setSensorPower(SENS_5V, SENS_ON); + pinMode(BAT_MONITOR_PW, OUTPUT); + digitalWrite(BAT_MONITOR_PW, HIGH); + delay(1); + + // dummy readings + for(int i = 0; i= 3) + if (counter >= 3) { break; } @@ -753,9 +907,9 @@ void WaspPWR::ifHibernate() } // make sure both digital pins are off depending on the boot version - if( Utils.getBootVersion() < 'E') + if (Utils.getBootVersion() < 'E') { - if(digitalRead(RTC_SLEEP)||digitalRead(RST_RTC)) + if (digitalRead(RTC_SLEEP) || digitalRead(RST_RTC)) { digitalWrite(RTC_SLEEP,LOW); digitalWrite(RST_RTC, LOW); @@ -788,48 +942,52 @@ void WaspPWR::reboot() // clear all kind of Interruption signal in Waspmote void WaspPWR::clearInterruptionPin() { - // unset XBee interruption line - pinMode(XBEE_MON,OUTPUT); - digitalWrite(XBEE_MON,LOW); - - // RTC module - if( digitalRead(RTC_INT_PIN_MON) ) - { - // clear RTC interrupt - RTC.ON(); - RTC.clearAlarmFlag(); - } - - // check ACC interruption - if( digitalRead(ACC_INT_PIN_MON)==HIGH ) - { - // clear ACC interrupt - ACC.ON(); + // check if there is a non-captured interruption and clear it + if (!intFlag && digitalRead(MUX_RX)) + { + // unset XBee interruption line + pinMode(XBEE_MON,OUTPUT); + digitalWrite(XBEE_MON,LOW); - switch(ACC.accInt) + // RTC module + if( digitalRead(RTC_INT_PIN_MON) ) { - case FF_INT: ACC.setFF(); - break; - - case IWU_INT: ACC.setIWU(); - break; - - case _6DMOV_INT:ACC.set6DMovement(); - break; - - case _6DPOS_INT:ACC.set6DPosition(); - break; - - case NO_INT: break; + // clear RTC interrupt + RTC.ON(); + RTC.clearAlarmFlag(); + } + + // check ACC interruption + if( digitalRead(ACC_INT_PIN_MON)==HIGH ) + { + // clear ACC interrupt + ACC.ON(); - default: // do nothing - break; - } + switch(ACC.accInt) + { + case FF_INT: ACC.setFF(); + break; + + case IWU_INT: ACC.setIWU(); + break; + + case _6DMOV_INT:ACC.set6DMovement(); + break; + + case _6DPOS_INT:ACC.set6DPosition(); + break; + + case NO_INT: break; + + default: // do nothing + break; + } + } + + // set the interruption line down + pinMode(MUX_RX, INPUT); + digitalWrite(MUX_RX, LOW); } - - // set the interruption line down - pinMode(MUX_RX, INPUT); - digitalWrite(MUX_RX, LOW); } @@ -841,7 +999,7 @@ void WaspPWR::printIntFlag() { USB.println(F(" __________________________________________________________")); USB.println(F("| | | | | | | | | |")); - USB.println(F("| PIR_3G | XBEE | RAD | HIB | PLV | SENS | WTD | RTC | ACC |")); + USB.println(F("| PIR_3G | -- | RAD | HIB | PLV | SENS | WTD | RTC | ACC |")); USB.println(F("|________|______|_____|_____|_____|______|_____|_____|_____|")); USB.print(F(" ")); USB.print(bool(intFlag & PIR_3G_INT)); @@ -867,6 +1025,90 @@ void WaspPWR::printIntFlag() + +/* + * powerSocket() - powers on/off the socket selected as input + */ +void WaspPWR::powerSocket(uint8_t socket, uint8_t state) +{ + switch (socket) + { + case SOCKET0: + pinMode(SOCKET0_PW, OUTPUT); + digitalWrite(SOCKET0_PW, state); + break; + + case SOCKET1: + pinMode(DIGITAL6, OUTPUT); + digitalWrite(DIGITAL6, state); + break; + + default: + break; + } +} + + + + +/* + * + * + */ +void WaspPWR::checkPeripherals() +{ + uint8_t answer; + + // define object for UART0 + WaspUART uart0 = WaspUART(); + + // init object in SOCKET0 + uart0.setUART(SOCKET0); + + // select multiplexer + Utils.setMuxSocket0(); + + // begin serial communication + uart0.beginUART(); + + // power on the socket + PWR.powerSocket(SOCKET0, HIGH); + delay(500); + serialFlush(SOCKET0); + + // check for XBees in SOCKET0 + uint8_t cmd_xbee[] = {0x7E, 0x00 , 0x04 , 0x08 , 0x01 , 0x56 , 0x52 , 0x4E}; + + // send command & receive answer + uart0.sendCommand(cmd_xbee, sizeof(cmd_xbee)); + uart0.readBuffer(100); + + // check response: 7E00078801565200xxxx?? + if (uart0._length > 0) + { + if ((uart0._buffer[0] == 0x7E) + && (uart0._buffer[1] == 0x00) + && (uart0._buffer[3] == 0x88) + && (uart0._buffer[4] == 0x01) + && (uart0._buffer[5] == 0x56) + && (uart0._buffer[6] == 0x52) + && (uart0._buffer[7] == 0x00)) + { + /* + USB.print(F("XBee module in SOCKET0. Firmware: ")); + USB.printHex(uart0._buffer[8]); + USB.printHex(uart0._buffer[9]); + USB.println(); + */ + + // mark corresponding flag in WaspRegister + WaspRegister |= REG_XBEE_SOCKET0; + } + } + +} + + // Private Methods ///////////////////////////////////////////////////////////// // Preinstantiate Objects ////////////////////////////////////////////////////// diff --git a/waspmote-api/WaspPWR.h b/waspmote-api/WaspPWR.h index a1a54a4..bc08c2a 100755 --- a/waspmote-api/WaspPWR.h +++ b/waspmote-api/WaspPWR.h @@ -1,7 +1,7 @@ /*! \file WaspPWR.h \brief Library for managing Waspmote Power & Energy Modes - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.2 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, David Cuartielles, Yuri Carmona @@ -36,6 +36,7 @@ ******************************************************************************/ #include +#include /****************************************************************************** @@ -113,16 +114,12 @@ /*! \def ALL_ON \brief Sleep Options. Do not switch off anything */ -#define SENS_OFF 1 -#define SOCKET0_OFF 2 -#define ALL_OFF SENS_OFF | SOCKET0_OFF #define ALL_ON 0 - -//! DEPRECATED definitions. *** FIXME: To be deleted -#define BAT_OFF ALL_ON -//#define RTC_OFF ALL_ON //! It was redefined -#define UART0_OFF SOCKET0_OFF -#define UART1_OFF ALL_ON +#define SENS_OFF 1 // redefined +#define SOCKET0_OFF 2 +#define ALL_OFF 3 //SENS_OFF | SOCKET0_OFF +#define SOCKET0_ON 5 +#define SENSOR_ON 6 /*! \def HIB_ADDR @@ -138,7 +135,8 @@ extern volatile uint16_t intFlag; extern volatile uint16_t intConf; extern volatile uint8_t intCounter; extern volatile uint8_t intArray[8]; -extern volatile unsigned long WaspRegister; +extern volatile uint16_t WaspRegister; +extern volatile uint16_t WaspRegisterSensor; /****************************************************************************** @@ -154,27 +152,24 @@ class WaspPWR { private: - //! It sets a certain internal peripheral on /*! - \param uint8_t peripheral : the peripheral to set on + \brief It sets a certain internal peripheral on + \param uint8_t peripheral : the peripheral to set on \return void - \sa resetIPF(uint8_t peripheral), getIPF() */ void setIPF(uint8_t peripheral); - //! It sets a certain internal peripheral off /*! - \param uint8_t peripheral : the peripheral to set off + \brief It sets a certain internal peripheral off + \param uint8_t peripheral : the peripheral to set off \return void - \sa setIPF(uint8_t peripheral), getIPF() */ void resetIPF(uint8_t peripheral); - //! It gets the whole IPR /*! - \param void + \brief It gets the whole IPR + \param void \return the IPRA flag - \sa setIPF(uint8_t peripheral), resetIPF(uint8_t peripheral) */ uint8_t getIPF(); @@ -192,133 +187,178 @@ class WaspPWR */ WaspPWR(); - //! It sets ON/OFF 3V3 or 5V switches - /*! - \param uint8_t type : SENS_3V3 or SENS_5V - \param uint8_t mode : SENS_ON or SENS_OFF + /*! + \brief It sets ON/OFF 3V3 or 5V switches + \param uint8_t type: + \arg SENS_3V3 + \arg SENS_5V + \param uint8_t mode: + \arg SENS_ON + \arg SENS_OFF \return void */ - void setSensorPower(uint8_t type, uint8_t mode); + void setSensorPower(uint8_t type, uint8_t mode); - //! It enables or disables watchdog interruption - /*! - \param uint8_t mode : WTD_ON or WTD_OFF - \param uint8_t timer : WTD_16MS, WTD_32MS, WTD_64MS, WTD_128MS, WTD_250MS, - WTD_500MS, WTD_1S, WTD_2S, WTD_4S or WTD_8S + /*! + \brief It enables or disables watchdog interruption + \param uint8_t mode: + \arg WTD_ON + \arg WTD_OFF + \param uint8_t timer: + \arg WTD_16MS + \arg WTD_32MS + \arg WTD_64MS + \arg WTD_128MS + \arg WTD_250MS + \arg WTD_500MS + \arg WTD_1S + \arg WTD_2S + \arg WTD_4S + \arg WTD_8S \return void */ - void setWatchdog(uint8_t mode, uint8_t timer); + void setWatchdog(uint8_t mode, uint8_t timer); - //! It switches off the specified Waspmote switches - /*! + /*! + \brief It switches off the specified Waspmote switches \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF \return void - \sa switchesON(uint8_t option) */ - void switchesOFF(uint8_t option); + void switchesOFF(uint8_t option); - //! It switches on the specified Waspmote switches - /*! + /*! + \brief It switches on the specified Waspmote switches \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF \return void - \sa switchesOFF(uint8_t option) */ - void switchesON(uint8_t option); - - //! It sets the microcontroller to the lowest consumption sleep mode + void switchesON(uint8_t option); + /*! + \brief It sets the microcontroller to the lowest consumption sleep mode \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF \return void - \sa sleep(uint8_t timer, uint8_t option), deepSleep(const char* time2wake, - uint8_t offset, uint8_t mode, uint8_t option), - hibernate(const char* time2wake, uint8_t offset, uint8_t mode) */ - void sleep(uint8_t option); + void sleep(uint8_t option); - //! It sets the microcontroller to the lowest consumption sleep mode - //! enabling the watchdog /*! + \brief It sets the microcontroller to the lowest consumption sleep mode + enabling the watchdog \param uint8_t timer : WTD_16MS, WTD_32MS, WTD_64MS, WTD_128MS, WTD_250MS, WTD_500MS, WTD_1S, WTD_2S, WTD_4S or WTD_8S \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF \return void - \sa sleep(uint8_t option) - \sa deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option) - \sa hibernate(const char* time2wake, uint8_t offset, uint8_t mode) */ - void sleep(uint8_t timer, uint8_t option); + void sleep(uint8_t timer, uint8_t option); - //! It sets the microcontroller to the lowest consumption sleep mode - //! enabling RTC interruption + /*! + \brief It sets the microcontroller to the lowest consumption sleep mode + enabling RTC interruption \param const char* time2wake : string that indicates the time to wake up. - It looks like "dd:hh:mm:ss" - \param uint8_t offset : RTC_OFFSET or RTC_ABSOLUTE - \param uint8_t mode : RTC_ALM1_MODE1, RTC_ALM1_MODE2, RTC_ALM1_MODE3, - RTC_ALM1_MODE4 or RTC_ALM1_MODE5 - \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF + It looks like "dd:hh:mm:ss" + \param uint8_t offset: + \arg RTC_OFFSET + \arg RTC_ABSOLUTE + \param uint8_t mode: + \arg RTC_ALM1_MODE1 + \arg RTC_ALM1_MODE2 + \arg RTC_ALM1_MODE3 + \arg RTC_ALM1_MODE4 + \arg RTC_ALM1_MODE5 + \param uint8_t option : ALL_ON, ALL_OFF, SENS_OFF, SOCKET0_OFF, SENSOR_ON \return void - \sa sleep(uint8_t option) - \sa sleep(uint8_t timer, uint8_t option) - \sa hibernate(const char* time2wake, uint8_t offset, uint8_t mode) */ - void deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option); + void deepSleep(const char* time2wake, uint8_t offset, uint8_t mode); + void deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option); + - //! It switches off the general switch enabling RTC interruption /*! + \brief It switches off the general switch enabling RTC interruption \param const char* time2wake : string that indicates the time to wake up. - It looks like "dd:hh:mm:ss" - \param uint8_t offset : RTC_OFFSET or RTC_ABSOLUTE - \param uint8_t mode : RTC_ALM1_MODE1, RTC_ALM1_MODE2, RTC_ALM1_MODE3, - RTC_ALM1_MODE4 or RTC_ALM1_MODE5 + It looks like "dd:hh:mm:ss" + \param uint8_t offset: + \arg RTC_OFFSET + \arg RTC_ABSOLUTE + \param uint8_t mode : + \arg RTC_ALM1_MODE1 + \arg RTC_ALM1_MODE2 + \arg RTC_ALM1_MODE3 + \arg RTC_ALM1_MODE4 + \arg RTC_ALM1_MODE5 \return void - \sa sleep(uint8_t option) - \sa sleep(uint8_t timer, uint8_t option) - \sa deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option) */ - void hibernate(const char* time2wake, uint8_t offset, uint8_t mode); + void hibernate(const char* time2wake, uint8_t offset, uint8_t mode); - //! It gets the remaining battery % - /*! - \return the remaining battery % + + /*! + \brief It gets the remaining battery % + \return the remaining battery in % unit */ uint8_t getBatteryLevel(); - //! It gets the remaining battery in volts + + /*! + \brief It gets the remaining battery in volts + \return the remaining battery in volts + */ + float getBatteryVolts(); + + /*! - \return the remaining battery in volts % + \brief It gets the current charging the battery + \return the current charging the battery in mA */ - float getBatteryVolts(); + uint16_t getBatteryCurrent(); + - //! It closes I2C bus /*! + \brief It gets the state of the battery charger + \return the he state of the battery charger (1 Battery is being charged, 0 battery is not being charged) + */ + bool getChargingState(); + + /*! + \brief It closes I2C bus \return void */ - void closeI2C(); - - //! It checks if Hibernate has generated the reset + void closeI2C(); + /*! + \brief It checks if Hibernate has generated the reset \return void */ - void ifHibernate(); + void ifHibernate(); - //! It restarts Waspmote /*! + \brief It restarts Waspmote \return void */ - void reboot(); + void reboot(); - //! It cleans the interruption signal /*! + \brief It cleans the interruption signal \return void */ void clearInterruptionPin(); - //! It prints the 'intFlag' bitmap /*! + \brief It prints the 'intFlag' bitmap \return void */ void printIntFlag(); + + /*! + \brief Manage SOCKET0 or SOCKET1 to set them to ON/OFF state + \return void + */ + void powerSocket(uint8_t socket, uint8_t state); + + /*! + \brief Check if XBee modules are connected to SOCKET0 + \return void + */ + void checkPeripherals(); + }; extern WaspPWR PWR; diff --git a/waspmote-api/WaspRTC.cpp b/waspmote-api/WaspRTC.cpp index de37bc3..2dea26a 100755 --- a/waspmote-api/WaspRTC.cpp +++ b/waspmote-api/WaspRTC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * Functions getEpochTime(), breakTimeAbsolute(), breakTimeOffset() and @@ -19,7 +19,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.9 + * Version: 3.0 * Design: David Gascón * Implementation: Alberto Bielsa, David Cuartielles, Marcos Yarza, Yuri Carmona */ @@ -35,21 +35,21 @@ /// table_RTC ///////////////////////////////////////////////////////////////// const char rtc_string_00[] PROGMEM = "Alarm Mode matches "; -const char rtc_string_01[] PROGMEM = "[Day : hours : minutes : seconds] -> "; -const char rtc_string_02[] PROGMEM = "[Date : hours : minutes : seconds] -> "; -const char rtc_string_03[] PROGMEM = "[Hours : minutes : seconds] -> "; -const char rtc_string_04[] PROGMEM = "[Minutes : seconds] -> "; -const char rtc_string_05[] PROGMEM = "[Seconds] -> "; +const char rtc_string_01[] PROGMEM = "[Day:Hours:Minutes:Seconds] --> "; +const char rtc_string_02[] PROGMEM = "[Date:Hours:Minutes:Seconds] --> "; +const char rtc_string_03[] PROGMEM = "[Hours:Minutes:Seconds] --> "; +const char rtc_string_04[] PROGMEM = "[Minutes:Seconds] --> "; +const char rtc_string_05[] PROGMEM = "[Seconds] --> "; const char rtc_string_06[] PROGMEM = "Once per second"; const char rtc_string_07[] PROGMEM = "Incorrect alarm mode"; const char rtc_string_08[] PROGMEM = "[%02u:%02u:%02u:%02u]"; const char rtc_string_09[] PROGMEM = "[%02u:%02u:%02u]"; const char rtc_string_10[] PROGMEM = "[%02u:%02u]"; const char rtc_string_11[] PROGMEM = "[%02u]"; -const char rtc_string_12[] PROGMEM = "[Day : hours : minutes ] -> "; -const char rtc_string_13[] PROGMEM = "[Date : hours : minutes ] -> "; -const char rtc_string_14[] PROGMEM = "[Hours : minutes] -> "; -const char rtc_string_15[] PROGMEM = "[Minutes] -> "; +const char rtc_string_12[] PROGMEM = "[Day:Hours:Minutes] --> "; +const char rtc_string_13[] PROGMEM = "[Date:Hours:Minutes ] --> "; +const char rtc_string_14[] PROGMEM = "[Hours:Minutes] --> "; +const char rtc_string_15[] PROGMEM = "[Minutes] --> "; const char rtc_string_16[] PROGMEM = "Once per minute"; const char rtc_string_17[] PROGMEM = "%s, %02u/%02u/%02u, %02u:%02u:%02u"; const char rtc_string_18[] PROGMEM = "error"; @@ -144,7 +144,10 @@ void WaspRTC::OFF(void) */ void WaspRTC::close() { - if( Wire.I2C_ON && !ACC.isON) PWR.closeI2C(); + if (Wire.isON && !ACC.isON) + { + PWR.closeI2C(); + } } @@ -154,18 +157,23 @@ void WaspRTC::close() */ void WaspRTC::setMode(uint8_t mode, uint8_t I2C_mode) { + // set power supply as 'mode' + if (_boot_version < 'G') + { + pinMode(RTC_PW, OUTPUT); + digitalWrite(RTC_PW, mode); + } + _pwrMode = mode; - pinMode(RTC_PW,OUTPUT); switch(_pwrMode) { - case RTC_ON : digitalWrite(RTC_PW,HIGH); - if( I2C_mode==RTC_I2C_MODE ) isON = 2; - else if( I2C_mode==RTC_NORMAL_MODE ) isON = 1; + case RTC_ON : if (I2C_mode==RTC_I2C_MODE) isON = 2; + else if (I2C_mode==RTC_NORMAL_MODE) isON = 1; break; - case RTC_OFF : digitalWrite(RTC_PW,LOW); - isON = 0; + case RTC_OFF : isON = 0; break; } + // stabilization time after switching on delay(10); @@ -270,8 +278,11 @@ void WaspRTC::readRTC(uint8_t endAddress) uint16_t timecount = 0; uint16_t timeout = 0; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } // ADDRESSING FROM MEMORY POSITION ZERO // the address specified in the datasheet is 208 (0xD0) @@ -346,8 +357,11 @@ void WaspRTC::writeRTC() { int timecount = 0; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } Wire.beginTransmission(I2C_ADDRESS_WASP_RTC); // transmit to device #104 (0x4A) // the address specified in the datasheet is 208 (0xD0) @@ -381,8 +395,11 @@ void WaspRTC::writeRTCalarm1() { byte timecount = 0; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } Wire.beginTransmission(I2C_ADDRESS_WASP_RTC); // transmit to device #104 (0x4A) // the address specified in the datasheet is 208 (0xD0) @@ -413,8 +430,11 @@ void WaspRTC::writeRTCalarm2() { byte timecount = 0; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } Wire.beginTransmission(I2C_ADDRESS_WASP_RTC); // transmit to device #104 (0x4A) // the address specified in the datasheet is 208 (0xD0) @@ -702,8 +722,11 @@ void WaspRTC::configureAlarmMode (uint8_t alarmNum, uint8_t alarmMode) */ void WaspRTC::writeRTCregister(uint8_t theAddress) { - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } // ADDRESSING FROM MEMORY POSITION RECEIVED AS PARAMETER Wire.beginTransmission(I2C_ADDRESS_WASP_RTC); // transmit to device #104 (0x68) @@ -728,8 +751,11 @@ void WaspRTC::readRTCregister(uint8_t theAddress) { uint16_t timeout = 0; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } // ADDRESSING FROM MEMORY POSITION RECEIVED AS PARAMETER Wire.beginTransmission(I2C_ADDRESS_WASP_RTC); // transmit to device #104 (0x68) @@ -1745,11 +1771,15 @@ char* WaspRTC::getAlarm2() */ void WaspRTC::clearAlarmFlag() { - // get alarm which triggered last alarm - uint8_t trig = getAlarmTriggered(); - - // if a pending alarm is being generated then update attribute - if( trig != 0 ) alarmTriggered = trig; + // check hardware version + if (_boot_version < 'G') + { + // get alarm which triggered last alarm + uint8_t trig = getAlarmTriggered(); + + // if a pending alarm is being generated then update attribute + if( trig != 0 ) alarmTriggered = trig; + } // reset the alarm flags in RTC RTC.registersRTC[RTC_STATUS_ADDRESS] &= B11111100; @@ -2035,7 +2065,7 @@ uint8_t WaspRTC::setGMT(int8_t gmt) } else { - USB.println("Invalid GMT value"); + USB.println(F("Invalid GMT value")); _gmt = 0; return 1; } @@ -2117,6 +2147,122 @@ void WaspRTC::detachInt(void) clearAlarmFlag(); } +/* + * setWatchdog(uint16_t minutes) - Set Watchdog alarm to reset Waspmote + * + * + */ +void WaspRTC::setWatchdog(uint16_t minutesWatchdog) +{ + if (_boot_version < 'H') + { + USB.println(F("\n*************** WARNING *******************")); + USB.println(F("This example is valid only for Waspmote v15.")); + USB.println(F("Your Waspmote version is v12.")); + USB.println(F("*******************************************")); + return (void)0; + } + + uint8_t days = 0; + uint8_t hours = 0; + uint8_t minutes = 0; + + // check correct input + if (minutesWatchdog == 0) return (void)1; + + // If needed: Translate from 'minutes' to 'days, hours and minutes' + if (minutesWatchdog < 60) + { + minutes = (uint8_t) minutesWatchdog; + } + else if (minutesWatchdog < 1440) + { + hours = (uint8_t)(minutesWatchdog/60); + minutes = (uint8_t)(minutesWatchdog%60); + } + else if (minutesWatchdog < 43200) + { + days = (uint8_t)(minutesWatchdog/(24*60)); + hours = (uint8_t)(minutesWatchdog%24); + minutes = (uint8_t)(minutesWatchdog%(24*60)); + } + else + { + return (void)1; + } + + // get RTC status + uint8_t status = RTC.isON; + + // switch on RTC if needed + if (!status) + { + RTC.ON(); + } + + // Set Alarm2 for specified time + RTC.setAlarm2(days, hours, minutes, RTC_OFFSET, RTC_ALM2_MODE2); + + // switch off RTC if needed + if (!status) + { + RTC.OFF(); + } +} + +/* + * getWatchdog() - return the Watchdog alarm settings + * + * + */ +char* WaspRTC::getWatchdog() +{ + return RTC.getAlarm2(); +} + + + +/* + * unSetWatchdog() - Unset Watchdog alarm + * + * + */ +void WaspRTC::unSetWatchdog(void) +{ + // get RTC status + uint8_t status = RTC.isON; + + // switch on RTC if needed + if (!status) + { + RTC.ON(); + } + + // disable the RTC alarm2 + RTC.disableAlarm2(); + + // switch off RTC if needed + if (!status) + { + RTC.OFF(); + } +} + + +/* + * disableSQW() - Disable SQW Square Wave Output on the SQW/INTB pin + * + * + */ +void WaspRTC::disableSQW(void) +{ + // set INTCN to '1' + registersRTC[RTC_CONTROL_ADDRESS] &= B11111011; + registersRTC[RTC_CONTROL_ADDRESS] |= B00000100; + writeRTCregister(RTC_CONTROL_ADDRESS); +} + + // Private Methods ///////////////////////////////////////////////////////////// // Preinstantiate Objects ////////////////////////////////////////////////////// diff --git a/waspmote-api/WaspRTC.h b/waspmote-api/WaspRTC.h index 758394c..7e88367 100755 --- a/waspmote-api/WaspRTC.h +++ b/waspmote-api/WaspRTC.h @@ -1,7 +1,7 @@ /*! \file WaspRTC.h \brief Library for managing the RTC - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com Functions getEpochTime(), breakTimeAbsolute(), breakTimeOffset() and @@ -21,7 +21,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.5 + Version: 3.0 Design: David Gascón Implementation: A. Bielsa, D. Cuartielles, M. Yarza, Y. Carmona @@ -105,13 +105,13 @@ /*! \def RTC_LSB_TEMP_ADDRESS \brief RTC Addresses constants. LSB Temperature register in this case */ -#define RTC_SECONDS_ADDRESS 0x00 -#define RTC_MINUTES_ADDRESS 0x01 -#define RTC_HOURS_ADDRESS 0x02 -#define RTC_DAYS_ADDRESS 0x03 -#define RTC_DATE_ADDRESS 0x04 -#define RTC_MONTH_ADDRESS 0x05 -#define RTC_YEAR_ADDRESS 0x06 +#define RTC_SECONDS_ADDRESS 0x00 +#define RTC_MINUTES_ADDRESS 0x01 +#define RTC_HOURS_ADDRESS 0x02 +#define RTC_DAYS_ADDRESS 0x03 +#define RTC_DATE_ADDRESS 0x04 +#define RTC_MONTH_ADDRESS 0x05 +#define RTC_YEAR_ADDRESS 0x06 #define RTC_ALM1_START_ADDRESS 0x07 #define RTC_ALM1_SECONDS_ADDRESS 0x07 #define RTC_ALM1_MINUTES_ADDRESS 0x08 @@ -611,9 +611,7 @@ class WaspRTC /*! \param const char* time : the time and date to set in the RTC. It looks like "YY:MM:DD:dow:hh:mm:ss" - \return void - \sa setTime(uint8_t year, uint8_t month, uint8_t date, uint8_t day_week, - uint8_t hour, uint8_t minute, uint8_t second), getTime() + \return '0' if OK; '1' if error */ uint8_t setTime(const char* time); @@ -626,16 +624,15 @@ class WaspRTC \param uint8_t hour : the hours to set in the RTC \param uint8_t minute : the minutes to set in the RTC \param uint8_t second : the seconds to set in the RTC - \return '0' on succes, '1' otherwise - \sa setTime(const char* time), getTime() + \return '0' if OK; '1' if error */ - uint8_t setTime( uint8_t year, + uint8_t setTime(uint8_t year, uint8_t month, uint8_t date, uint8_t day_week, uint8_t hour, uint8_t minute, - uint8_t second ); + uint8_t second); //! It gets from the RTC the date and time, storing them in the //! corresponding variables @@ -815,7 +812,7 @@ class WaspRTC //! It gets GMT value /*! This function get the GMT variable \param void - \return int8_t _gmt + \return int8_t _gmt */ int8_t getGMT(); @@ -823,12 +820,33 @@ class WaspRTC /*! This function gets the two last bit of the RTC status register and * returns the number of the alarm has been triggered \param void - \return uint8_t 1 if alarm 1 has been triggered - 2 if alarm 2 has been triggered - 3 if both alarms have been triggered + \return uint8_t 1 if alarm 1 has been triggered + 2 if alarm 2 has been triggered + 3 if both alarms have been triggered */ uint8_t getAlarmTriggered(); + + /*! It sets the RTC alarm2 for generating a Waspmote reset + \param uint16_t minutesWatchdog indicates the number of minute hand changes + to perform before the reset is done + \return void + */ + void setWatchdog(uint16_t minutesWatchdog); + + /*! It gets the RTC alarm2 settings for generating a Waspmote reset + \return pointer to the buffer which stores the watchdog time settings + */ + char* getWatchdog(); + /*! It disables the RTC alarm2 so no reset will be done + \return void + */ + void unSetWatchdog(void); + + /*! It disables the SQW output from the RTC + \return void + */ + void disableSQW(); }; extern WaspRTC RTC; diff --git a/waspmote-api/WaspSD.cpp b/waspmote-api/WaspSD.cpp index 3d4f469..b3c8734 100755 --- a/waspmote-api/WaspSD.cpp +++ b/waspmote-api/WaspSD.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.7 + * Version: 3.0 * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona */ @@ -2670,7 +2670,11 @@ void WaspSD::setFileDate() PWR.setSensorPower(SENS_5V,SENS_ON); PWR.setSensorPower(SENS_3V3,SENS_ON); - RTC.ON(); + // update RTC attributes + if (RTC.isON == 0) + { + RTC.ON(); + } RTC.getTime(); if( !set3V3 ) @@ -2688,27 +2692,176 @@ void WaspSD::setFileDate() } - +/* + * showFile() - + * + * Print out the contents of the whole input file + */ void WaspSD::showFile(char* filepath) { int32_t size = SD.getFileSize(filepath); + int32_t block = 128; + int32_t nL = size / block; + int32_t nR = size % block; + int32_t index = 0; // show file + USB.println(F("\n-------------------")); + USB.secureBegin(); + + for(int32_t i=0 ; i Enter numeric option:")); + USB.flush(); + + // wait for incoming data from keyboard + while (!USB.available() && (millis()-previous < timeout)); + + // parse incoming bytes + if (USB.available() > 0) + { + previous = millis(); + + // get option number + option = USB.read(); + USB.println(option); + USB.flush(); + + switch (option) + { + case '1': + SD.ls(LS_DATE | LS_SIZE | LS_R); + previous = millis(); + break; + + case '2': + // init vars + i = 0; + previous = millis(); + memset(filename, 0x00, sizeof(filename)); + USB.print(F("==> Enter name of file to read:")); + + // wait for incoming data from keyboard + while (!USB.available() && (millis()-previous < timeout)); + while (USB.available() > 0) + { + filename[i] = USB.read(); + i++; + if (i >= sizeof(filename)) + { + break; + } + } + USB.println(filename); + SD.showFile(filename); + previous = millis(); + break; + + case '3': + // init vars + i = 0; + previous = millis(); + memset(filename, 0x00, sizeof(filename)); + USB.print(F("==> Enter name of directory to change to:")); + + // wait for incoming data from keyboard + while (!USB.available() && (millis()-previous < timeout)); + while (USB.available() > 0) + { + filename[i] = USB.read(); + i++; + if (i >= sizeof(filename)) + { + break; + } + } + USB.println(filename); + SD.cd(filename); + previous = millis(); + break; + + case '4': + SD.goRoot(); + previous = millis(); + break; + + case '9': + SD.format(); + previous = millis(); + break; + default: + break; + + } + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + + } while (millis()-previous < timeout); + + USB.println(); + } + // Preinstantiate Objects ////////////////////////////////////////////////////// WaspSD SD = WaspSD(); diff --git a/waspmote-api/WaspSD.h b/waspmote-api/WaspSD.h index fa670ff..16c848b 100755 --- a/waspmote-api/WaspSD.h +++ b/waspmote-api/WaspSD.h @@ -1,7 +1,7 @@ /*! \file WaspSD.h \brief Library for managing the SD Card - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.4 + Version: 3.0 Design: David Gascón Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona */ @@ -674,6 +674,8 @@ class WaspSD \return void */ void showFile(char* filepath); + + void menu(uint32_t timeout); }; diff --git a/waspmote-api/WaspSPI.cpp b/waspmote-api/WaspSPI.cpp index 37aaedb..32ba4df 100755 --- a/waspmote-api/WaspSPI.cpp +++ b/waspmote-api/WaspSPI.cpp @@ -15,9 +15,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.4 - * Design: David Gascón - * Implementation: Alberto Bielsa, David Cuartielles + * Version: 3.1 + * Design: David Gascon + * Implementation: Alberto Bielsa, David Cuartielles, Yuri Carmona */ @@ -33,25 +33,25 @@ ******************************************************************************/ void WaspSPI::begin() { - // Set direction register for SCK and MOSI pin. - // MISO pin automatically overrides to INPUT. - // When the SS pin is set as OUTPUT, it can be used as - // a general purpose output port (it doesn't influence - // SPI operations). - - pinMode(SD_SCK, OUTPUT); - pinMode(SD_MOSI, OUTPUT); - pinMode(SD_SS, OUTPUT); - - digitalWrite(SD_SCK, LOW); - digitalWrite(SD_MOSI, LOW); - digitalWrite(SD_SS, HIGH); - - // Warning: if the SS pin ever becomes a LOW INPUT then SPI - // automatically switches to Slave, so the data direction of - // the SS pin MUST be kept as OUTPUT. - SPCR |= _BV(MSTR); - SPCR |= _BV(SPE); + // Set direction register for SCK and MOSI pin. + // MISO pin automatically overrides to INPUT. + // When the SS pin is set as OUTPUT, it can be used as + // a general purpose output port (it doesn't influence + // SPI operations). + + pinMode(SD_SCK, OUTPUT); + pinMode(SD_MOSI, OUTPUT); + pinMode(SD_SS, OUTPUT); + + digitalWrite(SD_SCK, LOW); + digitalWrite(SD_MOSI, LOW); + digitalWrite(SD_SS, HIGH); + + // Warning: if the SS pin ever becomes a LOW INPUT then SPI + // automatically switches to Slave, so the data direction of + // the SS pin MUST be kept as OUTPUT. + SPCR |= _BV(MSTR); + SPCR |= _BV(SPE); } @@ -65,12 +65,11 @@ void WaspSPI::close() // Close SPI COM only when all modules are off // if one of them is still on, then do not proceed with // the closing process - if( (SPI.isSD == false) - && (SPI.isSX == false) + if ((SPI.isSD == false) + && (SPI.isSocket0 == false) && (SPI.isDustSensor == false) && (SPI.isSmartWater == false) - && (SPI.isSmartWaterIons == false) - && (SPI.isRS485 == false) ) + && (SPI.isSmartWaterIons == false)) { // define SPI pins as INPUTs (high impedance) pinMode(SD_SCK, INPUT); @@ -102,12 +101,14 @@ void WaspSPI::end() ******************************************************************************/ void WaspSPI::setBitOrder(uint8_t bitOrder) { - if(bitOrder == LSBFIRST) - { - SPCR |= _BV(DORD); - } else { - SPCR &= ~(_BV(DORD)); - } + if (bitOrder == LSBFIRST) + { + SPCR |= _BV(DORD); + } + else + { + SPCR &= ~(_BV(DORD)); + } } @@ -117,7 +118,7 @@ void WaspSPI::setBitOrder(uint8_t bitOrder) ******************************************************************************/ void WaspSPI::setDataMode(uint8_t mode) { - SPCR = (SPCR & ~SPI_MODE_MASK) | mode; + SPCR = (SPCR & ~SPI_MODE_MASK) | mode; } @@ -127,8 +128,9 @@ void WaspSPI::setDataMode(uint8_t mode) ******************************************************************************/ void WaspSPI::setClockDivider(uint8_t rate) { - SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); - SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | (rate & SPI_2XCLOCK_MASK); + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); + //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | (rate & SPI_2XCLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); } @@ -145,13 +147,13 @@ uint8_t WaspSPI::receive() while (!(SPSR & (1 << SPIF))); // perform secure SPI power management - SPI.secureEnd(); - + SPI.secureEnd(); return SPDR; } + /******************************************************************************* * receive * @@ -212,15 +214,14 @@ byte WaspSPI::transfer(uint8_t _data) ******************************************************************************/ void WaspSPI::transfer(const uint8_t* buf , size_t n) { - for (size_t i = 0; i < n; i++) { - transfer(buf[i]); - } + for (size_t i = 0; i < n; i++) + { + transfer(buf[i]); + } } - - /******************************************************************************* * setSPISlave() - It selects the slave on SPI bus to use * @@ -229,40 +230,37 @@ void WaspSPI::transfer(const uint8_t* buf , size_t n) ******************************************************************************/ void WaspSPI::setSPISlave(uint8_t SELECTION) { + // disable SD pinMode(SD_SS,OUTPUT); - pinMode(SOCKET0_SS,OUTPUT); - digitalWrite(SD_SS,HIGH); + + // disable SOCKET0 + pinMode(SOCKET0_SS,OUTPUT); digitalWrite(SOCKET0_SS,HIGH); - if( WaspRegister & REG_DUST_GASES_PRO ) + // disable Gases Pro + if (WaspRegisterSensor & REG_DUST_GASES_PRO) { pinMode(DUST_SENSOR_CS,OUTPUT); digitalWrite(DUST_SENSOR_CS,HIGH); } - if( WaspRegister & REG_WATER ) + // disable Smart Water ADC + if (WaspRegisterSensor & REG_WATER) { - // Chip Select of the Smart Water ADC pinMode(DIGITAL4,OUTPUT); digitalWrite(DIGITAL4,HIGH); } - if( WaspRegister & REG_WATER_IONS ) + // disable Smart Ions + if (WaspRegisterSensor & REG_WATER_IONS) { - // Chip Select of the Smart Water Ions ADC pinMode(DIGITAL1,OUTPUT); digitalWrite(DIGITAL1,HIGH); } + - if( WaspRegister & REG_RS485 ) - { - // Chip Select of the RS-485 Board - pinMode(SOCKET0_SS,OUTPUT); - digitalWrite(SOCKET0_SS,HIGH); - } - - switch(SELECTION) + switch (SELECTION) { case SD_SELECT: digitalWrite(SD_SS,LOW); break; @@ -271,41 +269,24 @@ void WaspSPI::setSPISlave(uint8_t SELECTION) case SOCKET1_SELECT: Utils.setMuxSocket1(); digitalWrite(MUX_TX,LOW); break; - case DUST_SENSOR_SELECT: if( WaspRegister & REG_DUST_GASES_PRO ) + case DUST_SENSOR_SELECT: if (WaspRegisterSensor & REG_DUST_GASES_PRO) { digitalWrite(DUST_SENSOR_CS,LOW); } break; - case SMART_WATER_SELECT: if( WaspRegister & REG_WATER ) + case SMART_WATER_SELECT: if (WaspRegisterSensor & REG_WATER) { digitalWrite(DIGITAL4,LOW); } break; - case SMART_IONS_SELECT: if( WaspRegister & REG_WATER_IONS ) + case SMART_IONS_SELECT: if (WaspRegisterSensor & REG_WATER_IONS) { digitalWrite(DIGITAL1,LOW); } break; - case ALL_DESELECTED: digitalWrite(SD_SS,HIGH); - digitalWrite(SOCKET0_SS,HIGH); - - if( WaspRegister & REG_DUST_GASES_PRO ) - { - digitalWrite(DUST_SENSOR_CS,HIGH); - } - - if( WaspRegister & REG_WATER ) - { - digitalWrite(DIGITAL4,HIGH); - } - - if( WaspRegister & REG_WATER_IONS ) - { - digitalWrite(DIGITAL1,HIGH); - } - + case ALL_DESELECTED: // Do nothing more break; default: break; } @@ -324,42 +305,36 @@ void WaspSPI::secureBegin() { // this codeblock belongs to the performance of the SD card // check if Dust sensor was not powered on before using the SD card - if( WaspRegister & REG_DUST_GASES_PRO ) + if (WaspRegisterSensor & REG_DUST_GASES_PRO) { - if( (WaspRegister & REG_3V3) && (SPI.isDustSensor == false) ) + if ((WaspRegister & REG_3V3) && (SPI.isDustSensor == false)) { digitalWrite(DUST_SENSOR_POWER,HIGH); } } - // this codeblock belongs to the performance of the SD card - // check if Semtech module was not powered on before using the SD card - if( WaspRegister & REG_SX ) + // this codeblock belongs to the performance of the SD card: + // -> check if Semtech module was not powered on before using the SD card + // -> check if RS485 module was not powered on before using the SD card + if ((WaspRegister & REG_SX) || (WaspRegister & REG_RS485)) { - if( SPI.isSX == false ) + if (SPI.isSocket0 == false) { - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); + PWR.powerSocket(SOCKET0,HIGH); + if (WaspRegister & REG_DUST_GASES_PRO) + { + delay(1); + } } } // SD card - if( SPI.isSD == false ) + if (SPI.isSD == false) { pinMode(MEM_PW,OUTPUT); digitalWrite(MEM_PW, HIGH); } - // check if Semtech module was not powered on before using the SD card - if( WaspRegister & REG_RS485 ) - { - if( SPI.isRS485 == false ) - { - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,HIGH); - } - } - } @@ -374,41 +349,32 @@ void WaspSPI::secureEnd() { // this codeblock belongs to the performance of the SD card // check if Dust sensor was not powered on before using the SD card - if( WaspRegister & REG_DUST_GASES_PRO ) + if (WaspRegister & REG_DUST_GASES_PRO) { - if( (WaspRegister & REG_3V3) && (SPI.isDustSensor == false) ) + if ((WaspRegister & REG_3V3) && (SPI.isDustSensor == false)) { digitalWrite(DUST_SENSOR_POWER,LOW); } } // this codeblock belongs to the performance of the SD card - // switch off the SX module if it was not powered on - if( WaspRegister & REG_SX ) + // -> switch off the SX module if it was not powered on + // -> switch off the RS485 module if it was not powered on + if ((WaspRegister & REG_SX) || (WaspRegister & REG_RS485)) { - if( SPI.isSX == false ) + if (SPI.isSocket0 == false) { - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,LOW); + PWR.powerSocket(SOCKET0, LOW); } } // SD card - if( SPI.isSD == false ) + if (SPI.isSD == false) { pinMode(MEM_PW,OUTPUT); digitalWrite(MEM_PW, LOW); } - if( WaspRegister & REG_RS485 ) - { - if( SPI.isRS485 == false ) - { - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,LOW); - } - } - } diff --git a/waspmote-api/WaspSPI.h b/waspmote-api/WaspSPI.h index 582b104..4ccbadc 100755 --- a/waspmote-api/WaspSPI.h +++ b/waspmote-api/WaspSPI.h @@ -1,7 +1,7 @@ -/*! \file WaspUtils.h - \brief Library containing useful general functions +/*! \file WaspSPI.h + \brief Library for managing the SPI bus - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,16 +17,15 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.4 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, David Cuartielles */ -/*! \def Wasputils_h - \brief The library flag - +/*! \def WaspSPI_h + \brief The library flag */ #ifndef WaspSPI_h #define WaspSPI_h @@ -146,11 +145,10 @@ class WaspSPI WaspSPI() { isSD = false; - isSX = false; + isSocket0 = false; isDustSensor = false; isSmartWater = false; isSmartWaterIons = false; - isRS485 = false; }; static byte transfer(uint8_t _data); @@ -185,10 +183,10 @@ class WaspSPI void secureBegin(); void secureEnd(); - //! Variable : indicates when Semtech module is being powered on + //! Variable : indicates when SOCKET0 module is being powered on /*! true: ON; false: OFF */ - boolean isSX; + boolean isSocket0; //! Variable : indicates when SD module is being powered on /*! true: ON; false: OFF @@ -209,11 +207,6 @@ class WaspSPI /*! true: ON; false: OFF */ boolean isSmartWaterIons; - - //! Variable : indicates when RS-485 board is being powered on - /*! true: ON; false: OFF - */ - boolean isRS485; }; diff --git a/waspmote-api/WaspUART.cpp b/waspmote-api/WaspUART.cpp index 95be179..70c69f8 100755 --- a/waspmote-api/WaspUART.cpp +++ b/waspmote-api/WaspUART.cpp @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.1 + * Version: 3.0 * Design: David Gascón * Implementation: Yuri Carmona */ @@ -28,6 +28,17 @@ #include "WaspUART.h" +void WaspUART::setUART(uint8_t uart) +{ + _uart = uart; +} + +void WaspUART::setBaudrate(uint32_t baudrate) +{ + _baudrate = baudrate; +} + + /* * * name: beginUART @@ -43,6 +54,8 @@ void WaspUART::beginUART() // update Waspmote Register if(_uart==SOCKET0) WaspRegister |= REG_SOCKET0; if(_uart==SOCKET1) WaspRegister |= REG_SOCKET1; + + secureBegin(); } @@ -207,19 +220,21 @@ uint8_t WaspUART::sendCommand( char* command, { // index counter uint16_t i = 0; - - #if UART_DEBUG > 0 - USB.print(F("[debug] cmd:")); USB.println(command); + + secureBegin(); + + #if DEBUG_UART > 0 + PRINT_UART(F("cmd:")); USB.println(command); #endif - #if UART_DEBUG > 1 - USB.print(F("[debug] ans1:")); USB.println(ans1); - if(ans2!=NULL) { USB.print(F("[debug] ans2:")); USB.println(ans2);} - if(ans3!=NULL) { USB.print(F("[debug] ans3:")); USB.println(ans3);} - if(ans4!=NULL) { USB.print(F("[debug] ans4:")); USB.println(ans4);} + #if DEBUG_UART > 1 + PRINT_UART(F("ans1:")); USB.println(ans1); + if(ans2!=NULL) { PRINT_UART(F("ans2:")); USB.println(ans2);} + if(ans3!=NULL) { PRINT_UART(F("ans3:")); USB.println(ans3);} + if(ans4!=NULL) { PRINT_UART(F("ans4:")); USB.println(ans4);} #endif // clear uart buffer before sending command - if( _flush_mode == true ) + if (_flush_mode == true) { serialFlush(_uart); } @@ -238,34 +253,34 @@ uint8_t WaspUART::sendCommand( char* command, unsigned long previous = millis(); // check available data for 'timeout' milliseconds - while( (millis() - previous) < timeout ) + while ((millis() - previous) < timeout) { - if( serialAvailable(_uart) ) + if (serialAvailable(_uart)) { - if ( i < (sizeof(_buffer)-1) ) + if (i < (sizeof(_buffer)-1)) { - _buffer[i++] = serialRead(_uart); - _length++; + _buffer[i++] = serialRead(_uart); + _length++; } } // Check 'ans1' - if( find( _buffer, _length, ans1 ) == true ) + if (find( _buffer, _length, ans1 ) == true) { - #if UART_DEBUG > 0 - USB.print(F("[debug] ans:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans1 ); #endif return 1; } // Check 'ans2' - if( ans2 != NULL ) + if (ans2 != NULL) { if( find( _buffer, _length, ans2 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] ans:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans2 ); #endif return 2; @@ -273,12 +288,12 @@ uint8_t WaspUART::sendCommand( char* command, } // Check 'ans3' - if( ans3 != NULL ) + if (ans3 != NULL) { if( find( _buffer, _length, ans3 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] ans:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans3 ); #endif return 3; @@ -286,12 +301,12 @@ uint8_t WaspUART::sendCommand( char* command, } // Check 'ans4' - if( ans4 != NULL ) + if (ans4 != NULL) { if( find( _buffer, _length, ans4 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] ans:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans4 ); #endif return 4; @@ -303,11 +318,11 @@ uint8_t WaspUART::sendCommand( char* command, } // timeout - #if UART_DEBUG > 0 - USB.println(F("[debug] no answer")); + #if DEBUG_UART > 0 + PRINT_UART(F("no answer\n")); #endif - #if UART_DEBUG > 1 - USB.print(F("[debug] _buffer:")); + #if DEBUG_UART > 1 + PRINT_UART(F("_buffer:")); USB.println( _buffer, _length); #endif return 0; @@ -361,19 +376,21 @@ bool WaspUART::find( uint8_t* buffer, uint16_t length, char* pattern) */ void WaspUART::sendCommand( uint8_t* command, uint16_t length ) { + secureBegin(); + // clear uart buffer before sending command - if( _flush_mode == true ) + if (_flush_mode == true) { serialFlush(_uart); } /// print command - for (int i = 0; i < length; i++) + for (uint16_t i = 0; i < length; i++) { printByte( command[i], _uart ); } - delay( _def_delay ); + delay( _def_delay ); } @@ -469,12 +486,14 @@ uint8_t WaspUART::waitFor( char* ans1, // index counter uint16_t i = 0; + secureBegin(); + // clear _buffer memset( _buffer, 0x00, sizeof(_buffer) ); _length = 0; // get actual instant - unsigned long previous = millis(); + uint32_t previous = millis(); // check available data for 'timeout' milliseconds while( (millis() - previous) < timeout ) @@ -491,10 +510,10 @@ uint8_t WaspUART::waitFor( char* ans1, // Check 'ans1' if( find( _buffer, _length, ans1 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] found:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans1 ); - #endif + #endif return 1; } @@ -503,10 +522,10 @@ uint8_t WaspUART::waitFor( char* ans1, { if( find( _buffer, _length, ans2 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] found:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans2 ); - #endif + #endif return 2; } } @@ -516,8 +535,8 @@ uint8_t WaspUART::waitFor( char* ans1, { if( find( _buffer, _length, ans3 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] found:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans3 ); #endif return 3; @@ -529,10 +548,10 @@ uint8_t WaspUART::waitFor( char* ans1, { if( find( _buffer, _length, ans4 ) == true ) { - #if UART_DEBUG > 0 - USB.print(F("[debug] found:")); + #if DEBUG_UART > 0 + PRINT_UART(F("found:")); USB.println( ans4 ); - #endif + #endif return 4; } } @@ -579,6 +598,8 @@ uint16_t WaspUART::readBuffer(uint16_t requestBytes, bool clearBuffer) uint16_t i = 0; uint16_t nBytes = 0; + secureBegin(); + if( clearBuffer == true ) { // clear _buffer @@ -586,15 +607,12 @@ uint16_t WaspUART::readBuffer(uint16_t requestBytes, bool clearBuffer) _length = 0; } - // get actual instant - unsigned long previous = millis(); - - // check available data for 'timeout' milliseconds - while( serialAvailable(_uart) ) + // read available data + while (serialAvailable(_uart)) { - if ( (i < (sizeof(_buffer)-1)) && (requestBytes>0) ) + if ((i < (sizeof(_buffer)-1)) && (requestBytes>0)) { - _buffer[i++] = serialRead(_uart); + _buffer[i++] = serialRead(_uart); _length++; nBytes++; requestBytes--; @@ -604,7 +622,7 @@ uint16_t WaspUART::readBuffer(uint16_t requestBytes, bool clearBuffer) { break; } - } + } return nBytes; } @@ -676,7 +694,7 @@ uint8_t WaspUART::parseString(char* str, uint16_t size, char* delimiters) if (pch != NULL) { memset(str,0x00, size); - strncpy(str, pch, size); + strncpy(str, pch, size-1); return 0; } else @@ -686,6 +704,52 @@ uint8_t WaspUART::parseString(char* str, uint16_t size, char* delimiters) } +/*! + * @brief It parses the contents in '_buffer' escaping the delimiters indicated + * as inputs in delimiters. + * For instance _buffer stores: "\r\n" + * Then you can call: parseString(data, sizeof(data),"\r\n") + * + * @param char* str: pointer to the buffer where parsed data is stored + * @param uint16_t size: size of input 'str' buffer + * @param char* delimiters: string containing the delimiter characters + * @param uint8_t n: number of element to search for in the string of elements + * + * @return + * @arg '0' if ok + * @arg '1' if error + */ +uint8_t WaspUART::parseString(char* str, uint16_t size, char* delimiters, uint8_t n) +{ + // define the pointer to seek for token + char* pch; + + pch = strtok( (char*)_buffer, delimiters); + + for (int i = 0; i < n; i++) + { + + if (pch == NULL) + { + return 1; + } + + // check element + if (i+1 == n) + { + memset(str,0x00, size); + strncpy(str, pch, size-1); + return 0; + } + + // iterate to next element + pch = strtok(NULL, delimiters); + } + + return 1; +} + + /*! * @brief It parses the contents in '_buffer' escaping the delimiters indicated @@ -721,6 +785,89 @@ uint8_t WaspUART::parseFloat(float* value, char* delimiters) + +/*! + * @brief It parses the contents in '_buffer' escaping the delimiters indicated + * as inputs in delimiters. + * For instance _buffer stores: "\r\n" + * Then you can call: parseUint8(&variable, "\r\n") + * + * @param uint8_t* value: pointer to the variable where parsed data is stored + * @param char* delimiters: string containing the delimiter characters + * + * @return + * @arg '0' if ok + * @arg '1' if error + */ +uint8_t WaspUART::parseUint8(uint8_t* value, char* delimiters) +{ + // define the pointer to seek for token + char* pch; + uint32_t aux; + + pch = strtok( (char*)_buffer, delimiters); + + if (pch != NULL) + { + aux = strtoul( pch, NULL, 10); + *value = (uint8_t)aux; + return 0; + } + else + { + return 1; + } +} + + + +/*! + * @brief It parses the contents in '_buffer' escaping the delimiters indicated + * as inputs in delimiters. + * For instance _buffer stores: "\r\n" + * Then you can call: parseUint8(&variable, "\r\n") + * + * @param uint8_t* value: pointer to the variable where parsed data is stored + * @param char* delimiters: string containing the delimiter characters + * @param uint8_t n: number of element to search for in the string of elements + * + * @return + * @arg '0' if ok + * @arg '1' if error + */ +uint8_t WaspUART::parseUint8(uint8_t* value, char* delimiters, uint8_t n) +{ + // define the pointer to seek for token + char* pch; + uint32_t aux; + + pch = strtok( (char*)_buffer, delimiters); + + for (int i = 0; i < n; i++) + { + if (pch == NULL) + { + return 1; + } + + // check element + if (i+1 == n) + { + aux = strtoul( pch, NULL, 10); + *value = (uint8_t)aux; + return 0; + } + + // iterate to next element + pch = strtok(NULL, delimiters); + } + + return 1; +} + + + + /*! * @brief It parses the contents in '_buffer' escaping the delimiters indicated * as inputs in delimiters. @@ -753,6 +900,81 @@ uint8_t WaspUART::parseUint32(uint32_t* value, char* delimiters) } +/*! + * @brief It parses the contents in '_buffer' escaping the delimiters indicated + * as inputs in delimiters. + * For instance _buffer stores: "\r\n" + * Then you can call: parseInt32(&variable, "\r\n") + * + * @param int32_t* value: pointer to the variable where parsed data is stored + * @param char* delimiters: string containing the delimiter characters + * + * @return + * @arg '0' if ok + * @arg '1' if error + */ +uint8_t WaspUART::parseInt32(int32_t* value, char* delimiters) +{ + // define the pointer to seek for token + char* pch; + + pch = strtok( (char*)_buffer, delimiters); + + if (pch != NULL) + { + *value = strtol( pch, NULL, 10); + return 0; + } + else + { + return 1; + } +} + +/*! + * @brief It parses the contents in '_buffer' escaping the delimiters indicated + * as inputs in delimiters. + * For instance _buffer stores: "\r\n" + * Then you can call: parseInt32(&variable, "\r\n") + * + * @param int32_t* value: pointer to the variable where parsed data is stored + * @param char* delimiters: string containing the delimiter characters + * + * @return + * @arg '0' if ok + * @arg '1' if error + */ +uint8_t WaspUART::parseInt32(int32_t* value, char* delimiters, uint8_t n) +{ + // define the pointer to seek for token + char* pch; + uint32_t aux; + + pch = strtok( (char*)_buffer, delimiters); + + for (int i = 0; i < n; i++) + { + if (pch == NULL) + { + return 1; + } + + // check element + if (i+1 == n) + { + aux = strtol( pch, NULL, 10); + *value = (int32_t)aux; + return 0; + } + + // iterate to next element + pch = strtok(NULL, delimiters); + } + + return 1; +} + + /*! * @brief It parses the contents in '_buffer' escaping the delimiters indicated @@ -785,6 +1007,34 @@ uint8_t WaspUART::parseInt(int* value, char* delimiters) } } +/*! + * + */ +void WaspUART::secureBegin() +{ + /* + if (_uart == SOCKET1) + { + // set ss pin in socket0 to low + pinMode(SOCKET0_SS,OUTPUT); + digitalWrite(SOCKET0_SS,HIGH); + + if (WaspRegister & REG_XBEE_SOCKET0) + { + // switch module ON + PWR.powerSocket(SOCKET0, HIGH); + + // set ss pin in socket0 to low + //pinMode(XBEE_MON,OUTPUT); + //digitalWrite(XBEE_MON,LOW); + } + } + */ + +} + + + diff --git a/waspmote-api/WaspUART.h b/waspmote-api/WaspUART.h index 4593dce..16ccb47 100755 --- a/waspmote-api/WaspUART.h +++ b/waspmote-api/WaspUART.h @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Yuri Carmona @@ -27,18 +27,21 @@ #ifndef WaspUART_h #define WaspUART_h -/****************************************************************************** - * Includes - ******************************************************************************/ - - /****************************************************************************** * Definitions & Declarations ******************************************************************************/ -#define UART_DEBUG 0 +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled for error output messages + * 2: debug mode enabled for both error and ok messages + * \Remarks do not enable mode 2 unless SOCKET1 is used + */ +#define DEBUG_UART 0 +// define print MACRO +#define PRINT_UART(str) USB.print(F("[UART] ")); USB.print(str); /*! \def UART0 \brief UART0 of the MCU @@ -234,26 +237,38 @@ class WaspUART //! It waits depending on the baudrate used void latencyDelay(); + + void setUART(uint8_t uart); + void setBaudrate(uint32_t baudrate); protected: //! It parses the contents of _buffer and copies the string to the pointer uint8_t parseString(char* str, uint16_t size, char* delimiters); + uint8_t parseString(char* str, uint16_t size, char* delimiters, uint8_t n); //! It parses the contents of _buffer and converts it to a float type uint8_t parseFloat(float* value, char* delimiters); + //! It parses the contents of _buffer and converts it to a uint8_t type + uint8_t parseUint8(uint8_t* value, char* delimiters); + uint8_t parseUint8(uint8_t* value, char* delimiters, uint8_t n); + //! It parses the contents of _buffer and converts it to a uint32_t type - uint8_t parseUint32(uint32_t* value, char* delimiters); + uint8_t parseUint32(uint32_t* value, char* delimiters); + + //! It parses the contents of _buffer and converts it to a int32_t type + uint8_t parseInt32(int32_t* value, char* delimiters); + uint8_t parseInt32(int32_t* value, char* delimiters, uint8_t n); //! It parses the contents of _buffer and converts it to a int type - uint8_t parseInt(int* value, char* delimiters); - - //! It parses the contents of _buffer and converts it to a uint16_t type - uint8_t parseUint8(uint8_t* value, char* delimiters); + uint8_t parseInt(int* value, char* delimiters); //! It parses the contents of _buffer and converts it to a uint16_t type uint8_t parseHex(uint8_t* value, char* delimiters); + + void secureBegin(); + }; diff --git a/waspmote-api/WaspUSB.cpp b/waspmote-api/WaspUSB.cpp index 19b083e..0631c94 100755 --- a/waspmote-api/WaspUSB.cpp +++ b/waspmote-api/WaspUSB.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.3 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascon * Implementation: David Cuartielles, Alberto Bielsa, Marcos Yarza */ @@ -50,13 +50,8 @@ void WaspUSB::ON() // open UART0 beginSerial(USB_RATE, _uart); - // switch multiplexer on - pinMode(MUX_PW,OUTPUT); - digitalWrite(MUX_PW,HIGH); - // configure multiplexer to USB port. XBee disabled - pinMode(MUX_USB_XBEE,OUTPUT); - digitalWrite(MUX_USB_XBEE,LOW); + Utils.setMuxUSB(); // unset XBee interruption line pinMode(XBEE_MON,OUTPUT); @@ -70,12 +65,22 @@ void WaspUSB::ON() */ void WaspUSB::OFF() { - // First: close UART - closeSerial(_uart); - - // Second: configure multiplexer to XBEE port - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,HIGH); + if (!(WaspRegister & REG_SOCKET0)) + { + // close UART + closeSerial(_uart); + + // switch off mux on uart0 + if (_boot_version >= 'G') + { + Utils.muxOFF0(); + } + } + else + { + // configure mux to Socket0 + Utils.setMuxSocket0(); + } // unset XBee interruption line pinMode(XBEE_MON,OUTPUT); @@ -91,8 +96,7 @@ uint8_t WaspUSB::available() beginSerial(USB_RATE, _uart); // configure multiplexor to USB port - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,LOW); + Utils.setMuxUSB(); return serialAvailable( _uart); } @@ -607,10 +611,9 @@ void WaspUSB::printHexln(uint8_t* pointer, uint16_t length) void WaspUSB::secureBegin() { // store previous baudrate - _reg_ubrr0h = UBRR0H; - _reg_ubrr0l = UBRR0L; - _reg_ucsr0c = UCSR0C; - _reg_ucsr1c = UCSR1C; + _reg_ubrr0h = UBRR0H; // USART0 Baud Rate Register High Byte + _reg_ubrr0l = UBRR0L; // USART0 Baud Rate Register Low Byte + _reg_ucsr0c = UCSR0C; // USART0 Control and Status Register n C // No parity bit cbi(UCSR0C, UPM01); @@ -623,8 +626,7 @@ void WaspUSB::secureBegin() beginSerial(USB_RATE, _uart); // switch on mux - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,LOW); + Utils.setMuxUSB(); } @@ -641,18 +643,21 @@ void WaspUSB::secureEnd() if (WaspRegister & REG_SOCKET0) { delay(3); - digitalWrite(MUX_USB_XBEE,HIGH); + Utils.setMuxSocket0(); } else { delay(3); + if (_boot_version >= 'G') + { + Utils.muxOFF0(); + } } // load previous stored registers UBRR0H = _reg_ubrr0h; UBRR0L = _reg_ubrr0l; UCSR0C = _reg_ucsr0c; - UCSR1C = _reg_ucsr1c; } diff --git a/waspmote-api/WaspUSB.h b/waspmote-api/WaspUSB.h index aa7dc67..89df37c 100755 --- a/waspmote-api/WaspUSB.h +++ b/waspmote-api/WaspUSB.h @@ -1,6 +1,6 @@ /*! \file WaspUSB.h \brief Library for managing the USB interface - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.3 + Version: 3.0 Design: David Gascón Implementation: David Cuartielles, Alberto Bielsa, Yuri Carmona @@ -105,7 +105,6 @@ class WaspUSB uint8_t _reg_ubrr0h; uint8_t _reg_ubrr0l; uint8_t _reg_ucsr0c; - uint8_t _reg_ucsr1c; public: diff --git a/waspmote-api/WaspUtils.cpp b/waspmote-api/WaspUtils.cpp index 1b7ae87..7434086 100755 --- a/waspmote-api/WaspUtils.cpp +++ b/waspmote-api/WaspUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.8 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascon * Implementation: Alberto Bielsa, David Cuartielles, Yuri Carmona */ @@ -194,19 +194,19 @@ long WaspUtils::map(long x, long in_min, long in_max, long out_min, long out_max * It sets MUX to the desired combination. * * -------------- - * MUX_LOW = 0 & MUX_HIGH = 1 ---> GPS MODULE - * MUX_LOW = 1 & MUX_HIGH = 1 ---> GPRS MODULE - * MUX_LOW = 1 & MUX_HIGH = 0 ---> AUX1 MODULE - * MUX_LOW = 0 & MUX_HIGH = 0 ---> AUX2 MODULE + * MUX1_0 = 0 & MUX1_1 = 1 ---> GPS MODULE + * MUX1_0 = 1 & MUX1_1 = 1 ---> GPRS MODULE + * MUX1_0 = 1 & MUX1_1 = 0 ---> AUX1 MODULE + * MUX1_0 = 0 & MUX1_1 = 0 ---> AUX2 MODULE */ void WaspUtils::setMux(uint8_t MUX_LOW, uint8_t MUX_HIGH) { - pinMode(MUX_PW, OUTPUT); - pinMode(MUX_0, OUTPUT); - pinMode(MUX_1, OUTPUT); - digitalWrite(MUX_PW, HIGH); - digitalWrite(MUX_0, MUX_LOW); - digitalWrite(MUX_1, MUX_HIGH); + pinMode(MUX1_PW, OUTPUT); + pinMode(MUX1_0, OUTPUT); + pinMode(MUX1_1, OUTPUT); + digitalWrite(MUX1_PW, HIGH); + digitalWrite(MUX1_0, MUX_LOW); + digitalWrite(MUX1_1, MUX_HIGH); } @@ -215,19 +215,19 @@ void WaspUtils::setMux(uint8_t MUX_LOW, uint8_t MUX_HIGH) * It sets multiplexer on UART_1 to the desired combination (0,1) to enable GPS module * * -------------- - * MUX_LOW = 0 & MUX_HIGH = 1 ---> GPS MODULE - * MUX_LOW = 1 & MUX_HIGH = 1 ---> SOCKET1 - * MUX_LOW = 1 & MUX_HIGH = 0 ---> AUX1 MODULE - * MUX_LOW = 0 & MUX_HIGH = 0 ---> AUX2 MODULE + * MUX1_0 = 0 & MUX1_1 = 1 ---> GPS MODULE + * MUX1_0 = 1 & MUX1_1 = 1 ---> GPRS MODULE + * MUX1_0 = 1 & MUX1_1 = 0 ---> AUX1 MODULE + * MUX1_0 = 0 & MUX1_1 = 0 ---> AUX2 MODULE */ void WaspUtils::setMuxGPS() { - pinMode(MUX_PW, OUTPUT); - pinMode(MUX_0, OUTPUT); - pinMode(MUX_1, OUTPUT); - digitalWrite(MUX_PW, HIGH); - digitalWrite(MUX_0, LOW); - digitalWrite(MUX_1, HIGH); + pinMode(MUX1_PW, OUTPUT); + pinMode(MUX1_0, OUTPUT); + pinMode(MUX1_1, OUTPUT); + digitalWrite(MUX1_PW, HIGH); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, HIGH); } @@ -236,19 +236,38 @@ void WaspUtils::setMuxGPS() * It sets multiplexer on UART_1 to the desired combination (1,1) to enable SOCKET1 * * -------------- - * MUX_LOW = 0 & MUX_HIGH = 1 ---> GPS MODULE - * MUX_LOW = 1 & MUX_HIGH = 1 ---> SOCKET1 - * MUX_LOW = 1 & MUX_HIGH = 0 ---> AUX1 MODULE - * MUX_LOW = 0 & MUX_HIGH = 0 ---> AUX2 MODULE + * MUX1_0 = 0 & MUX1_1 = 1 ---> GPS MODULE + * MUX1_0 = 1 & MUX1_1 = 1 ---> GPRS MODULE + * MUX1_0 = 1 & MUX1_1 = 0 ---> AUX1 MODULE + * MUX1_0 = 0 & MUX1_1 = 0 ---> AUX2 MODULE */ void WaspUtils::setMuxSocket1() { - pinMode(MUX_PW, OUTPUT); - pinMode(MUX_0, OUTPUT); - pinMode(MUX_1, OUTPUT); - digitalWrite(MUX_PW, HIGH); - digitalWrite(MUX_0, HIGH); - digitalWrite(MUX_1, HIGH); + // check RTC int pin to disable line in order to communicate + if (digitalRead(RTC_INT_PIN_MON) == HIGH) + { + if (RTC.isON == 0) + { + RTC.ON(); + RTC.clearAlarmFlag(); + RTC.OFF(); + } + else + { + RTC.clearAlarmFlag(); + } + } + + // disable interruptions when using UART1 + detachInterrupt(RXD1_PIN); + detachInterrupt(TXD1_PIN); + + pinMode(MUX1_PW, OUTPUT); + pinMode(MUX1_0, OUTPUT); + pinMode(MUX1_1, OUTPUT); + digitalWrite(MUX1_PW, HIGH); + digitalWrite(MUX1_0, HIGH); + digitalWrite(MUX1_1, HIGH); } @@ -257,19 +276,19 @@ void WaspUtils::setMuxSocket1() * It sets multiplexer on UART_1 to the desired combination (1,1) to enable Aux1 module * * -------------- - * MUX_LOW = 0 & MUX_HIGH = 1 ---> GPS MODULE - * MUX_LOW = 1 & MUX_HIGH = 1 ---> SOCKET1 - * MUX_LOW = 1 & MUX_HIGH = 0 ---> AUX1 MODULE - * MUX_LOW = 0 & MUX_HIGH = 0 ---> AUX2 MODULE + * MUX1_0 = 0 & MUX1_1 = 1 ---> GPS MODULE + * MUX1_0 = 1 & MUX1_1 = 1 ---> GPRS MODULE + * MUX1_0 = 1 & MUX1_1 = 0 ---> AUX1 MODULE + * MUX1_0 = 0 & MUX1_1 = 0 ---> AUX2 MODULE */ void WaspUtils::setMuxAux1() { - pinMode(MUX_PW, OUTPUT); - pinMode(MUX_0, OUTPUT); - pinMode(MUX_1, OUTPUT); - digitalWrite(MUX_PW, HIGH); - digitalWrite(MUX_0, HIGH); - digitalWrite(MUX_1, LOW); + pinMode(MUX1_PW, OUTPUT); + pinMode(MUX1_0, OUTPUT); + pinMode(MUX1_1, OUTPUT); + digitalWrite(MUX1_PW, HIGH); + digitalWrite(MUX1_0, HIGH); + digitalWrite(MUX1_1, LOW); } @@ -278,19 +297,19 @@ void WaspUtils::setMuxAux1() * It sets multiplexer on UART_1 to the desired combination (1,1) to enable Aux2 module * * -------------- - * MUX_LOW = 0 & MUX_HIGH = 1 ---> GPS MODULE - * MUX_LOW = 1 & MUX_HIGH = 1 ---> SOCKET1 - * MUX_LOW = 1 & MUX_HIGH = 0 ---> AUX1 MODULE - * MUX_LOW = 0 & MUX_HIGH = 0 ---> AUX2 MODULE + * MUX1_0 = 0 & MUX1_1 = 1 ---> GPS MODULE + * MUX1_0 = 1 & MUX1_1 = 1 ---> GPRS MODULE + * MUX1_0 = 1 & MUX1_1 = 0 ---> AUX1 MODULE + * MUX1_0 = 0 & MUX1_1 = 0 ---> AUX2 MODULE */ void WaspUtils::setMuxAux2() { - pinMode(MUX_PW, OUTPUT); - pinMode(MUX_0, OUTPUT); - pinMode(MUX_1, OUTPUT); - digitalWrite(MUX_PW, HIGH); - digitalWrite(MUX_0, LOW); - digitalWrite(MUX_1, LOW); + pinMode(MUX1_PW, OUTPUT); + pinMode(MUX1_0, OUTPUT); + pinMode(MUX1_1, OUTPUT); + digitalWrite(MUX1_PW, HIGH); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, LOW); } @@ -299,34 +318,125 @@ void WaspUtils::setMuxAux2() */ void WaspUtils::setMuxUSB() { - pinMode(MUX_PW,OUTPUT); - pinMode(MUX_USB_XBEE,OUTPUT); - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,LOW); + if (_boot_version >= 'G') + { + pinMode(MUX0_PW,OUTPUT); + digitalWrite(MUX0_PW,HIGH); + + pinMode(MUX_USB_XBEE,OUTPUT); + digitalWrite(MUX_USB_XBEE,LOW); + } + else + { + pinMode(MUX_PW,OUTPUT); + digitalWrite(MUX_PW,HIGH); + + pinMode(MUX_USB_XBEE,OUTPUT); + digitalWrite(MUX_USB_XBEE,LOW); + } } -/* muxOFF() - switch off the multiplexer on UART_0 +/* muxOFF() - switch off the multiplexer on UART_0 and UART_1 * */ void WaspUtils::muxOFF() { - pinMode(MUX_PW,OUTPUT); - pinMode(MUX_USB_XBEE,OUTPUT); - digitalWrite(MUX_PW,LOW); - digitalWrite(MUX_USB_XBEE,LOW); - digitalWrite(MUX_0, LOW); - digitalWrite(MUX_1, LOW); + if (_boot_version >= 'G') + { + pinMode(MUX1_PW,OUTPUT); + pinMode(MUX0_PW,OUTPUT); + pinMode(MUX_USB_XBEE,OUTPUT); + pinMode(MUX1_0,OUTPUT); + pinMode(MUX1_1,OUTPUT); + digitalWrite(MUX1_PW,LOW); + digitalWrite(MUX0_PW,LOW); + digitalWrite(MUX_USB_XBEE,LOW); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, LOW); + } + else + { + pinMode(MUX_PW,OUTPUT); + pinMode(MUX_USB_XBEE,OUTPUT); + pinMode(MUX1_0,OUTPUT); + pinMode(MUX1_1,OUTPUT); + digitalWrite(MUX_PW,LOW); + digitalWrite(MUX_USB_XBEE,LOW); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, LOW); + } } + + +/* muxOFF1() - switch off the multiplexer on UART_1 + * +*/ +void WaspUtils::muxOFF1() +{ + if (_boot_version >= 'G') + { + pinMode(MUX1_PW,OUTPUT); + pinMode(MUX1_0,OUTPUT); + pinMode(MUX1_1,OUTPUT); + digitalWrite(MUX1_PW,LOW); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, LOW); + } + else + { + // previous generation -> switch mux to Aux2 + Utils.setMuxAux2(); + } +} + +/* muxOFF0() - switch off the multiplexer on UART_0 + * +*/ +void WaspUtils::muxOFF0() +{ + if (_boot_version >= 'G') + { + pinMode(MUX0_PW,OUTPUT); + pinMode(MUX_USB_XBEE,OUTPUT); + digitalWrite(MUX0_PW,LOW); + digitalWrite(MUX_USB_XBEE,LOW); + } + else + { + pinMode(MUX_PW,OUTPUT); + pinMode(MUX_USB_XBEE,OUTPUT); + pinMode(MUX1_0,OUTPUT); + pinMode(MUX1_1,OUTPUT); + digitalWrite(MUX_PW,LOW); + digitalWrite(MUX_USB_XBEE,LOW); + digitalWrite(MUX1_0, LOW); + digitalWrite(MUX1_1, LOW); + } +} + + /* setMuxSocket0() - set multiplexer on UART_0 to SOCKET0 * */ void WaspUtils::setMuxSocket0() { - pinMode(MUX_PW,OUTPUT); - pinMode(MUX_USB_XBEE,OUTPUT); - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,HIGH); + if (_boot_version >= 'G') + { + pinMode(MUX0_PW,OUTPUT); + digitalWrite(MUX0_PW,HIGH); + + pinMode(MUX_USB_XBEE,OUTPUT); + digitalWrite(MUX_USB_XBEE,HIGH); + } + else + { + pinMode(MUX_PW,OUTPUT); + digitalWrite(MUX_PW,HIGH); + + pinMode(MUX_USB_XBEE,OUTPUT); + digitalWrite(MUX_USB_XBEE,HIGH); + } } /* readEEPROM(address) - reads from the EEPROM specified address @@ -366,13 +476,13 @@ void WaspUtils::setID(char* moteID) // set zeros in EEPROM addresses for( int i=0 ; i<16 ; i++ ) { - eeprom_write_byte( (uint8_t*)(i+MOTEID_ADDR), 0x00); + eeprom_write_byte( (uint8_t*)(i+EEPROM_FRAME_MOTEID), 0x00); } // set the mote ID to EEPROM memory for( int i=0 ; i<16 ; i++ ) { - eeprom_write_byte( (uint8_t*)(i+MOTEID_ADDR), moteID[i] ); + eeprom_write_byte( (uint8_t*)(i+EEPROM_FRAME_MOTEID), moteID[i] ); // break if end of string if( moteID[i] == '\0') { @@ -394,20 +504,19 @@ void WaspUtils::setAuthKey(char* authkey) // set zeros in EEPROM addresses for(int i=0;i<8;i++) { - eeprom_write_byte((unsigned char *) i+AUTHKEY_ADDR, 0x00); + eeprom_write_byte((unsigned char *) i+EEPROM_OTA_AUTHKEY, 0x00); } // set the authentication key to EEPROM memory for(int i=0;i<8;i++) { - eeprom_write_byte((unsigned char *) i+AUTHKEY_ADDR, authkey[i]); + eeprom_write_byte((unsigned char *) i+EEPROM_OTA_AUTHKEY, authkey[i]); // break if end of string if( authkey[i] == '\0') { break; } } - } @@ -501,34 +610,72 @@ unsigned long WaspUtils::readSerialChip() } + + /* readSerialID() - reads the Waspmote unique serial identifier * * It reads the Waspmote unique serial identifier */ unsigned long WaspUtils::readSerialID() { + uint8_t error; unsigned long eeprom_id; - unsigned long id = readSerialChip(); - - if( id == 0 ) + unsigned long id; + + if (_boot_version >= 'G') { - // get eeprom serial id (latest Waspmote batches) - eeprom_id = Utils.getSerialEEPROM(); - - // check correct value of serial id - // -> 0x0A0A0A0A is a wrong value for default Waspmote EEPROM - // -> 0xFFFFFFFF is a wrong value - if( (eeprom_id != 0x0A0A0A0A) && (eeprom_id !=0xFFFFFFFF) ) - { - id = eeprom_id; + eeprom.ON(); + error = eeprom.readSerialNumber(); + if (error == 0) + { + _serial_id[0] = eeprom._response[0]; + _serial_id[1] = eeprom._response[1]; + _serial_id[2] = eeprom._response[2]; + _serial_id[3] = eeprom._response[3]; + _serial_id[4] = eeprom._response[4]; + _serial_id[5] = eeprom._response[5]; + _serial_id[6] = eeprom._response[6]; + _serial_id[7] = eeprom._response[7]; + return 0; } else { - id = 0; + memset( (uint8_t*)_serial_id, 0x00, sizeof(_serial_id)); + return 1; } } - - return id; + else + { + id = readSerialChip(); + if( id == 0 ) + { + // get eeprom serial id (latest Waspmote batches) + eeprom_id = Utils.getSerialEEPROM(); + + // check correct value of serial id + // -> 0x0A0A0A0A is a wrong value for default Waspmote EEPROM + // -> 0xFFFFFFFF is a wrong value + if( (eeprom_id != 0x0A0A0A0A) && (eeprom_id !=0xFFFFFFFF) ) + { + id = eeprom_id; + } + else + { + id = 0; + } + } + + _serial_id[0] = 0x00; + _serial_id[1] = 0x00; + _serial_id[2] = 0x00; + _serial_id[3] = 0x00; + _serial_id[4] = (id>>24) & 0xFF; + _serial_id[5] = (id>>16) & 0xFF; + _serial_id[6] = (id>>8) & 0xFF; + _serial_id[7] = (id>>0) & 0xFF; + + return id; + } } @@ -587,7 +734,7 @@ float WaspUtils::readTempDS1820(uint8_t pin, bool is3v3 ) byte data[12]; byte addr[8]; - + delay(25); if ( !OneWireTemp.search(addr)) { //no more sensors on chain, reset search @@ -597,7 +744,7 @@ float WaspUtils::readTempDS1820(uint8_t pin, bool is3v3 ) if ( WaspOneWire::crc8( addr, 7) != addr[7]) { - return -1000; + return -1000; } if ( addr[0] != 0x10 && addr[0] != 0x28) @@ -607,8 +754,8 @@ float WaspUtils::readTempDS1820(uint8_t pin, bool is3v3 ) OneWireTemp.reset(); OneWireTemp.select(addr); - OneWireTemp.write(0x44,0); // start conversion, with parasite power on at the end - delay(750); + OneWireTemp.write(0x44,1); // start conversion, with parasite power on at the end + delay(1000); OneWireTemp.reset(); OneWireTemp.select(addr); @@ -696,12 +843,14 @@ float WaspUtils::readTemperature() // Powering the sensor PWR.setSensorPower(SENS_3V3,SENS_ON); + delay(1000); // Reading the analog value sensor_value = analogRead(ANALOG6); delay(100); sensor_value = analogRead(ANALOG6); - + delay(100); + PWR.setSensorPower(SENS_3V3,SENS_OFF); // Calculating the volts @@ -733,7 +882,7 @@ uint8_t WaspUtils::readHumidity() sensor_value = analogRead(ANALOG7); delay(100); sensor_value = analogRead(ANALOG7); - + delay(100); PWR.setSensorPower(SENS_3V3,SENS_OFF); // Calculating the volts @@ -815,34 +964,42 @@ uint8_t WaspUtils::long2array(long num, char* numb) */ uint8_t WaspUtils::str2hex(char* str) { - int aux=0, aux2=0; - - - if( (*str>='0') && (*str<='9') ) - { - aux=*str++-'0'; - } - else if( (*str>='A') && (*str<='F') ) - { - aux=*str++-'A'+10; - } - if( (*str>='0') && (*str<='9') ) - { - aux2=*str-'0'; - } - else if( (*str>='A') && (*str<='F') ) - { - aux2=*str-'A'+10; - } - return aux*16+aux2; + int aux=0, aux2=0; + + if( (*str>='0') && (*str<='9') ) + { + aux=*str++-'0'; + } + else if( (*str>='A') && (*str<='F') ) + { + aux=*str++-'A'+10; + } + else if( (*str>='a') && (*str<='f') ) + { + aux=*str++-'a'+10; + } + if( (*str>='0') && (*str<='9') ) + { + aux2=*str-'0'; + } + else if( (*str>='A') && (*str<='F') ) + { + aux2=*str-'A'+10; + } + else if( (*str>='a') && (*str<='f') ) + { + aux2=*str-'a'+10; + } + return aux*16+aux2; } /* * Function: Converts a string to an array of bytes - * For example: If the input array -> 23576173706D6F74655F50726F23 - * The output string is str -> #Waspmote_Pro# + * For example: If the input string is defined as: + * char input[] = ""; + * The output string is array -> 23576173706D6F74655F50726F23 */ uint16_t WaspUtils::str2hex(char* str, uint8_t* array) { @@ -859,6 +1016,35 @@ uint16_t WaspUtils::str2hex(char* str, uint8_t* array) } + + + +/* + * Function: Converts a string to an array of bytes + */ +uint16_t WaspUtils::str2hex(char* str, uint8_t* array, uint16_t size) +{ + // get length in bytes (half of ASCII characters) + uint16_t length = strlen(str)/2; + + // Conversion from ASCII to HEX + for(uint16_t j=0; j= size) + { + length = j; + break; + } + + // store conversion in array + array[j] = Utils.str2hex(&str[j*2]); + } + + return length; +} + + /* * Function: Converts a string to an hex number * @@ -1055,36 +1241,45 @@ void WaspUtils::float2String (float fl, char str[], int N) * */ void WaspUtils::loadOTA(const char* filename, uint8_t version) -{ - - // save the name in EEPROM - for(int aux=0; aux<32; aux++) - { - if (aux < 7) - { - // filename - eeprom_write_byte((unsigned char *) (aux+2), uint8_t(filename[aux])); - } - else - { - // asterisks - eeprom_write_byte((unsigned char *) (aux+2), 0x2A); - } - } +{ + uint8_t program_version; + + // save the name in EEPROM + for (int aux=0; aux<32; aux++) + { + if (aux < 7) + { + // filename + eeprom_write_byte((uint8_t *) (aux+2), uint8_t(filename[aux])); + } + else + { + // asterisks + eeprom_write_byte((uint8_t *) (aux+2), 0x2A); + } + } - // set OTA flag in EEPROM to '1' - eeprom_write_byte((unsigned char *) 0x01, 0x01); + // set OTA flag in EEPROM to '1' + eeprom_write_byte((uint8_t *) EEPROM_OTA_FLAG, 0x01); - // sets the new program version into EEPROM - setProgramVersion( version); + // set OTA retries to 3 attempts + eeprom_write_byte((uint8_t *) EEPROM_OTA_RETRIES, 0x03); + + // sets the new program version into EEPROM + program_version = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION ); + eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP, program_version); + + // sets the new program version into EEPROM + setProgramVersion(version); - SD.ON(); - delay(100); - // reboot - PWR.reboot(); + SD.ON(); + delay(100); + + // reboot + PWR.reboot(); - // A little delay - delay(2000); + // A little delay + delay(2000); } /* @@ -1111,8 +1306,7 @@ void WaspUtils::readEEPROM() { USB.print(F("Address: ")); USB.print(address,DEC); - USB.print(F(" -- Value: ")); - USB.print("\t\t"); + USB.print(F(" -- Value: \t\t")); //PID aux = Utils.readEEPROM(address); @@ -1122,14 +1316,14 @@ void WaspUtils::readEEPROM() //CID aux = Utils.readEEPROM(address+32); - USB.print("\t\t"); + USB.print(F("\t\t")); USB.printHex(aux); USB.print(F(" ")); USB.print(char(aux)); //Last Stable ID aux = Utils.readEEPROM(address+64); - USB.print("\t\t"); + USB.print(F("\t\t")); USB.printHex(aux); USB.print(F(" ")); USB.println(char(aux)); @@ -1147,61 +1341,70 @@ void WaspUtils::readEEPROM() */ int8_t WaspUtils::checkNewProgram() { + uint8_t buffer_OTA[32]; + uint8_t current_ID[32]; + uint8_t program_version; + uint8_t program_version_backup; + bool reprogrammingOK = true; + + // copy current ID (CID) to Last Stable ID + for (int i = 0; i < 32; i++) + { + current_ID[i] = Utils.readEEPROM(i + 34); + eeprom_write_byte((uint8_t *)(i + 66), current_ID[i]); + } - uint8_t buffer_OTA[32]; - uint8_t current_ID[32]; - uint8_t program_version; - bool reprogrammingOK = true; - - // copy current ID (CID) to Last Stable ID - for(int i = 0; i < 32; i++) - { - current_ID[i] = Utils.readEEPROM(i + 34); - eeprom_write_byte((uint8_t *)(i + 66), current_ID[i]); - } - - // check OTA flag - if( WaspRegister & REG_OTA) - { - // Checking if programID and currentID are the same --> the program has been changed properly - for(int i = 0;i<32;i++) - { - // get PID - buffer_OTA[i] = eeprom_read_byte((uint8_t*)(i+2)); - } + // check OTA flag + if (WaspRegister & REG_OTA) + { + // Checking if programID and currentID are the same + // If so, the program has been changed properly + for (int i = 0; i < 32; i++) + { + // get PID + buffer_OTA[i] = eeprom_read_byte((uint8_t*)(i+2)); + } - for(int i = 0;i<32;i++) - { - // compare PID vs CID - if (buffer_OTA[i] != eeprom_read_byte( (uint8_t*)(i+34) ) ) - { - reprogrammingOK = false; - } - } + for (int i = 0; i < 32; i++) + { + // compare PID vs CID + if (buffer_OTA[i] != eeprom_read_byte((uint8_t*)(i+34))) + { + reprogrammingOK = false; + } + } - // unset OTA Flag in Waspmote Control Register - WaspRegister &= ~(REG_OTA); + // unset OTA Flag in Waspmote Control Register + WaspRegister &= ~(REG_OTA); - // If both IDs are equal a confirmation message is sent to the trasmitter - if(reprogrammingOK) - { + // If both IDs are equal a confirmation message is sent to the trasmitter + if (reprogrammingOK) + { + program_version = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION ); + eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP, program_version); + + return 1; + } + // If the IDs are different an error message is sent to the transmitter + else + { + program_version = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP); + eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION, program_version); + return 0; + } + } + else + { program_version = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION ); - eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP, program_version); + program_version_backup = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP ); - return 1; - } - // If the IDs are different an error message is sent to the transmitter - else - { - program_version = eeprom_read_byte((unsigned char *) EEPROM_PROG_VERSION_BACKUP); - eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION, program_version); - return 0; - } - } - else - { + if (program_version_backup != program_version) + { + eeprom_write_byte((unsigned char *) EEPROM_PROG_VERSION, program_version_backup); + return 0; + } return 2; - } + } } @@ -1281,6 +1484,24 @@ uint8_t WaspUtils::getBootVersion() } } +/* + * showVersion () - display Waspmote version number: v12 or v15 + * + * + */ +void WaspUtils::showVersion() +{ + if (getBootVersion() >= 'H') + { + USB.println(F("v15")); + } + else + { + USB.println(F("v12")); + } + +} + WaspUtils Utils = WaspUtils(); diff --git a/waspmote-api/WaspUtils.h b/waspmote-api/WaspUtils.h index e248ade..d36a8df 100755 --- a/waspmote-api/WaspUtils.h +++ b/waspmote-api/WaspUtils.h @@ -1,7 +1,7 @@ /*! \file WaspUtils.h \brief Library containing useful general functions - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.3 - Design: David Gascón + Version: 3.0 + Design: David Gascon Implementation: Alberto Bielsa, David Cuartielles */ @@ -45,41 +45,52 @@ /*! \def LED_ON \brief sets LED ON */ -#define LED_ON 1 - /*! \def LED_OFF \brief sets LED OFF */ +#define LED_ON 1 #define LED_OFF 0 -/*! \def MUX_TO_HIGH - \brief sets mux high - */ -#define MUX_TO_HIGH 1 -/*! \def MUX_TO_LOW - \brief sets mux low +/*! \def EEPROM_OTA_AUTHKEY + \brief Authentication key EEPROM address */ -#define MUX_TO_LOW 0 - -/*! \def EEPROM_START - \brief First EEPROM's writable address. There is a 1kB reserved area from - address 0 to address 1023. +/*! \def EEPROM_FRAME_MOTEID + \brief MOTEID EEPROM address */ -#define EEPROM_START 1024 - +/*! \def EEPROM_FRAME_SEQUENCE + \brief Sequence EEPROM address + */ /*! \def EEPROM_PROG_VERSION \brief EEPROM address for program version + */ +/*! \def EEPROM_SERIALID_START + \brief Starting address for the backup of Serial ID of Waspmote (4B) + */ +/*! \def EEPROM_START + \brief First EEPROM's writable address. There is a 1kB reserved area from + address 0 to address 1023. */ +#define EEPROM_OTA_FLAG 1 +#define EEPROM_OTA_RETRIES 98 +#define EEPROM_OTA_AUTHKEY 107 +#define EEPROM_FRAME_MOTEID 147 +#define EEPROM_FRAME_SEQUENCE 163 #define EEPROM_PROG_VERSION 225 #define EEPROM_PROG_VERSION_BACKUP 226 +#define EEPROM_SERIALID_START 227 +#define EEPROM_START 1024 + + -/*! \def EEPROM_SERIALID_START - \brief Starting address for the backup of Serial ID of Waspmote (4B) - */ -#define EEPROM_SERIALID_START 227 +//! Variable : Waspmote bootloader version +extern volatile uint8_t _boot_version; + +//! Variable : Waspmote serial id +extern volatile uint8_t _serial_id[8]; + /****************************************************************************** * Class @@ -253,11 +264,23 @@ class WaspUtils void setMuxUSB(); - //! It switches off the multiplexer on UART_0 + //! It switches off the multiplexer on UART0 and UART1 /*! \return void */ - void muxOFF(); + void muxOFF(); + + //! It switches off the multiplexer on UART0 + /*! + \return void + */ + void muxOFF0(); + + //! It switches off the multiplexer on UART1 + /*! + \return void + */ + void muxOFF1(); //! set multiplexer on UART_0 to SOCKET0 /*! @@ -379,6 +402,7 @@ class WaspUtils \return length of the converted array; '0' if error */ uint16_t str2hex(char* str, uint8_t* array); + uint16_t str2hex(char* str, uint8_t* array, uint16_t size); //! It converts a number stored in a string into a hexadecimal number /*! @@ -492,6 +516,9 @@ class WaspUtils */ uint8_t getBootVersion(); + //! It displays the Waspmote's version + void showVersion(); + }; extern WaspUtils Utils; diff --git a/waspmote-api/WaspVariables.h b/waspmote-api/WaspVariables.h index 7358a1b..e2977a9 100755 --- a/waspmote-api/WaspVariables.h +++ b/waspmote-api/WaspVariables.h @@ -1,7 +1,7 @@ /*! \file WaspVariables.h \brief General variables used through the libraries - Copyright (C) 2014 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.1 + Version: 3.0 Design: David Gascón Implementation: Alberto Bielsa, David Cuartielles @@ -56,7 +56,8 @@ volatile uint8_t intArray[8]; \brief Bitmap used for managing the different modules and power supplies by different libraries */ -volatile unsigned long WaspRegister; +volatile uint16_t WaspRegister; +volatile uint16_t WaspRegisterSensor; /*! \def pwrGasRegister \brief Bitmap used for managing the power supply for Gases PRO board @@ -70,4 +71,6 @@ volatile unsigned long WaspRegister; */ volatile uint8_t pwrGasPRORegister; +volatile uint8_t pwrCitiesPRORegister; + diff --git a/waspmote-api/WaspXBeeCore.cpp b/waspmote-api/WaspXBeeCore.cpp index ed11bf3..a857556 100755 --- a/waspmote-api/WaspXBeeCore.cpp +++ b/waspmote-api/WaspXBeeCore.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.2 + * Version: 3.1 * Design: David Gascón * Implementation: Alberto Bielsa, Yuri Carmona */ @@ -492,7 +492,11 @@ uint8_t WaspXBeeCore::setPAN(uint8_t* PANID) int8_t error=2; char buffer[33]; - if( (protocol==XBEE_802_15_4) || (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_868) ) + if( (protocol == XBEE_802_15_4) + || (protocol == DIGIMESH) + || (protocol == XBEE_900) + || (protocol == XBEE_868) + || (protocol == XBEE_900HP) ) { error_AT=2; @@ -520,12 +524,17 @@ uint8_t WaspXBeeCore::setPAN(uint8_t* PANID) if(!error) { - if( (protocol==XBEE_802_15_4) || (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_868) ) - { + if( (protocol == XBEE_802_15_4) + || (protocol == DIGIMESH) + || (protocol == XBEE_900) + || (protocol == XBEE_868) + || (protocol == XBEE_900HP) ) + { PAN_ID[0] = PANID[0]; PAN_ID[1] = PANID[1]; } - if(protocol==ZIGBEE) + + if( protocol == ZIGBEE ) { PAN_ID[0] = PANID[0]; PAN_ID[1] = PANID[1]; @@ -565,8 +574,12 @@ uint8_t WaspXBeeCore::getPAN() if(!error) { - if( (protocol==XBEE_802_15_4) || (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_868) ) - { + if( (protocol == XBEE_802_15_4) + || (protocol == DIGIMESH) + || (protocol == XBEE_900) + || (protocol == XBEE_868) + || (protocol == XBEE_900HP) ) + { PAN_ID[0] = data[0]; PAN_ID[1] = data[1]; } @@ -671,7 +684,7 @@ uint8_t WaspXBeeCore::setAwakeTime(uint8_t* awake) error=gen_send(buffer); } - if( (protocol==DIGIMESH) || (protocol==XBEE_900) ) + if( (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_900HP)) { error_AT=2; @@ -691,7 +704,7 @@ uint8_t WaspXBeeCore::setAwakeTime(uint8_t* awake) awakeTime[0]=awake[0]; awakeTime[1]=awake[1]; } - if( (protocol==DIGIMESH) || (protocol==XBEE_900) ) + if( (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_900HP) ) { awakeTime[0]=awake[0]; awakeTime[1]=awake[1]; @@ -730,7 +743,7 @@ uint8_t WaspXBeeCore::setSleepTime(uint8_t* sleep) error=gen_send(buffer); } - if( (protocol==DIGIMESH) || (protocol==XBEE_900) ) + if( (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_900HP) ) { error_AT=2; @@ -750,7 +763,7 @@ uint8_t WaspXBeeCore::setSleepTime(uint8_t* sleep) sleepTime[0]=sleep[0]; sleepTime[1]=sleep[1]; } - if( (protocol==DIGIMESH) || (protocol==XBEE_900) ) + if( (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_900HP) ) { sleepTime[0]=sleep[0]; sleepTime[1]=sleep[1]; @@ -1025,9 +1038,10 @@ uint8_t WaspXBeeCore::setScanningTime(uint8_t* time) error=gen_send(buffer); } - if( protocol==XBEE_868 || - protocol==DIGIMESH || - protocol==XBEE_900 ) + if( ( protocol == XBEE_868 ) + || ( protocol == DIGIMESH ) + || ( protocol == XBEE_900 ) + || ( protocol == XBEE_900HP ) ) { error_AT=2; // set_scanning_time_DM @@ -1046,7 +1060,7 @@ uint8_t WaspXBeeCore::setScanningTime(uint8_t* time) { scanTime[0]=time[0]; } - if( (protocol==DIGIMESH) || (protocol==XBEE_868)|| (protocol==XBEE_900) ) + if( (protocol==DIGIMESH) || (protocol==XBEE_868)|| (protocol==XBEE_900)|| (protocol==XBEE_900HP) ) { scanTime[0]=time[0]; scanTime[1]=time[1]; @@ -1088,7 +1102,7 @@ uint8_t WaspXBeeCore::getScanningTime() { scanTime[0]=data[1]; } - if( (protocol==DIGIMESH) || (protocol==XBEE_868) || (protocol==XBEE_900)) + if( (protocol==DIGIMESH) || (protocol==XBEE_868) || (protocol==XBEE_900)|| (protocol==XBEE_900HP)) { scanTime[0]=data[0]; scanTime[1]=data[1]; @@ -1585,7 +1599,7 @@ uint8_t WaspXBeeCore::getRSSI() //clear buffer memset( ByteIN, 0x00, sizeof(ByteIN) ); - if( (protocol == XBEE_802_15_4 ) || (protocol==ZIGBEE) ) + if( (protocol == XBEE_802_15_4 ) || (protocol==ZIGBEE) || (protocol==XBEE_900HP) ) { error_AT=2; @@ -1633,7 +1647,7 @@ uint8_t WaspXBeeCore::getRSSI() if( error == 0 ) { - if( (protocol==XBEE_802_15_4) || (protocol==ZIGBEE) ) + if( (protocol==XBEE_802_15_4) || (protocol==ZIGBEE) || (protocol==XBEE_900HP) ) { valueRSSI[0] = data[0]; } @@ -1844,7 +1858,11 @@ uint8_t WaspXBeeCore::setSleepOptions(uint8_t soption) int8_t error=2; char buffer[20]; - if( (protocol==ZIGBEE) || (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_868) ) + if(( protocol == ZIGBEE ) + || ( protocol == DIGIMESH ) + || ( protocol == XBEE_900 ) + || ( protocol == XBEE_868 ) + || ( protocol == XBEE_900HP ) ) { error_AT = 2; @@ -1886,7 +1904,11 @@ uint8_t WaspXBeeCore::getSleepOptions() strcpy_P(buffer, (char*)pgm_read_word(&(table_CORE[42]))); if(buffer==NULL) return 1; - if( (protocol==ZIGBEE) || (protocol==DIGIMESH) || (protocol==XBEE_900) || (protocol==XBEE_868) ) + if(( protocol == ZIGBEE ) + || ( protocol == DIGIMESH ) + || ( protocol == XBEE_900 ) + || ( protocol == XBEE_868 ) + || ( protocol == XBEE_900HP ) ) { error_AT = 2; gen_data(buffer); @@ -2028,10 +2050,11 @@ uint8_t WaspXBeeCore::getDestinationAddress(uint8_t* naD) naD[0]=data[2]; naD[1]=data[3]; } - else if( protocol == ZIGBEE || - protocol == DIGIMESH || - protocol == XBEE_900 || - protocol == XBEE_868 ) + else if(( protocol == ZIGBEE ) + || ( protocol == DIGIMESH ) + || ( protocol == XBEE_900 ) + || ( protocol == XBEE_868) + || ( protocol == XBEE_900HP) ) { naD[0]=0x00; naD[1]=0x13; @@ -2204,16 +2227,40 @@ uint8_t WaspXBeeCore::ON(uint8_t uart_used) uint8_t error=2; // call initialization function - init(uart_used); + init(uart_used); + + // select multiplexer + if (uart == SOCKET0) + { + Utils.setMuxSocket0(); + } + if (uart == SOCKET1) + { + Utils.setMuxSocket1(); + + // update WaspRegister for SPI interferences in Waspv15 + WaspRegister &= ~(REG_XBEE_SOCKET0); + } + + // begin serial communication + beginSerial(XBEE_RATE, uart); - begin(uart,XBEE_RATE); - setMode(XBEE_ON); + // power on the socket + PWR.powerSocket(uart, HIGH); + + if (_boot_version >= 'G') + { + // update SPI flag + SPI.isSocket0 = true; + } // update Waspmote Register if(uart_used==SOCKET0) WaspRegister |= REG_SOCKET0; if(uart_used==SOCKET1) WaspRegister |= REG_SOCKET1; if( protocol == ZIGBEE) delay(500); + else if( protocol == XBEE_868LP) delay(500); + else if( protocol == XBEE_900HP) delay(500); else if( protocol == DIGIMESH) delay(500); else delay(50); error=0; @@ -2226,72 +2273,6 @@ uint8_t WaspXBeeCore::ON(uint8_t uart_used) } -/* - Function: opens uart communication depending on the selected uart. - It also set high the microcontroller pins which switch the XBee ON and select - the USB multiplexor output in order to communicate with the XBee instead of the - USB port. - - Returns: void -*/ -void WaspXBeeCore::begin(uint8_t uart, uint32_t speed) -{ - // begin serial communication - beginSerial(speed, uart); - - // set microcontroller pins as output - pinMode(XBEE_PW,OUTPUT); - pinMode(MUX_PW,OUTPUT); - pinMode(MUX_USB_XBEE,OUTPUT); - - // set multiplexor supply on - digitalWrite(MUX_PW,HIGH); - digitalWrite(MUX_USB_XBEE,HIGH); -} - - -/* - Function: switches ON/OFF the correspondent XBee module allocated in the - selected uart. - It also switches the GPRS/GPS/aux1/aux2 multiplexor to Expansion Board (GPRS) - Returns: void -*/ -void WaspXBeeCore::setMode(uint8_t mode) -{ - switch (mode) - { - case XBEE_ON: if(uart==SOCKET0) - { - digitalWrite(XBEE_PW,HIGH); - } - else if(uart==SOCKET1) - { - // Switch Multiplexor to Expansion Board - Utils.setMuxSocket1(); - // Switch on XBee module - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,HIGH); - } - break; - - case XBEE_OFF: if(uart==SOCKET0) - { - digitalWrite(XBEE_PW,LOW); - } - else if(uart==SOCKET1) - { - Utils.setMux(MUX_TO_LOW,MUX_TO_LOW); - // Switch off XBee module - pinMode(DIGITAL6,OUTPUT); - digitalWrite(DIGITAL6,LOW); - } - break; - - default: break; - } -} - - /* Function: disconnects XBee, switching it off and closing the UART Returns: Integer that determines if there has been any error @@ -2302,12 +2283,22 @@ void WaspXBeeCore::setMode(uint8_t mode) uint8_t WaspXBeeCore::OFF() { uint8_t error=2; + + // close UART + closeSerial(uart); + + // unselect multiplexer + if (uart == SOCKET0) Utils.setMuxUSB(); + if (uart == SOCKET1) Utils.muxOFF1(); - // close UART and MUX - close(); + // switch module OFF + PWR.powerSocket(uart, LOW); - // switch XBee OFF - setMode(XBEE_OFF); + if (_boot_version >= 'G') + { + // update SPI flag + SPI.isSocket0 = false; + } // update Waspmote Register if(uart == SOCKET0) WaspRegister &= ~(REG_SOCKET0); @@ -2319,15 +2310,6 @@ uint8_t WaspXBeeCore::OFF() } -void WaspXBeeCore::close() -{ - closeSerial(uart); - pinMode(MUX_PW,OUTPUT); - pinMode(MUX_USB_XBEE,OUTPUT); - digitalWrite(MUX_PW,LOW); - digitalWrite(MUX_USB_XBEE,LOW); -} - /* Function: Set XBee to sleep, asserting PIN 9 @@ -2352,8 +2334,9 @@ uint8_t WaspXBeeCore::sleep() digitalWrite(DIGITAL7,HIGH); } - // close UART and MUX - close(); + // close UART and Multiplexer + closeSerial(uart); + Utils.setMuxUSB(); error=0; return error; @@ -2381,7 +2364,8 @@ uint8_t WaspXBeeCore::wake() digitalWrite(DIGITAL7,LOW); } - begin(uart,XBEE_RATE); + Utils.setMuxSocket0(); + beginSerial(XBEE_RATE, uart); delay(50); error=0; @@ -2482,6 +2466,12 @@ uint8_t WaspXBeeCore::sendXBee(struct packetXBee* packet) case XBEE_868: maxPayload=100; break; + + case XBEE_900HP:maxPayload=0xFF; + break; + + case XBEE_868LP:maxPayload=0xFF; + break; default: break; @@ -4185,7 +4175,8 @@ uint8_t WaspXBeeCore::atCommandResponse( uint8_t* data_in, // FIXME: Digimesh/868/900 typo if( (protocol == DIGIMESH || protocol == XBEE_900 || - protocol == XBEE_868 ) && data_in[start+7]==0x40 ) + protocol == XBEE_868 || + protocol == XBEE_900HP ) && data_in[start+7]==0x40 ) { // do nothing. it is a valid response because these protocols // answer command_status = 0x40 when doing a Discovery @@ -4263,7 +4254,7 @@ uint8_t WaspXBeeCore::txStatusResponse() uint8_t status=0; uint16_t num_TX=0; uint8_t num_esc=0; - uint16_t interval=2000; + uint16_t interval=5000; uint8_t num_mes=0; uint16_t i=1; uint16_t length_mes=0; @@ -4511,7 +4502,7 @@ uint8_t WaspXBeeCore::txZBStatusResponse() uint8_t status=0; uint16_t num_TX=0; uint8_t num_esc=0; - uint16_t interval=2000; + uint16_t interval=5000; uint8_t num_mes=0; uint16_t i=1; uint16_t length_mes=0; @@ -4879,8 +4870,9 @@ void WaspXBeeCore::treatScan() else if( protocol == ZIGBEE || protocol == DIGIMESH || protocol == XBEE_900 || - protocol == XBEE_868 ) - { + protocol == XBEE_868 || + protocol == XBEE_900HP ) + { if (data_length>19) { length_NI = data_length-19; @@ -5583,9 +5575,7 @@ void WaspXBeeCore::new_firmware_end() // set destination parameters setDestinationParams(paq_sent, destination, data); - - // set random seed - srand(_serial_id); + // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -5634,8 +5624,6 @@ void WaspXBeeCore::new_firmware_end() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -5827,8 +5815,6 @@ void WaspXBeeCore::upload_firmware() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -5905,8 +5891,6 @@ void WaspXBeeCore::upload_firmware() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6004,8 +5988,6 @@ void WaspXBeeCore::request_ID() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6112,8 +6094,6 @@ void WaspXBeeCore::request_bootlist() setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6171,8 +6151,6 @@ void WaspXBeeCore::request_bootlist() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6214,10 +6192,7 @@ void WaspXBeeCore::request_bootlist() // set destination parameters setDestinationParams(paq_sent, destination, data); - - - // set random seed - srand(_serial_id); + // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6323,9 +6298,7 @@ void WaspXBeeCore::checkNewProgram() // set destination parameters setDestinationParams(paq_sent, destination, data); - - // set random seed - srand(_serial_id); + // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6361,8 +6334,6 @@ void WaspXBeeCore::checkNewProgram() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6396,8 +6367,6 @@ void WaspXBeeCore::checkNewProgram() // set destination parameters setDestinationParams(paq_sent, destination, data); - // set random seed - srand(_serial_id); // delay random time delay( (rand()%delay_end + delay_start) ); // Try to send the answer for several times @@ -6621,9 +6590,7 @@ void WaspXBeeCore::delete_firmware() // set destination parameters setDestinationParams(paq_sent, destination, data); - - // set random seed - srand(_serial_id); + // delay random time delay( (rand()%delay_end + delay_start) ); @@ -6665,9 +6632,7 @@ void WaspXBeeCore::delete_firmware() // set destination parameters setDestinationParams(paq_sent, destination, data); - - // set random seed - srand(_serial_id); + // delay random time delay( (rand()%delay_end + delay_start) ); @@ -6893,9 +6858,7 @@ void WaspXBeeCore::gen_escaped_frame( uint8_t* TX, int8_t WaspXBeeCore::receivePacketTimeout( uint32_t timeout) { unsigned long previous; - int i=0; - uint16_t start = 0; - uint16_t end = 0; + uint16_t i=0; uint16_t length = 0; bool restart = false; bool doneStep1 = false; @@ -7240,8 +7203,7 @@ int8_t WaspXBeeCore::receivePacketTimeout( uint32_t timeout) * state = 0 --> OK: The command has been executed with no errors */ uint8_t WaspXBeeCore::setRTCfromMeshlium(char* address) -{ - uint16_t length = 0; +{ bool status = false; uint8_t error = 0; int result; @@ -7303,9 +7265,9 @@ uint8_t WaspXBeeCore::setRTCfromMeshlium(char* address) if( status == true ) { // wait for response - int error = receivePacketTimeout( 5000 ); + int rx_error = receivePacketTimeout( 5000 ); - if( error == 0 ) + if( rx_error == 0 ) { if( _length == PATTERN_LENGTH ) { @@ -7375,7 +7337,10 @@ uint8_t WaspXBeeCore::setRTCfromMeshlium(char* address) if( status == true) { // set new timestamp - RTC.ON(); + if (RTC.isON == 0) + { + RTC.ON(); + } error = RTC.setTime(year, month, date, diff --git a/waspmote-api/WaspXBeeCore.h b/waspmote-api/WaspXBeeCore.h index e7a53dd..db018a5 100755 --- a/waspmote-api/WaspXBeeCore.h +++ b/waspmote-api/WaspXBeeCore.h @@ -1,7 +1,7 @@ /*! \file WaspXBeeCore.h \brief Library for managing the XBee modules - Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. http://www.libelium.com This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . - Version: 1.5 + Version: 3.1 Design: David Gascón Implementation: Alberto Bielsa, Yuri Carmona @@ -41,6 +41,7 @@ #include "WConstants.h" #include "WaspUSB.h" #include "pins_waspmote.h" +#include "WaspConstants.h" #include // SD Utilities @@ -58,6 +59,8 @@ #define DIGIMESH 3 #define XBEE_900 4 #define XBEE_868 5 +#define XBEE_900HP 6 +#define XBEE_868LP 7 //Different modes @@ -663,12 +666,9 @@ struct rxPacket91_t uint8_t checksum; }; - -//! Variable : Waspmote serial id -/*! -*/ -extern volatile unsigned long _serial_id; - +extern volatile uint8_t _boot_version; +extern volatile uint16_t WaspRegister; +extern volatile uint16_t WaspRegisterSensor; @@ -697,8 +697,8 @@ class WaspXBeeCore */ SdFile boot_file; -public: - +public: + //! Class constructor /*! Initializes buffers \param void @@ -707,9 +707,12 @@ class WaspXBeeCore WaspXBeeCore() { // set the default maximum number of retries to '3' - _send_retries = 3; - }; - + _send_retries = 3; + + // update WaspRegister for SPI interferences in Waspv15 + WaspRegister |= REG_XBEE_SOCKET0; + } + //! It initalizes all necessary variables including its parent's variables virtual void init( uint8_t uart_used ); @@ -1053,7 +1056,6 @@ class WaspXBeeCore //! It sends a packet from one XBee to another XBee in API mode /*! This function performs application-level retries. * This function is only used for 64-bit addressing. - /*! \param char* macAddress : destination MAC address \param char* data : data to be sent (as string) \return '0' on success, '1' error @@ -1063,7 +1065,6 @@ class WaspXBeeCore //! It sends a packet from one XBee to another XBee in API mode /*! This function performs application-level retries. * This function is only used for 64-bit addressing. - /*! \param char* macAddress : destination MAC address \param uint8_t* pointer : pointer to buffer of data to be sent \param uint16_t length : length of the buffer @@ -1124,33 +1125,13 @@ class WaspXBeeCore \return '0' on success, '1' otherwise */ uint8_t ON(uint8_t uart_used); - - //! It opens the UART - /*! It also set high the microcontroler pins which switch the XBee on and - select the USB multiplexor output in order to communicate with the XBee - instead of the USB port. - \return void - */ - void begin(uint8_t uart, uint32_t speed); - - //! switches ON/OFF the XBee module depending on the socket - /*! It also switches the GPRS/GPS/aux1/aux2 multiplexor to Expansion Board - \return void - */ - void setMode(uint8_t mode); - + //! It disconnects XBee, switching it off and closing the UART /*! \return '0' on success, '1' otherwise */ uint8_t OFF(); - - //! It closes the UART and unsets the multiplexor to the XBee - /*! - \return void - */ - void close(); - + //! It sets the XBee to sleep, asserting PIN 9 /*! \return '0' on success, '1' otherwise diff --git a/waspmote-api/Waspmote.h b/waspmote-api/Waspmote.h index 3eefd2a..89f1315 100755 --- a/waspmote-api/Waspmote.h +++ b/waspmote-api/Waspmote.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 0.1 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascón * Implementation: David Cuartielles, Alberto Bielsa */ diff --git a/waspmote-api/Wire.cpp b/waspmote-api/Wire.cpp index 67b7bb5..570b07c 100755 --- a/waspmote-api/Wire.cpp +++ b/waspmote-api/Wire.cpp @@ -1,5 +1,5 @@ /* - * Modified for Waspmote by Libelium, 2009-2015 + * Modified for Waspmote by Libelium, 2009-2016 * * Copyright (c) 2006 Nicholas Zambetti. All right reserved. * @@ -15,6 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ extern "C" { @@ -61,6 +63,10 @@ TwoWire::TwoWire() void TwoWire::begin(void) { + #if DEBUG_I2C > 1 + PRINT_I2C(F("I2C begin\n")); + #endif + // init buffer for reads memset( rxBuffer, 0x00, BUFFER_LENGTH); rxBufferIndex = 0; @@ -74,8 +80,10 @@ void TwoWire::begin(void) twi_init(); // update flag - I2C_ON = 1; + isON = 1; + Wire.secureBegin(); + delayMicroseconds(4); } @@ -89,7 +97,7 @@ void TwoWire::begin(uint8_t address) void TwoWire::begin(int address) { - begin((uint8_t)address); + begin((uint8_t)address); } @@ -120,9 +128,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) rxBufferIndex = 0; rxBufferLength = quantity; - // Secure I2C power management - Wire.secureEnd(); - return ret; } @@ -163,9 +168,6 @@ uint8_t TwoWire::endTransmission(void) // indicate that we are done transmitting transmitting = 0; - // Secure I2C power management - Wire.secureEnd(); - return ret; } @@ -196,9 +198,6 @@ void TwoWire::send(uint8_t data) // in slave send mode // reply to master twi_transmit(&data, 1); - - // Secure I2C power management - Wire.secureEnd(); } } @@ -223,9 +222,6 @@ void TwoWire::send(uint8_t* data, uint8_t quantity) // in slave send mode // reply to master twi_transmit(data, quantity); - - // Secure I2C power management - Wire.secureEnd(); } } @@ -234,7 +230,7 @@ void TwoWire::send(uint8_t* data, uint8_t quantity) // or after beginTransmission(address) void TwoWire::send(char* data) { - send((uint8_t*)data, strlen(data)); + send((uint8_t*)data, strlen(data)); } // must be called in: @@ -242,7 +238,7 @@ void TwoWire::send(char* data) // or after beginTransmission(address) void TwoWire::send(int data) { - send((uint8_t)data); + send((uint8_t)data); } // must be called in: @@ -250,7 +246,7 @@ void TwoWire::send(int data) // or after requestFrom(address, numBytes) uint8_t TwoWire::available(void) { - return rxBufferLength - rxBufferIndex; + return rxBufferLength - rxBufferIndex; } // must be called in: @@ -258,75 +254,90 @@ uint8_t TwoWire::available(void) // or after requestFrom(address, numBytes) uint8_t TwoWire::receive(void) { - // default to returning null char - // for people using with char strings - uint8_t value = '\0'; + // default to returning null char + // for people using with char strings + uint8_t value = '\0'; - // get each successive byte on each call - if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; - ++rxBufferIndex; - } + // get each successive byte on each call + if(rxBufferIndex < rxBufferLength) + { + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + } - return value; + #if DEBUG_I2C > 1 + PRINT_I2C(F("rxBuffer: ")); + USB.printHexln(rxBuffer, rxBufferIndex); + #endif + + return value; } // behind the scenes function that is called when data is received void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { - // don't bother if user hasn't registered a callback - if(!user_onReceive){ - return; - } - // don't bother if rx buffer is in use by a master requestFrom() op - // i know this drops data, but it allows for slight stupidity - // meaning, they may not have read all the master requestFrom() data yet - if(rxBufferIndex < rxBufferLength){ - return; - } - // copy twi rx buffer into local read buffer - // this enables new reads to happen in parallel - for(uint8_t i = 0; i < numBytes; ++i){ - rxBuffer[i] = inBytes[i]; - } - // set rx iterator vars - rxBufferIndex = 0; - rxBufferLength = numBytes; - // alert user program - user_onReceive(numBytes); + // don't bother if user hasn't registered a callback + if(!user_onReceive) + { + return; + } + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if(rxBufferIndex < rxBufferLength) + { + return; + } + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + for(uint8_t i = 0; i < numBytes; ++i) + { + rxBuffer[i] = inBytes[i]; + } + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + // alert user program + user_onReceive(numBytes); } // behind the scenes function that is called when data is requested void TwoWire::onRequestService(void) { - // don't bother if user hasn't registered a callback - if(!user_onRequest){ - return; - } - // reset tx buffer iterator vars - // !!! this will kill any pending pre-master sendTo() activity - txBufferIndex = 0; - txBufferLength = 0; - // alert user program - user_onRequest(); + // don't bother if user hasn't registered a callback + if(!user_onRequest) + { + return; + } + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + // alert user program + user_onRequest(); } // sets function called on slave write void TwoWire::onReceive( void (*function)(int) ) { - user_onReceive = function; + user_onReceive = function; } // sets function called on slave read void TwoWire::onRequest( void (*function)(void) ) { - user_onRequest = function; + user_onRequest = function; } void TwoWire::close() { twi_close(); - I2C_ON = 0; + isON = 0; + Wire.secureEnd(); + + #if DEBUG_I2C > 1 + PRINT_I2C(F("I2C closed\n")); + #endif } @@ -345,20 +356,32 @@ void TwoWire::secureBegin() // this codeblock belongs to the performance of the I2C bus // check if any Sensor Board (with I2C components) is ON before using I2C - if( (WaspRegister & REG_METERING) || - (WaspRegister & REG_AGRICULTURE) || - (WaspRegister & REG_GASES) || - (WaspRegister & REG_EVENTS) || - (WaspRegister & REG_CITIES_V14) || - (WaspRegister & REG_CITIES_V15) || - (WaspRegister & REG_PROTOTYPING) ) + if ((WaspRegisterSensor & REG_METERING) || + (WaspRegisterSensor & REG_AGRICULTURE) || + (WaspRegisterSensor & REG_GASES) || + (WaspRegisterSensor & REG_EVENTS) || + (WaspRegisterSensor & REG_CITIES_V14) || + (WaspRegisterSensor & REG_CITIES_V15) || + (WaspRegisterSensor & REG_PROTOTYPING)) { - if( Wire.isBoard == false ) - { + if (Wire.isBoard == false) + { + #if DEBUG_I2C > 0 + PRINT_I2C(F("Sensor Board power ON\n")); + #endif // It is necessary to switch on the power supply if the Sensor Board is // connected to Waspmote so as not to cause intereferences in the I2C bus - PWR.setSensorPower(SENS_3V3, SENS_ON); - PWR.setSensorPower(SENS_5V, SENS_ON); + if ((WaspRegisterSensor & REG_EVENTS) && !_3V3_ON) + { + PWR.setSensorPower(SENS_3V3, SENS_ON); + delay(50); + } + else if (!_5V_ON || !_3V3_ON) + { + PWR.setSensorPower(SENS_3V3, SENS_ON); + PWR.setSensorPower(SENS_5V, SENS_ON); + delay(50); + } } } } @@ -375,40 +398,49 @@ void TwoWire::secureEnd() { // this codeblock belongs to the performance of the I2C bus // check if any Sensor Board (with I2C components) is ON before using I2C - if( (WaspRegister & REG_METERING) || - (WaspRegister & REG_AGRICULTURE) || - (WaspRegister & REG_GASES) || - (WaspRegister & REG_EVENTS) || - (WaspRegister & REG_CITIES_V14) || - (WaspRegister & REG_CITIES_V15) || - (WaspRegister & REG_PROTOTYPING) ) + if ((WaspRegisterSensor & REG_METERING) || + (WaspRegisterSensor & REG_AGRICULTURE) || + (WaspRegisterSensor & REG_GASES) || + (WaspRegisterSensor & REG_EVENTS) || + (WaspRegisterSensor & REG_CITIES_V14) || + (WaspRegisterSensor & REG_CITIES_V15) || + (WaspRegisterSensor & REG_PROTOTYPING)) { // this codeblock belongs to the performance of the SD card // switch off the SX module if it was not powered on - if( (Wire.isBoard == false) ) + if (Wire.isBoard == false) { + #if DEBUG_I2C > 0 + PRINT_I2C(F("Sensor Board power OFF\n")); + #endif + // switch OFF sensor boards to previous state before 'secureBegin' - PWR.setSensorPower(SENS_3V3, SENS_OFF); - PWR.setSensorPower(SENS_5V, SENS_OFF); + if (WaspRegisterSensor & REG_EVENTS) + { + PWR.setSensorPower(SENS_3V3, SENS_OFF); + } + else + { + PWR.setSensorPower(SENS_3V3, SENS_OFF); + PWR.setSensorPower(SENS_5V, SENS_OFF); + } } else { // if sensor board were switched off without doing OFF from their // class function, then it is necessary to do it manually: // set power supply lines to previous state before 'secureBegin' - if( _3V3_ON == false ) + if (_3V3_ON == false) { PWR.setSensorPower(SENS_3V3, SENS_OFF); } - if( _5V_ON == false ) + if (_5V_ON == false) { PWR.setSensorPower(SENS_5V, SENS_OFF); } } - - - } + } } /* Function: This function writes a bit via I2C @@ -416,10 +448,14 @@ void TwoWire::secureEnd() * regAddr: I2C register * data: data to send * pos: position of the bit to write [7|6|5|4|3|2|1|0] - * Return: 1 if OK, -1 if error - * + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ -int8_t TwoWire::writeBit(uint8_t devAddr, uint8_t regAddr, bool data, uint8_t pos) +int8_t TwoWire::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_t pos) { uint8_t buffer; uint8_t mask; @@ -428,36 +464,36 @@ int8_t TwoWire::writeBit(uint8_t devAddr, uint8_t regAddr, bool data, uint8_t po // Read the register error = readBytes(devAddr, regAddr, &buffer, 1); - if (error != 1) + if (error != 0) { return error; } - - #ifdef I2C_DEBUG_FULL - USB.print(F("Bit pos: ")); + #if DEBUG_I2C > 1 + PRINT_I2C(F("Bit pos: ")); USB.println(pos, DEC); - USB.print("Old value: "); + PRINT_I2C(F("Old value: ")); USB.println(buffer, BIN); #endif + // Mask to the read data and stores the value mask = ~(1 << pos); - data = (data << pos) & mask; + data = (data << pos); buffer &= mask; buffer |= data; - #ifdef I2C_DEBUG_FULL - USB.print("mask: "); + #if DEBUG_I2C > 1 + PRINT_I2C(F("mask: ")); USB.println(mask, BIN); - USB.print("data: "); + PRINT_I2C(F("data: ")); USB.println(data, BIN); - USB.print("New value: "); + PRINT_I2C(F("New value: ")); USB.println(buffer, BIN); #endif // Write the register - writeBytes(devAddr, regAddr, &buffer, 1); - if (error != 1) + error = writeBytes(devAddr, regAddr, &buffer, 1); + if (error != 0) { return error; } @@ -471,7 +507,12 @@ int8_t TwoWire::writeBit(uint8_t devAddr, uint8_t regAddr, bool data, uint8_t po * data: data to send * pos: first position of the bits to write starting by the LSb [7|6|5|4|3|2|1|0] * length: number of bits to write - * Return: 1 if OK, -1 if error + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ int8_t TwoWire::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_t pos, uint8_t length) { @@ -481,17 +522,17 @@ int8_t TwoWire::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_ // Read the register error = readBytes(devAddr, regAddr, &buffer, 1); - if (error != 1) + if (error != 0) { return error; } - #ifdef I2C_DEBUG_FULL - USB.print(F("Bit pos: ")); + #if DEBUG_I2C > 1 + PRINT_I2C(F("Bit pos: ")); USB.println(pos, DEC); - USB.print(F("Bit length: ")); + PRINT_I2C(F("Bit length: ")); USB.println(length, DEC); - USB.print("Old value: "); + PRINT_I2C(F("Old value: ")); USB.println(buffer, BIN); #endif @@ -501,18 +542,18 @@ int8_t TwoWire::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_ buffer &= ~mask; buffer |= data; - #ifdef I2C_DEBUG_FULL - USB.print("mask: "); + #if DEBUG_I2C > 1 + PRINT_I2C(F("mask: ")); USB.println(mask, BIN); - USB.print("data: "); + PRINT_I2C(F("data: ")); USB.println(data, BIN); - USB.print("New value: "); + PRINT_I2C(F("New value: ")); USB.println(buffer, BIN); #endif // Write the register - writeBytes(devAddr, regAddr, &buffer, 1); - if (error != 1) + error = writeBytes(devAddr, regAddr, &buffer, 1); + if (error != 0) { return error; } @@ -525,13 +566,36 @@ int8_t TwoWire::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_ * regAddr: I2C register * data: data to send * length: number of bytes to send - * Return: Nothing + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ -void TwoWire::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length) +int8_t TwoWire::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { - - #ifdef I2C_DEBUG - USB.print(F("I2C (0x")); + return writeBytes(devAddr, regAddr, &data, 1); +} + +/* Function: This function writes bytes via I2C + * Parameters: devAddr: I2C address of the device + * regAddr: I2C register + * data: data to send + * length: number of bytes to send + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout + */ +int8_t TwoWire::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length) +{ + uint8_t error; + + #if DEBUG_I2C > 0 + PRINT_I2C(F("I2C (0x")); USB.printHex(devAddr); USB.print(F(") writing ")); USB.print(length, DEC); @@ -540,17 +604,21 @@ void TwoWire::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_ USB.print(F("...")); #endif - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) { Wire.beginTransmission(devAddr); Wire.send(regAddr + k); - for (uint8_t i = 0; i < length; i++) { + for (uint8_t i = 0; i < length; i++) + { Wire.send( data[i]); - #ifdef I2C_DEBUG + #if DEBUG_I2C > 0 USB.printHex(data[i]); if (i + 1 < length) { @@ -558,12 +626,21 @@ void TwoWire::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_ } #endif } - Wire.endTransmission(); + error = Wire.endTransmission(); + /*if (error != 0) + { + #if DEBUG_I2C > 0 + USB.println(F(". endTransmission error")); + #endif + return error; + }*/ } - #ifdef I2C_DEBUG + #if DEBUG_I2C > 0 USB.println(F(". Done")); #endif + + return 0; } /* Function: This function reads a bit via I2C @@ -571,7 +648,12 @@ void TwoWire::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_ * regAddr: I2C register * data: buffer to store the data * pos: position of the bit to read [7|6|5|4|3|2|1|0] - * Return: Bytes read, -1 if error + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ int8_t TwoWire::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t pos) { @@ -580,10 +662,10 @@ int8_t TwoWire::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t answer = readBytes( devAddr, regAddr, &buffer, 1); - #ifdef I2C_DEBUG_FULL - USB.print(F("Bit pos: ")); + #if DEBUG_I2C > 1 + PRINT_I2C(F("Bit pos: ")); USB.println(pos, DEC); - USB.print("Old value: "); + PRINT_I2C(F("Old value: ")); USB.println(buffer, BIN); #endif @@ -598,10 +680,10 @@ int8_t TwoWire::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t } - #ifdef I2C_DEBUG_FULL - USB.print("mask: "); + #if DEBUG_I2C > 1 + PRINT_I2C(F("mask: ")); USB.println(mask, BIN); - USB.print("New value: "); + PRINT_I2C(F("New value: ")); USB.println(data[0], BIN); #endif @@ -613,7 +695,12 @@ int8_t TwoWire::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t * regAddr: I2C register * data: buffer to store the data * pos: position of the bit to read starting by the LSb [7|6|5|4|3|2|1|0] - * Return: Bytes read, -1 if error + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ int8_t TwoWire::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t pos, uint8_t length) { @@ -623,12 +710,12 @@ int8_t TwoWire::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_ answer = readBytes( devAddr, regAddr, &buffer, 1); - #ifdef I2C_DEBUG_FULL - USB.print(F("Bit pos: ")); + #if DEBUG_I2C > 1 + PRINT_I2C(F("Bit pos: ")); USB.println(pos, DEC); - USB.print(F("Bit length: ")); + PRINT_I2C(F("Bit length: ")); USB.println(length, DEC); - USB.print("Old value: "); + PRINT_I2C(F("Old value: ")); USB.println(buffer, BIN); #endif @@ -638,28 +725,49 @@ int8_t TwoWire::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_ buffer &= mask; data[0] = buffer; - #ifdef I2C_DEBUG_FULL - USB.print("mask: "); + #if DEBUG_I2C > 1 + PRINT_I2C(F("mask: ")); USB.println(mask, BIN); - USB.print("New value: "); + PRINT_I2C(F("New value: ")); USB.println(buffer, BIN); #endif return answer; } +/* Function: This function reads bytes via I2C + * Parameters: devAddr: I2C address of the device + * regAddr: I2C register + * data: buffer to store the data + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout + */ +int8_t TwoWire::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data) +{ + return readBytes( devAddr, regAddr, data, 1); +} + /* Function: This function reads bytes via I2C * Parameters: devAddr: I2C address of the device * regAddr: I2C register * data: buffer to store the data * length: number of bytes to read - * Return: Bytes read, -1 if error + * Return: 0 if OK + * 1 if length to long for buffer + * 2 if address send, NACK received + * 3 if data send, NACK received + * 4 if other twi error (lost bus arbitration, bus error, ..) + * 5 if timeout */ int8_t TwoWire::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length) { - #ifdef I2C_DEBUG - USB.print(F("I2C (0x")); + #if DEBUG_I2C > 0 + PRINT_I2C(F("I2C (0x")); USB.printHex(devAddr); USB.print(F(") reading ")); USB.print(length, DEC); @@ -669,16 +777,27 @@ int8_t TwoWire::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8 #endif int8_t count = 0; - uint32_t t1; + uint32_t t1 = millis(); + uint8_t error; - // Inits I2C bus - if( !Wire.I2C_ON ) Wire.begin(); + // init I2C bus + if (!Wire.isON) + { + Wire.begin(); + } for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) { Wire.beginTransmission(devAddr); - Wire.send(regAddr + k); - Wire.endTransmission(); + Wire.send(regAddr + k); + error = Wire.endTransmission(); + /*if (error != 0) + { + #if DEBUG_I2C > 0 + USB.println(F(". endTransmission error")); + #endif + return error; + }*/ t1 = millis(); Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); @@ -686,7 +805,7 @@ int8_t TwoWire::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8 for (; Wire.available() && ((readTimeout == 0) || (millis() - t1) < readTimeout); count++) { data[count] = Wire.receive(); - #ifdef I2C_DEBUG + #if DEBUG_I2C > 0 USB.printHex(data[count]); if (count + 1 < length) { @@ -694,23 +813,34 @@ int8_t TwoWire::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8 } #endif } - Wire.endTransmission(); + error = Wire.endTransmission(); + /* if (error != 0) + { + #if DEBUG_I2C > 0 + USB.println(F(". endTransmission error")); + #endif + return error; + }*/ + } // check for timeout if ((readTimeout > 0) && ((millis() - t1) >= readTimeout) && (count < length)) { - count = -1; // timeout + #if DEBUG_I2C > 0 + USB.print(F(". Timeout error")); + #endif + return 5; // timeout } - #ifdef I2C_DEBUG + #if DEBUG_I2C > 0 USB.print(F(". Done (")); USB.print(count, DEC); USB.println(F(" read).")); #endif - return count; + return 0; } diff --git a/waspmote-api/Wire.h b/waspmote-api/Wire.h index ee9daa0..04282b9 100755 --- a/waspmote-api/Wire.h +++ b/waspmote-api/Wire.h @@ -1,8 +1,8 @@ /*! * @file Wire.h - * @version 1.1 + * @version 3.1 * - * Modified for Waspmote by Libelium, 2009-2015 + * Modified for Waspmote by Libelium, 2009-2016 * Copyright (c) 2006 Nicholas Zambetti. All right reserved. * * This program is free software: you can redistribute it and/or modify @@ -27,8 +27,20 @@ #define BUFFER_LENGTH 32 -//#define I2C_DEBUG -//#define I2C_DEBUG_FULL +//! DEBUG MODE +/*! 0: No debug mode enabled + * 1: debug mode enabled + * 2: verbose debug mode enabled + */ +#define DEBUG_I2C 0 +// #define DEBUG_I2C 1 +// #define DEBUG_I2C 2 + + +// define print MACRO +#define PRINT_I2C(str) USB.print(F("[I2C] ")); USB.print(str); + + #define I2C_TIMEOUT 250 // timeout for I2C reads in milliseconds //I2c addresses @@ -40,10 +52,9 @@ #define I2C_ADDRESS_AGR_DENDROMETER 0x16 #define I2C_ADDRESS_AGR_PT1000 0x16 #define I2C_ADDRESS_AGR_RADIATION 0x14 -#define I2C_ADDRESS_GASES_SOCKET_1A_1B 0x28 -#define I2C_ADDRESS_GASES_SOCKET_4 0x2A -#define I2C_ADDRESS_GASES_SOCKET_2A_2B 0x2C -#define I2C_ADDRESS_GASES_SOCKET_3_3B 0x2E +#define I2C_ADDRESS_GASES_DIGIPOT1 0x2C +#define I2C_ADDRESS_GASES_DIGIPOT2 0x28 +#define I2C_ADDRESS_GASES_DIGIPOT3 0x2E #define I2C_ADDRESS_SENS_CITIES_DUST 0X2A #define I2C_ADDRESS_CITIES_LD 0X28 #define I2C_ADDRESS_CITIES_AUDIO 0X2A @@ -57,9 +68,18 @@ #define I2C_ADDRESS_CITIES_CP 0X2C #define I2C_ADDRESS_GASPRO_BME280 0x77 #define I2C_ADDRESS_GASPRO_LMP91000 0x48 -#define I2C_ADDRESS_GASPRO_MCP3421 0x69 +#define I2C_ADDRESS_GASPRO_MCP3421_A1 0x69 +#define I2C_ADDRESS_GASPRO_MCP3421_A2 0x6A #define I2C_ADDRESS_GASPRO_E2PROM 0x50 #define I2C_ADDRESS_GASPRO_MCP4146 0x2A +#define I2C_ADDRESS_EEPROM 0x55 +#define I2C_ADDRESS_EEPROM_DEFAULT 0x50 +#define I2C_ADDRESS_TSL2561 0x39 +#define I2C_ADDRESS_MB7040_MB1202 0x70 +#define I2C_ADDRESS_GASES_SOCKET_1A_1B 0x28 +#define I2C_ADDRESS_GASES_SOCKET_4 0x2A +#define I2C_ADDRESS_GASES_SOCKET_2A_2B 0x2C +#define I2C_ADDRESS_GASES_SOCKET_3_3B 0x2E class TwoWire { @@ -87,8 +107,14 @@ class TwoWire public: TwoWire(); - uint8_t I2C_ON; + //! Variable : indicates when I2C bus is ON (1) or OFF (0) + uint8_t isON; + //! Variable : indicates when Sensor Board is being powered on + /*! true: ON; false: OFF + */ + bool isBoard; + void begin(); void begin(uint8_t); void begin(int); @@ -106,11 +132,7 @@ class TwoWire void onReceive( void (*)(int) ); void onRequest( void (*)(void) ); void close(); - - //! Variable : indicates when Sensor Board is being powered on - /*! true: ON; false: OFF - */ - bool isBoard; + void secureBegin(); void secureEnd(); @@ -122,10 +144,14 @@ class TwoWire \param uint8_t regAddr: I2C register \param uint8_t data: data to send \param uint8_t pos: position of the bit to write [7|6|5|4|3|2|1|0] - \return 1 if OK - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ - int8_t writeBit(uint8_t devAddr, uint8_t regAddr, bool data, uint8_t pos); + int8_t writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_t pos); //! This function writes some bits via I2C /*! @@ -134,10 +160,28 @@ class TwoWire \param uint8_t data: data to send \param uint8_t pos: first position of the bits to write starting by the LSb [7|6|5|4|3|2|1|0] \param uint8_t length: number of bits to write - \return 1 if OK - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ int8_t writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t data, uint8_t pos, uint8_t length); + + //! This function writes byte via I2C + /*! + \param uint8_t devAddr: I2C address of the device + \param uint8_t regAddr: I2C register + \param uint8_t data: data to send + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout + */ + int8_t writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data); //! This function writes bytes via I2C /*! @@ -145,10 +189,14 @@ class TwoWire \param uint8_t regAddr: I2C register \param uint8_t *data: data to send \param uint8_t length: number of bytes to write - \return 1 if OK - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ - void writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length); + int8_t writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length); //! This function reads a bit via I2C /*! @@ -156,8 +204,12 @@ class TwoWire \param uint8_t regAddr: I2C register \param uint8_t *data: buffer to store the data \param uint8_t pos: position of the bit to read [7|6|5|4|3|2|1|0] - \return Bytes read - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t pos); @@ -168,19 +220,41 @@ class TwoWire \param uint8_t data: buffer to store the data \param uint8_t pos: first position of the bits to read starting by the LSb [7|6|5|4|3|2|1|0] \param uint8_t length: number of bits to read - \return Bytes read - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t pos, uint8_t length); + //! This function reads a byte via I2C + /*! + \param uint8_t devAddr: I2C address of the device + \param uint8_t regAddr: I2C register + \param uint8_t data: buffer to store the data + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout + */ + int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data); + //! This function reads bytes via I2C /*! \param uint8_t devAddr: I2C address of the device \param uint8_t regAddr: I2C register \param uint8_t data: buffer to store the data \param uint8_t length: number of bytes to read - \return Bytes read - -1 if error + \return 0 if OK + 1 if length to long for buffer + 2 if address send, NACK received + 3 if data send, NACK received + 4 if other twi error (lost bus arbitration, bus error, ..) + 5 if timeout */ int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint8_t length); diff --git a/waspmote-api/binary.h b/waspmote-api/binary.h index 4ebbbea..3750c7e 100755 --- a/waspmote-api/binary.h +++ b/waspmote-api/binary.h @@ -12,6 +12,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 * */ diff --git a/waspmote-api/eeprom_utilities/aes132_comm.c b/waspmote-api/eeprom_utilities/aes132_comm.c new file mode 100644 index 0000000..d83a65d --- /dev/null +++ b/waspmote-api/eeprom_utilities/aes132_comm.c @@ -0,0 +1,465 @@ +// ---------------------------------------------------------------------------- +// ATMEL Crypto-Devices Software Support - Colorado Springs, CO - +// ---------------------------------------------------------------------------- +// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +// DISCLAIMED. IN NO EVENT SHALL ATMEL 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. +// ---------------------------------------------------------------------------- + +/** \file + * \brief This file contains implementations of interface independent functions + * for the AES132 device. + * \author Atmel Crypto Products + * \date June 08, 2015 + */ + +#include +#include + +#include "aes132_comm.h" + +/** \brief This function calculates a 16-bit CRC. + * \param[in] length number of bytes in data buffer + * \param[in] data pointer to data + * \param[out] crc pointer to calculated CRC (high byte at crc[0]) + */ +void aes132c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint8_t counter; + uint8_t crc_low = 0, crc_high = 0, crc_carry; + uint8_t poly_low = 0x05, poly_high = 0x80; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) { + for (shift_register = 0x80; shift_register > 0x00; shift_register >>= 1) { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_high >> 7; + + // Shift CRC to the left by 1. + crc_carry = crc_low >> 7; + crc_low <<= 1; + crc_high <<= 1; + crc_high |= crc_carry; + + if ((data_bit ^ crc_bit) != 0) { + crc_low ^= poly_low; + crc_high ^= poly_high; + } + } + } + crc[0] = crc_high; + crc[1] = crc_low; +} + + +/** \brief This function resets the command and response buffer address. + * \return status of the operation + */ +uint8_t aes132c_reset_io_address(void) +{ + return aes132p_write_memory_physical(0, AES132_RESET_ADDR, (void *) 0); +} + + +/** \brief This function resynchronizes communication with the device. + * \return status of the operation + */ +uint8_t aes132c_resync() +{ + uint8_t aes132_lib_return = aes132p_resync_physical(); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + return aes132_lib_return; + + return aes132c_reset_io_address(); +} + + +/** \brief This function reads the device status register. + * \param[out] device_status_register pointer to byte where the register value is stored + * \return status of the operation + */ +uint8_t aes132c_read_device_status_register(uint8_t *device_status_register) +{ + uint8_t aes132_lib_return; + uint8_t n_retries = AES132_RETRY_COUNT_ERROR; + + do { + aes132_lib_return = aes132p_read_memory_physical(1, AES132_STATUS_ADDR, device_status_register); + } while ((aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) && (--n_retries > 0)); + + return aes132_lib_return; +} + + +/** \brief This function waits until a bit in the device status register is set or reset. + * Reading this register will wake up the device. + * \param[in] mask contains bit pattern to wait for + * \param[in] is_set specifies whether to wait until bit is set (#AES132_BIT_SET) or reset (#AES132_BIT_SET) + * \param[in] n_retries 16-bit number that indicates the number of retries before stopping to poll. + * \return status of the operation + */ +uint8_t aes132c_wait_for_status_register_bit(uint8_t mask, uint8_t is_set, uint16_t n_retries) +{ + uint8_t aes132_lib_return; + uint8_t device_status_register; + + do { + aes132_lib_return = aes132p_read_memory_physical(1, AES132_STATUS_ADDR, &device_status_register); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + // The device is busy. Continue polling until "n_retries" is depleted. + continue; + + if (is_set == AES132_BIT_SET) { + // Wait for the mask bit(s) being set. + if ((device_status_register & mask) == mask) + // Mask pattern has been found in device status register. Return success. + return aes132_lib_return; + + } else { + // Wait for the mask bit(s) being cleared. + if ((device_status_register & mask) == 0) + // Mask pattern has been found in device status register. Return success. + return aes132_lib_return; + } + + // Device is busy, or "mask" pattern does not yet match the device status register value. + // Continue polling. + } while (n_retries-- > 0); + + // The mask pattern was not found in the device status register after "n_retries" polling + // iterations. Return timeout error. + return AES132_FUNCTION_RETCODE_TIMEOUT; +} + + +/** \brief This function waits for the Write-In-Progress (WIP) bit in the device status register to be cleared. + * \return status of the operation + */ +uint8_t aes132c_wait_for_device_ready(void) +{ + return aes132c_wait_for_status_register_bit(AES132_WIP_BIT, AES132_BIT_CLEARED, AES132_RETRY_COUNT_DEVICE_READY); +} + + +/** \brief This function waits for the Response-Ready (RRDY) bit in the device status register to be set. + * \ return status of the operation + */ +uint8_t aes132c_wait_for_response_ready(void) +{ + return aes132c_wait_for_status_register_bit(AES132_RESPONSE_READY_BIT, AES132_BIT_SET, AES132_RETRY_COUNT_RESPONSE_READY); +} + + +/** \brief This function sends a Sleep command to the device. + * \param[in] standby mode (0: sleep, non-zero: standby) + * \return status of the operation + */ +uint8_t aes132c_send_sleep_command(uint8_t standby) +{ + // command buffer fields: + // + const uint8_t command_sleep[] = {AES132_COMMAND_SIZE_MIN, 0x11, AES132_COMMAND_MODE_SLEEP, 0, 0, 0, 0, 0x71, 0x81}; + const uint8_t command_standby[] = {AES132_COMMAND_SIZE_MIN, 0x11, AES132_COMMAND_MODE_STANDBY, 0, 0, 0, 0, 0xEF, 0x82}; + + // Disable reading the device status register after sending the command and disable appending the CRC. + const uint8_t options = (AES132_OPTION_NO_APPEND_CRC | AES132_OPTION_NO_STATUS_READ); + + // We reset the IO buffer address as a precaution. + // Since we cannot read the device status register after sending the Sleep command + // without waking up the device again, we cannot know whether the command failed. + uint8_t aes132_lib_return = aes132c_reset_io_address(); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + return aes132_lib_return; + + if (standby == AES132_COMMAND_MODE_SLEEP) + return aes132c_send_command((uint8_t *) command_sleep, options); + + return aes132c_send_command((uint8_t *) command_standby, options); +} + + +/** \brief This function wakes up a device. + * + * It takes about 1.5 ms for the device to wake up when in Sleep mode, and + * about 0.3 ms when in Standby mode. + * \return status of the operation + */ +uint8_t aes132c_wakeup(void) +{ + return aes132c_wait_for_device_ready(); +} + + +/** \brief This function puts a device into Sleep mode. + * \return status of the operation + * */ +uint8_t aes132c_sleep(void) +{ + return aes132c_send_sleep_command(AES132_COMMAND_MODE_SLEEP); +} + + +/** \brief This function puts a device into Standby mode. + * \return status of the operation + * */ +uint8_t aes132c_standby(void) +{ + return aes132c_send_sleep_command(AES132_COMMAND_MODE_STANDBY); +} + + +/** \brief This function writes to or reads from memory with retries. + * \param[in] count number of bytes to send + * \param[in] word_address word address + * \param[in, out] data pointer to tx or rx data + * \param[in] read flag indicating whether to read (#AES132_READ) or write (#AES132_WRITE) + * \return status of the operation or response return code + * */ +uint8_t aes132c_access_memory(uint8_t count, uint16_t word_address, uint8_t *data, uint8_t read) +{ + uint8_t aes132_lib_return; + + // inner while loop + uint8_t n_retries_memory_access; + + // outer while loop that resynchronizes communication if inner while loop got exhausted / timed out + uint8_t n_retries_resync = AES132_RETRY_COUNT_RESYNC; + + // used to hold the return code after writing to memory (word address < AES132_IO_ADDR) + uint8_t response_buffer[AES132_RESPONSE_SIZE_MIN]; + + do { + n_retries_memory_access = AES132_RETRY_COUNT_ERROR; + + do { + aes132_lib_return = aes132c_wait_for_device_ready(); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + // We lost communication. Re-synchronize. + break; + + if (read == 0) { + // Write to the device. + aes132_lib_return = aes132p_write_memory_physical(count, word_address, data); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + // Communication failed. Retry. + continue; + + // Communication succeeded. + if (word_address >= AES132_IO_ADDR) + // Return success and do not read response buffer if we wrote to the I/O buffer + // or to the address used to reset the I/O buffer index. + return aes132_lib_return; + + // Read response buffer when writing to device memory to check for write success. + aes132c_wait_for_response_ready(); + + aes132_lib_return = aes132c_receive_response(sizeof(response_buffer), response_buffer); + if (aes132_lib_return == AES132_FUNCTION_RETCODE_SUCCESS) + // Reading the return code from the I/O buffer succeeded. Return the code byte. + return response_buffer[AES132_RESPONSE_INDEX_RETURN_CODE]; + else + // Reading the return code from the I/O buffer failed. Return the error code that + // aes132c_receive_response returned. + return aes132_lib_return; + } + else { + // Read from the device. + aes132_lib_return = aes132p_read_memory_physical(count, word_address, data); + if (aes132_lib_return == AES132_FUNCTION_RETCODE_SUCCESS) + return aes132_lib_return; + } + // Accessing the device failed. Retry until "n_retries_memory_access" is depleted. + } while (--n_retries_memory_access > 0); + + // We failed to communicate with the device even after retrying. + if (--n_retries_resync == 0) + // We failed to communicate with the device even after re-synchronizing. Return. + return aes132_lib_return; + + // Re-synchronize communication. + // Do not override return value from previous call to communication function. + (void) aes132c_resync(); + + // Communication failed. Retry accessing device after having re-synchronized communication. + } while (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS); + + return aes132_lib_return; +} + + +/** \brief This function writes a command into the I/O buffer of the device. + * + * The fields of the command buffer are described below:\n + * + * \n + * The "count" field and size of the command buffer has to include the + * two CRC bytes independent from the #AES132_OPTION_NO_APPEND_CRC flag in the + * options parameter.\n + * The function retries sending the command if the device indicates a CRC error. + * \param[in] command pointer to command buffer + * \param[in] options flags for communication behavior + * \return status of the operation + */ +uint8_t aes132c_send_command(uint8_t *command, uint8_t options) +{ + uint8_t aes132_lib_return; + uint8_t n_retries = AES132_RETRY_COUNT_ERROR; + uint8_t device_status_register; + uint8_t count = command[AES132_COMMAND_INDEX_COUNT]; + + if ((options & AES132_OPTION_NO_APPEND_CRC) == 0) + // Append two-byte CRC to command. + aes132c_calculate_crc(count - AES132_CRC_SIZE, command, &command[count - AES132_CRC_SIZE]); + + do { + aes132_lib_return = aes132c_access_memory(count, AES132_IO_ADDR, command, AES132_WRITE); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + // Writing to the I/O buffer failed. Retry. + continue; + + if ((options & AES132_OPTION_NO_STATUS_READ) != 0) + // We don't read device status register when sending a Sleep command. + return aes132_lib_return; + + // Try to read the device status register. If it fails with an I2C nack of the I2C write address, + // we know that the device is busy. + aes132_lib_return = aes132c_read_device_status_register(&device_status_register); + //aes132_lib_return = aes132p_read_memory_physical(1, AES132_STATUS_ADDR, &device_status_register); + if (aes132_lib_return == AES132_FUNCTION_RETCODE_SUCCESS) { + // We were able to read the device status register. Check the CRC bit. + if ((device_status_register & AES132_CRC_ERROR_BIT) != 0) + // The device has calculated a not-matching CRC, which indicates a flawed communication. + // Retry sending the command. + aes132_lib_return = AES132_FUNCTION_RETCODE_BAD_CRC_TX; + } + else if (aes132_lib_return == AES132_FUNCTION_RETCODE_COMM_FAIL){ + // This code block applies to I2C only. Receiving a nack to a I2C address write + // indicates that the device is busy executing the command. We therefore return success. + return AES132_FUNCTION_RETCODE_SUCCESS; + + // In case of read-device-status-register failure, we do not send the command again but only + // re-synchronize, because we do not want certain commands being repeated, e.g. the Counter command. + }else { + // Do not override the return value from the call to aes132p_read_memory_physical. + (void) aes132c_resync(); + return aes132_lib_return; + } + + // Retry sending the command if an error occurred sending the command, or the device status register + // indicates a CRC error after having sent the command. + } while ((aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) && (--n_retries > 0)); + + // We did not succeed sending a command. Return the error from aes132p_read_memory_physical or + // AES132_FUNCTION_RETCODE_BAD_CRC_TX. + return aes132_lib_return; +} + + +/** \brief This function reads a response from the I/O buffer of the device. + * \param[in] size number of bytes to retrieve (<= response buffer size allocated by caller) + * \param[out] response pointer to retrieved response + * \return status of the operation + */ +uint8_t aes132c_receive_response(uint8_t size, uint8_t *response) +{ + uint8_t aes132_lib_return; + uint8_t n_retries = AES132_RETRY_COUNT_ERROR; + uint8_t crc[AES132_CRC_SIZE]; + uint8_t crc_index; + uint8_t count_byte; + + do { + aes132_lib_return = aes132c_wait_for_response_ready(); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) { + // Waiting for the Response-Ready bit timed out. We might have lost communication. + // Re-synchronize and retry. + // Do not override the return value from the call to aes132c_wait_for_response_ready. + (void) aes132c_resync(); + continue; + } + + // Read count byte from response buffer. + aes132_lib_return = aes132p_read_memory_physical(1, AES132_IO_ADDR, &response[AES132_COMMAND_INDEX_COUNT]); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) { + // Reading the count byte failed. We might have lost communication. + // Re-synchronize and retry. + // Do not override the return value from the call to aes132p_read_memory_physical. + (void) aes132c_resync(); + continue; + } + + count_byte = response[AES132_RESPONSE_INDEX_COUNT]; + if (count_byte > size) { + // The buffer provided by the caller is not big enough to store the entire response, + // or the count value got corrupted due to a bad communication channel. + // Re-synchronize and retry. + aes132_lib_return = AES132_FUNCTION_RETCODE_SIZE_TOO_SMALL; + // Do not override aes132_lib_return. + (void) aes132c_resync(); + continue; + } + + if ((count_byte < AES132_RESPONSE_SIZE_MIN) || (count_byte > AES132_RESPONSE_SIZE_MAX)) { + // A response has to be between #AES132_RESPONSE_SIZE_MIN and #AES132_RESPONSE_SIZE_MAX bytes long to be valid. + // Re-synchronize and retry. + aes132_lib_return = AES132_FUNCTION_RETCODE_COUNT_INVALID; + // Do not override aes132_lib_return. + (void) aes132c_resync(); + continue; + } + + // Read remainder of response. + aes132_lib_return = aes132p_read_memory_physical(count_byte - 1, AES132_IO_ADDR, &response[AES132_RESPONSE_INDEX_RETURN_CODE]); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) { + // Reading the remainder of the response failed. We might have lost communication. + // Re-synchronize and retry. + // Do not override the return value from the call to aes132p_read_memory_physical. + (void) aes132c_resync(); + continue; + } + + // Check CRC. + crc_index = count_byte - AES132_CRC_SIZE; + aes132c_calculate_crc(crc_index, response, crc); + if ((crc[0] == response[crc_index]) && (crc[1] == response[crc_index + 1])) + // We received a consistent response packet. Return the response return code. + return response[AES132_RESPONSE_INDEX_RETURN_CODE]; + + // Received and calculated CRC do not match. Retry reading the response buffer. + aes132_lib_return = AES132_FUNCTION_RETCODE_BAD_CRC_RX; + + // Do not override aes132_lib_return. + (void) aes132c_resync(); + + // Retry if communication failed, or CRC did not match. + } while ((aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) && (--n_retries > 0)); + + // Even after re-synchronizing and retrying, we could not receive a consistent response packet. + return aes132_lib_return; +} + + +/** \brief This function sends a command and reads its response. + * \param[in] command pointer to command buffer + * \param[in] size size of response buffer + * \param[out] response pointer to response buffer + * \param[in] options flags for communication behavior + * \return status of the operation + */ +uint8_t aes132c_send_and_receive(uint8_t *command, uint8_t size, uint8_t *response, uint8_t options) +{ + uint8_t aes132_lib_return = aes132c_send_command(command, options); + if (aes132_lib_return != AES132_FUNCTION_RETCODE_SUCCESS) + return aes132_lib_return; + + return aes132c_receive_response(size, response); +} + diff --git a/waspmote-api/eeprom_utilities/aes132_comm.h b/waspmote-api/eeprom_utilities/aes132_comm.h new file mode 100644 index 0000000..d942048 --- /dev/null +++ b/waspmote-api/eeprom_utilities/aes132_comm.h @@ -0,0 +1,270 @@ +// ---------------------------------------------------------------------------- +// ATMEL Crypto-Devices Software Support - Colorado Springs, CO - +// ---------------------------------------------------------------------------- +// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +// DISCLAIMED. IN NO EVENT SHALL ATMEL 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. +// ---------------------------------------------------------------------------- + +/** \file + * \brief Header file for aes132.c. + * \author Atmel Crypto Products + * \date June 08, 2015 + */ + +#ifndef AES132_H_ +#define AES132_H_ + +#include +#include "aes132_i2c.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +//~ #ifdef AES132_I2C +//~ # include "aes132_i2c.h" +//~ #elif AES132_SPI +//~ # include "aes132_spi.h" +//~ #else +//~ # error You have to define either AES132_I2C or AES132_SPI. +//~ #endif + + +/** \brief These enumerations are used as arguments + * when calling aes132m_access_memory(). */ +enum aes132_read_write_flag { + AES132_WRITE = (uint8_t) 0, //!< write flag + AES132_READ = (uint8_t) 1 //!< read flag +}; + + +/** \brief These enumerations are used as arguments + * when calling aes132c_wait_for_status_register_bit(). */ +enum aes132_bit_set_flag { + AES132_BIT_CLEARED = (uint8_t) 0, //!< bit cleared flag + AES132_BIT_SET = (uint8_t) 1 //!< bit set flag +}; + +// ------------------------ timing definitions ----------------------------------- + +//! Poll this many ms for the device being ready for access. +#define AES132_DEVICE_READY_TIMEOUT (100) + +/** \brief Poll this many ms for the response buffer being ready for reading. + * + * When adjusting this number, consider the command execution delays used. + * As these delays lie closer to or farther from the minimum command execution + * delays, this number has to be made bigger or smaller accordingly. With other + * words: The earlier we start polling after sending a command, + * the longer we have to make the wait-for-response-ready time-out. + */ +#define AES132_RESPONSE_READY_TIMEOUT (145) // Biggest response timeout is the one for the TempSense command (in ms). + + +// ----------------------- definitions for retry counts ----------------------------- + +//! number of retries for sending a command, receiving a response, and accessing memory +#define AES132_RETRY_COUNT_ERROR ((uint8_t) 2) + +//! number of re-synchronization retries +#define AES132_RETRY_COUNT_RESYNC ((uint8_t) 2) + + +// ------------- definitions for packet sizes -------------------- + +//! size of CRC +#define AES132_CRC_SIZE ((uint8_t) 2) + +//! minimum command size +#define AES132_COMMAND_SIZE_MIN ((uint8_t) 9) + +//! maximum command size (KeyImport command) +#define AES132_COMMAND_SIZE_MAX ((uint8_t) 63) + +//! minimum response size (EncRead and Encrypt command) +#define AES132_RESPONSE_SIZE_MIN ((uint8_t) 4) + +//! maximum response size +#define AES132_RESPONSE_SIZE_MAX ((uint8_t) 52) + +//! maximum number of bytes to write to or read from memory +#define AES132_MEM_ACCESS_MAX ((uint8_t) 32) + + +// ------------- definitions for device word addresses -------------------- + +//! word address of command / response buffer +#define AES132_IO_ADDR ((uint16_t) 0xFE00) + +//! Write to this word address to reset the index of the command / response buffer. +#define AES132_RESET_ADDR ((uint16_t) 0xFFE0) + +//! word address of device status register +#define AES132_STATUS_ADDR ((uint16_t) 0xFFF0) + + +// ------------- definitions for device status register bits -------------------- + +//! bit position of the Write-In-Progress bit (WIP) in the device status register +#define AES132_WIP_BIT ((uint8_t) 0x01) + +//! bit position of the Write-Enabled bit in the device status register (SPI only) +#define AES132_WEN_BIT ((uint8_t) 0x02) + +//! bit position of the power state bit in the device status register +#define AES132_WAKE_BIT ((uint8_t) 0x04) + +//! bit position of reserved bit 3 in the device status register +#define AES132_RESERVED3_BIT ((uint8_t) 0x08) + +//! bit position of the CRC error bit in the device status register +#define AES132_CRC_ERROR_BIT ((uint8_t) 0x10) + +//! bit position of reserved bit 5 in the device status register +#define AES132_RESERVED5_BIT ((uint8_t) 0x20) + +//! bit position of the CRC error bit in the device status register +#define AES132_RESPONSE_READY_BIT ((uint8_t) 0x40) + +//! bit position of bit in the device status register that indicates error +#define AES132_DEVICE_ERROR_BIT ((uint8_t) 0x80) + + +// --- definitions for device return codes (byte at index 1 of device response buffer --- + +//! no error in executing a command and receiving a response, or writing data to memory +#define AES132_DEVICE_RETCODE_SUCCESS ((uint8_t) 0x00) + +//! error when crossing a page or key boundary for a Write, BlockRead or EncRead +#define AES132_DEVICE_RETCODE_BOUNDARY_ERROR ((uint8_t) 0x02) + +//! Access to the specified User Zone is not permitted due to the current configuration or internal state. +#define AES132_DEVICE_RETCODE_RW_CONFIG ((uint8_t) 0x04) + +//! Address is not implemented, or address is illegal for this command, or attempted to write locked memory. +#define AES132_DEVICE_RETCODE_BAD_ADDR ((uint8_t) 0x08) + +//! Counter limit reached, or count usage error, or restricted key error. +#define AES132_DEVICE_RETCODE_COUNT_ERROR ((uint8_t) 0x10) + +//! no nonce available, or nonce invalid, or nonce does not include a random source, or MacCount limit has been reached +#define AES132_DEVICE_RETCODE_NONCE_ERROR ((uint8_t) 0x20) + +//! Authorization MAC input is missing, or MAC compare failed. +#define AES132_DEVICE_RETCODE_MAC_ERROR ((uint8_t) 0x40) + +//! bad opcode, bad mode, bad parameter, invalid length, or other encoding failure +#define AES132_DEVICE_RETCODE_PARSE_ERROR ((uint8_t) 0x50) + +//! EEPROM post-write automatic data verification failed due to data mismatch. +#define AES132_DEVICE_RETCODE_DATA_MISMATCH ((uint8_t) 0x60) + +//! Lock command contained bad checksum or bad MAC. +#define AES132_DEVICE_RETCODE_LOCK_ERROR ((uint8_t) 0x70) + +/** \brief Key is not permitted to be used for this operation, + * or wrong key was used for operation, + * or prior authentication has not been performed, + * or other authentication error, + * or other key error has occurred. + */ +#define AES132_DEVICE_RETCODE_KEY_ERROR ((uint8_t) 0x80) + +//! temperature sensor timeout error +#define AES132_DEVICE_RETCODE_TEMP_SENSE_ERROR ((uint8_t) 0x90) + + +// ------------- definitions for option flags used when sending a command -------- + +//! default flags for option parameter +#define AES132_OPTION_DEFAULT ((uint8_t) 0x00) + +/** \brief flag for option parameter that indicates whether or not to + * calculate and append a CRC. + */ +#define AES132_OPTION_NO_APPEND_CRC ((uint8_t) 0x01) + +/** \brief flag for option parameter that indicates whether or not to + * read the device status register after sending a command. + */ +#define AES132_OPTION_NO_STATUS_READ ((uint8_t) 0x02) + + +// ----- definitions for byte indexes of command buffer -------- + +//! count at index 0 (1 byte) +#define AES132_COMMAND_INDEX_COUNT (0) + +//! op-code at index 1 (1 byte) +#define AES132_COMMAND_INDEX_OPCODE (1) + +//! mode at index 2 (1 byte) +#define AES132_COMMAND_INDEX_MODE (2) + +//! msb of param1 (2 bytes) at index 3 +#define AES132_COMMAND_INDEX_PARAM1_MSB (3) + +//! lsb of param1 (2 bytes) at index 4 +#define AES132_COMMAND_INDEX_PARAM1_LSB (4) + +//! msb of param2 (2 bytes) at index 5 +#define AES132_COMMAND_INDEX_PARAM2_MSB (5) + +//! msb of param2 (2 bytes) at index 5 +#define AES132_COMMAND_INDEX_PARAM2_LSB (6) + + +// ----- definitions for Standby and Sleep modes -------- + +//! value of mode byte for the Sleep command to put device into Sleep mode +#define AES132_COMMAND_MODE_SLEEP ((uint8_t) 0x00) + +//! value of mode byte for the Sleep command to put device into Standby mode +#define AES132_COMMAND_MODE_STANDBY ((uint8_t) 0x40) + + +// ----- definitions for byte indexes of response buffer -------- + +//! count at index 0 (1 byte) +#define AES132_RESPONSE_INDEX_COUNT ((uint8_t) 0) + +//! response return code at index 1 (1 byte) +#define AES132_RESPONSE_INDEX_RETURN_CODE ((uint8_t) 1) + +//! Response data start at index 2 (1 or more bytes). +#define AES132_RESPONSE_INDEX_DATA ((uint8_t) 2) + + + + +uint8_t aes132c_access_memory(uint8_t count, uint16_t word_address, uint8_t *data, uint8_t read); +uint8_t aes132c_read_device_status_register(uint8_t *deviceStatus); +uint8_t aes132c_send_command(uint8_t *command, uint8_t options); +uint8_t aes132c_receive_response(uint8_t count, uint8_t *response); +uint8_t aes132c_send_and_receive(uint8_t *command, uint8_t size, uint8_t *response, uint8_t options); +uint8_t aes132c_wakeup(void); +uint8_t aes132c_sleep(void); +uint8_t aes132c_standby(void); +uint8_t aes132c_resync(void); +uint8_t aes132c_wait_for_status_register_bit(uint8_t mask, uint8_t is_set, uint16_t n_retries); +uint8_t aes132c_wait_for_response_ready(void); +uint8_t aes132c_wait_for_device_ready(void); +uint8_t aes132c_send_sleep_command(uint8_t standby); +uint8_t aes132c_reset_io_address(void); +void aes132c_calculate_crc(uint8_t count, uint8_t *data, uint8_t *crc); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/waspmote-api/eeprom_utilities/aes132_i2c.h b/waspmote-api/eeprom_utilities/aes132_i2c.h new file mode 100644 index 0000000..09422eb --- /dev/null +++ b/waspmote-api/eeprom_utilities/aes132_i2c.h @@ -0,0 +1,142 @@ +// ---------------------------------------------------------------------------- +// ATMEL Crypto-Devices Software Support - Colorado Springs, CO - +// ---------------------------------------------------------------------------- +// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +// DISCLAIMED. IN NO EVENT SHALL ATMEL 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. +// ---------------------------------------------------------------------------- + +/** \file + * \brief This file contains definitions of the I2C layer of the AES132 library. + * \author Atmel Crypto Products + * \date June 16, 2011 + */ + +#ifndef AES132_I2C_H +# define AES132_I2C_H + +#include + + +// ---------------------------------------------------------------------------------- +// ------------------------ definitions for timeout counters ------------------------ +// ----------- Adjust the values for the timeout counters to your hardware. --------- +// ---------------------------------------------------------------------------------- + +/** \brief Status byte polling time was measured. + * + * Undefine this if you want to use estimated values (see below). + */ +#define POLL_TIME_MEASURED + +#ifdef POLL_TIME_MEASURED +/** \brief time for polling a bit in the device status register in us (measured) + * + * With an oscilloscope or logic analyzer, measure the time it takes for one + * loop iteration in aes132c_wait_for_status_bit() when acknowledged + * and when not acknowledged, and enter it here. + */ +# define AES132_STATUS_REG_POLL_TIME_ACK (158) +# define AES132_STATUS_REG_POLL_TIME_NACK (41) + +#else + +/** \brief time in us per byte (number of clocks per byte * number of bytes / clock frequency) + * + * If you cannot measure the polling time for a status bit in the device status register, + * you can derive it by establishing three separate values, + * #AES132_STATUS_REG_POLL_TIME_COMM_NACK, #AES132_STATUS_REG_POLL_TIME_OVERHEAD, + * and #AES132_STATUS_REG_POLL_TIME_LOOP. + * + * Time to poll the device status register:\n + * t_poll = t_comm + t_comm_overhead + t_loop,\n + * where\n + * t_comm(when I2C address gets acknowledged) + * = (5 bytes * 9 clocks / i2c_clock + 2 * t_start + t_stop)\n + * t_comm_overhead = 2 * t_execute_start_function + 5 * t_i2c_register_access + t_execute_stop_function\n + * t_loop = t_loop(aes132c_read_device_status_register())\n + * + * Example for AVR eight-bit CPU running at 16 MHz and I2C clocked at 400 kHz:\n + * t_comm = (5 bytes * 9 clocks / 400000 Hz + 2 * 2.2 us + 0.8 us) = 117.7 us\n + * t_comm_overhead = 27.3 us\n + * t_loop = 13.0 us\n + * t_poll = 117.7 us + 27.3 us + 13.0 us = 158.0 us + */ +# define AES132_STATUS_REG_POLL_TIME_COMM ( 29) + +/** \brief time in us it takes to access the interface peripheral + * + * times for calling twi_send_start and twi_send_stop + */ +# define AES132_STATUS_REG_POLL_TIME_OVERHEAD ( 19) + +//! time in us the polling loop takes to decrement the counter and branch +# define AES132_STATUS_REG_POLL_TIME_LOOP ( 13) + +/** \brief time in us for polling a bit in the device status register when acked (calculated) + + * When the I2C address is acknowledged we need to transmit a total of five bytes + * (I2C write address, two bytes of status byte address, I2C read address, status byte) + */ +# define AES132_STATUS_REG_POLL_TIME_ACK (5 * AES132_STATUS_REG_POLL_TIME_COMM + \ + AES132_STATUS_REG_POLL_TIME_OVERHEAD + AES132_STATUS_REG_POLL_TIME_LOOP) + +//! time in us for polling a bit in the device status register when nacked (calculated) +# define AES132_STATUS_REG_POLL_TIME_NACK (AES132_STATUS_REG_POLL_TIME_COMM + \ + AES132_STATUS_REG_POLL_TIME_OVERHEAD + AES132_STATUS_REG_POLL_TIME_LOOP) +#endif + +//! timeout loop iterations per ms derived from the times it takes to communicate and loop when acknowledged +#define AES132_ITERATIONS_PER_MS_ACK (1000 / AES132_STATUS_REG_POLL_TIME_ACK) + +//! timeout loop iterations per ms derived from the times it takes to communicate and loop when not acknowledged +#define AES132_ITERATIONS_PER_MS_NACK (1000 / AES132_STATUS_REG_POLL_TIME_NACK) + +//! Poll this many times for the device being ready for access. +#define AES132_RETRY_COUNT_DEVICE_READY ((uint16_t) (AES132_DEVICE_READY_TIMEOUT * AES132_ITERATIONS_PER_MS_NACK)) + +/** \brief Poll this many times for the response buffer being ready for reading. + * + * The device "nacks" the I2C address while parsing the command during the first few (average of two) milliseconds + * (second term in formula below). Give some slack by doubling the minimum timeout. + */ +#define AES132_RETRY_COUNT_RESPONSE_READY ((uint16_t) (AES132_RESPONSE_READY_TIMEOUT * AES132_ITERATIONS_PER_MS_ACK * 2 \ + + 2 * AES132_ITERATIONS_PER_MS_NACK)) + +// ---------------------------------------------------------------------------------- +// --------------- end of definitions for timeout counter values -------------------- +// ---------------------------------------------------------------------------------- + + +// ------------ definitions for library return codes ---------------------------- + +#define AES132_FUNCTION_RETCODE_ADDRESS_WRITE_NACK ((uint8_t) 0xA0) //!< I2C nack when sending a I2C address for writing +#define AES132_FUNCTION_RETCODE_ADDRESS_READ_NACK ((uint8_t) 0xA1) //!< I2C nack when sending a I2C address for reading +#define AES132_FUNCTION_RETCODE_SIZE_TOO_SMALL ((uint8_t) 0xA2) //!< Count value in response was bigger than buffer. + +// The codes below are the same as in the SHA204 library. +#define AES132_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Function succeeded. +#define AES132_FUNCTION_RETCODE_BAD_CRC_TX ((uint8_t) 0xD4) //!< Device status register bit 4 (CRC) is set. +#define AES132_FUNCTION_RETCODE_NOT_IMPLEMENTED ((uint8_t) 0xE0) //!< interface function not implemented +#define AES132_FUNCTION_RETCODE_DEVICE_SELECT_FAIL ((uint8_t) 0xE3) //!< device index out of bounds +#define AES132_FUNCTION_RETCODE_COUNT_INVALID ((uint8_t) 0xE4) //!< count byte in response is out of range +#define AES132_FUNCTION_RETCODE_BAD_CRC_RX ((uint8_t) 0xE5) //!< incorrect CRC received +#define AES132_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xE7) //!< Function timed out while waiting for response. +#define AES132_FUNCTION_RETCODE_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. + + +void aes132p_enable_interface(void); +void aes132p_disable_interface(void); +uint8_t aes132p_select_device(uint8_t device_id); +uint8_t aes132p_read_memory_physical(uint8_t size, uint16_t word_address, uint8_t *data); +uint8_t aes132p_write_memory_physical(uint8_t count, uint16_t word_address, uint8_t *data); +uint8_t aes132p_resync_physical(void); + +#endif diff --git a/waspmote-api/main.cpp b/waspmote-api/main.cpp index 0eeb64b..4ec2fc3 100755 --- a/waspmote-api/main.cpp +++ b/waspmote-api/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. + * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 2.3 - * Design: David Gascón + * Version: 3.0 + * Design: David Gascon * Implementation: Yuri Carmona */ @@ -24,22 +24,42 @@ #include //define global variable for Waspmote serial id -volatile unsigned long _serial_id; +volatile uint8_t _serial_id[8]; + +//define global variable for Waspmote bootloader version +volatile uint8_t _boot_version; int main(void) { init(); + // switch on main power supply + pinMode(POWER_3V3, OUTPUT); + digitalWrite(POWER_3V3,HIGH); + + // get bootloader version + _boot_version = Utils.getBootVersion(); + // proceed depending on the bootloader version - if( Utils.getBootVersion() >= 'E') + if (_boot_version >= 'E') { pinMode(RTC_SLEEP, OUTPUT); digitalWrite(RTC_SLEEP, HIGH); } + uint8_t rtc_hibernate_triggered = digitalRead(RTC_INT_PIN_MON); + + // proceed depending on the bootloader version + if (_boot_version >= 'G') + { + RTC.ON(); + RTC.disableSQW(); + RTC.OFF(); + } + // Check OTA EEPROM flag and mark flag in Waspmote // Control Register if corresponds to - if( Utils.readEEPROM(0x01) == 0x01 ) + if (Utils.readEEPROM(0x01) == 0x01) { // set register flag WaspRegister |= REG_OTA; @@ -50,8 +70,8 @@ int main(void) // validate Hibernate interruption when both RTC interruption // signal and hibernate EEPROM flag are active - if( digitalRead(RTC_INT_PIN_MON) && (Utils.readEEPROM(HIB_ADDR)==HIB_VALUE) ) - { + if (rtc_hibernate_triggered && (Utils.readEEPROM(HIB_ADDR)==HIB_VALUE)) + { // get RTC time and last almarm setting RTC.ON(); RTC.getAlarm1(); @@ -64,18 +84,18 @@ int main(void) int total_diff = RTC.second - RTC.second_alarm1; // check seconds zero crossing - if( RTC.minute - RTC.minute_alarm1 > 0 ) + if (RTC.minute - RTC.minute_alarm1 > 0) { total_diff = total_diff + (RTC.minute - RTC.minute_alarm1)*60; } // check minute zero crossing - if( RTC.minute - RTC.minute_alarm1 < 0 ) + if (RTC.minute - RTC.minute_alarm1 < 0) { total_diff = total_diff + (RTC.minute-RTC.minute_alarm1+60)*60; } - if( (total_diff < 3) && (total_diff >= 0) ) + if ((total_diff < 3) && (total_diff >= 0)) { intFlag |= HIB_INT; } @@ -87,14 +107,16 @@ int main(void) RTC.disableAlarm2(); RTC.OFF(); + // Improve consumption if there is an XBee in SOCKET0 and + // also a SPI sensor board is connected + pinMode(SOCKET0_SS, INPUT); + delay(3); - if( WaspRegister & REG_SX ) + if (WaspRegister & REG_SX) { delay(3); // Powering the module - pinMode(XBEE_PW,OUTPUT); - delay(3); - digitalWrite(XBEE_PW,HIGH); + PWR.powerSocket(SOCKET0, HIGH); delay(3); //Configure the MISO, MOSI, CS, SPCR. SPI.begin(); @@ -115,17 +137,31 @@ int main(void) SPI.setSPISlave(ALL_DESELECTED); delay(3); // Powering the module - pinMode(XBEE_PW,OUTPUT); - digitalWrite(XBEE_PW,LOW); + PWR.powerSocket(SOCKET0, LOW); delay(3); - } + } + delay(3); - delay(3); // get serial id - _serial_id = Utils.readSerialID(); + Utils.readSerialID(); // set random seed - srand(_serial_id); + unsigned int seed = 0; + seed += _serial_id[6] * 0x100; + seed += _serial_id[7]; + srand(seed); + + // check for XBee modules in SOCKET0 + //PWR.checkPeripherals(); + + // close UART + closeSerial(0); + + // switch off mux on uart0 + if (_boot_version >= 'G') + { + Utils.muxOFF0(); + } setup(); diff --git a/waspmote-api/pins_waspmote.c b/waspmote-api/pins_waspmote.c index 32f7e2a..647fd10 100755 --- a/waspmote-api/pins_waspmote.c +++ b/waspmote-api/pins_waspmote.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2005 David A. Mellis * Revised for Waspmote by D. Cuartielles & A. Bielsa, 2009 - * Revised for Waspmote by Libelium, 2014 + * Revised for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: David Gascón * Implementation: D.Mellis, D. Cuartielles, A. Bielsa, Y. Carmona */ @@ -132,8 +132,8 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PF , // PF 6 ** 19 ** ANA5 PF , // PF 7 ** 20 ** ANA6 PF , // PF 0 ** 21 ** BAT_MONITOR - PA , // PA 1 ** 22 ** XBEE_PW - PD , // PD 7 ** 23 ** XBEE SLEEP + PA , // PA 1 ** 22 ** SOCKET0_PW + PD , // PD 7 ** 23 ** MUX_PW (Waspmote v12) or MUX1_PW (v15) PE , // PE 5 ** 24 ** SENS_PW_5V PA , // PA 6 ** 25 ** BAT_MONITOR_PW PE , // PE 2 ** 26 ** SENS_PW_3v3 @@ -143,8 +143,8 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PB , // PB 1 ** 30 ** SD_SCK PB , // PB 2 ** 31 ** SD_MOSI PB , // PB 3 ** 32 ** SD_MISO - PB , // PB 4 ** 33 ** SERID_PW - PB , // PB 5 ** 34 ** SERID_IN + PB , // PB 4 ** 33 ** HIB_PIN + PB , // PB 5 ** 34 ** SOCKET0_SS PA , // PA 0 ** 35 ** GPS_PW PB , // PB 6 ** 36 ** GPS_RX PB , // PB 7 ** 37 ** GPS_TX @@ -153,14 +153,16 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD , // PD 0 ** 40 ** I2C_SCL PD , // PD 1 ** 41 ** I2C_SDA PC , // PC 3 ** 42 ** GPRS_PW - PD , // PD 2 ** 43 ** GPRS_RX - PD , // PD 3 ** 44 ** GPRS_TX - PA , // PA 7 ** 45 ** BOOT PIN - PC , // PC 2 ** 46 ** PWON - PD , // PD 4 ** 47 ** FREE PIN - PG , // PG 2 ** 48 ** RTC_PW + PD , // PD 2 ** 43 ** GPS/Socket1/Aux1/Aux2_RX + PD , // PD 3 ** 44 ** GPS/Socket1/Aux1/Aux2_TX + PA , // PA 7 ** 45 ** XBEE_MON + PC , // PC 2 ** 46 ** GPRS_PIN + PD , // PD 4 ** 47 ** XBEE_SLEEP + PG , // PG 2 ** 48 ** MUX0_PW (Waspmote v15) or RTC_PW (v12) PG , // PG 1 ** 49 ** RTC_SLEEP - PG , // PG 0 ** 50 ** LOW_BAT_MON + PG , // PG 0 ** 50 ** MAIN POWER_3V3 + PG , // PG 3 ** 51 ** CHG_IND (v15) + PG , // PG 4 ** 52 ** SPI_ON (v15) }; const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { @@ -187,8 +189,8 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { _BV( 6 ) , // PF 6 ** 19 ** ANA5 _BV( 7 ) , // PF 7 ** 20 ** ANA6 _BV( 0 ) , // PF 0 ** 21 ** BAT_MONITOR - _BV( 1 ) , // PA 1 ** 22 ** XBEE_PW - _BV( 7 ) , // PD 7 ** 23 ** XBEE SLEEP + _BV( 1 ) , // PA 1 ** 22 ** SOCKET0_PW + _BV( 7 ) , // PD 7 ** 23 ** MUX_PW (v12) or MUX1_PW (v15) _BV( 5 ) , // PE 5 ** 24 ** SENS_PW_5V _BV( 6 ) , // PA 6 ** 25 ** BAT_MONITOR_PW _BV( 2 ) , // PE 2 ** 26 ** SENS_PW_3v3 @@ -198,8 +200,8 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { _BV( 1 ) , // PB 1 ** 30 ** SD_SCK _BV( 2 ) , // PB 2 ** 31 ** SD_MOSI _BV( 3 ) , // PB 3 ** 32 ** SD_MISO - _BV( 4 ) , // PB 4 ** 33 ** SERID_PW - _BV( 5 ) , // PB 5 ** 34 ** SERID_IN + _BV( 4 ) , // PB 4 ** 33 ** HIB_PIN + _BV( 5 ) , // PB 5 ** 34 ** SOCKET0_SS _BV( 0 ) , // PA 0 ** 35 ** GPS_PW _BV( 6 ) , // PB 6 ** 36 ** GPS_RX _BV( 7 ) , // PB 7 ** 37 ** GPS_TX @@ -208,23 +210,25 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { _BV( 0 ) , // PD 0 ** 40 ** I2C_SCL _BV( 1 ) , // PD 1 ** 41 ** I2C_SDA _BV( 3 ) , // PC 3 ** 42 ** GPRS_PW - _BV( 2 ) , // PD 2 ** 43 ** GPRS_RX - _BV( 3 ) , // PD 3 ** 44 ** GPRS_TX - _BV( 7 ) , // PA 7 ** 45 ** BOOT PIN - _BV( 2 ) , // PC 2 ** 46 ** PWON - _BV( 4 ) , // PD 4 ** 47 ** FREE PIN - _BV( 2 ) , // PG 2 ** 48 ** RTC_PW + _BV( 2 ) , // PD 2 ** 43 ** GPS/Socket1/Aux1/Aux2_RX + _BV( 3 ) , // PD 3 ** 44 ** GPS/Socket1/Aux1/Aux2_TX + _BV( 7 ) , // PA 7 ** 45 ** XBEE_MON + _BV( 2 ) , // PC 2 ** 46 ** GPRS_PIN + _BV( 4 ) , // PD 4 ** 47 ** XBEE_SLEEP + _BV( 2 ) , // PG 2 ** 48 ** MUX0_PW (v15) or RTC_PW (v12) _BV( 1 ) , // PG 1 ** 49 ** RTC_SLEEP - _BV( 0 ) , // PG 0 ** 50 ** LOW_BAT_MON + _BV( 0 ) , // PG 0 ** 50 ** MAIN POWER_3V3 + _BV( 3 ) , // PG 3 ** 51 ** CHG_IND (v15) + _BV( 4 ) , // PG 4 ** 52 ** SPI_ON (v15) }; const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - // PORT PIN WASP API PIN DESCRIPTION + // PORT PIN WASP API PIN DESCRIPTION NOT_ON_TIMER , // PE 0 ** 0 ** USB_XBEE_RX NOT_ON_TIMER , // PE 1 ** 1 ** USB_XBEE_TX - TIMER3A , // PE 3 ** 2 ** DIGITAL1 - TIMER3B , // PE 4 ** 3 ** DIGITAL0 + TIMER3A , // PE 3 ** 2 ** DIGITAL1 + TIMER3B , // PE 4 ** 3 ** DIGITAL0 NOT_ON_TIMER , // PC 4 ** 4 ** DIGITAL7 NOT_ON_TIMER , // PC 5 ** 5 ** DIGITAL8 NOT_ON_TIMER , // PC 6 ** 6 ** DIGITAL6 @@ -243,8 +247,8 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER , // PF 6 ** 19 ** ANA5 NOT_ON_TIMER , // PF 7 ** 20 ** ANA6 NOT_ON_TIMER , // PF 0 ** 21 ** BAT_MONITOR - NOT_ON_TIMER , // PA 1 ** 22 ** XBEE_PW - NOT_ON_TIMER , // PD 7 ** 23 ** XBEE SLEEP + NOT_ON_TIMER , // PA 1 ** 22 ** SOCKET0_PW + NOT_ON_TIMER , // PD 7 ** 23 ** MUX_PW (v12) or MUX1_PW (v15) NOT_ON_TIMER , // PE 5 ** 24 ** SENS_PW_5V NOT_ON_TIMER , // PA 6 ** 25 ** BAT_MONITOR_PW NOT_ON_TIMER , // PE 2 ** 26 ** SENS_PW_3v3 @@ -254,8 +258,8 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER , // PB 1 ** 30 ** SD_SCK NOT_ON_TIMER , // PB 2 ** 31 ** SD_MOSI NOT_ON_TIMER , // PB 3 ** 32 ** SD_MISO - NOT_ON_TIMER , // PB 4 ** 33 ** SERID_PW - NOT_ON_TIMER , // PB 5 ** 34 ** SERID_IN + NOT_ON_TIMER , // PB 4 ** 33 ** HIB_PIN + NOT_ON_TIMER , // PB 5 ** 34 ** SOCKET0_SS NOT_ON_TIMER , // PA 0 ** 35 ** GPS_PW NOT_ON_TIMER , // PB 6 ** 36 ** GPS_RX NOT_ON_TIMER , // PB 7 ** 37 ** GPS_TX @@ -264,14 +268,16 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER , // PD 0 ** 40 ** I2C_SCL NOT_ON_TIMER , // PD 1 ** 41 ** I2C_SDA NOT_ON_TIMER , // PC 3 ** 42 ** GPRS_PW - NOT_ON_TIMER , // PD 2 ** 43 ** GPRS_RX - NOT_ON_TIMER , // PD 3 ** 44 ** GPRS_TX - NOT_ON_TIMER , // PA 7 ** 45 ** BOOT PIN - NOT_ON_TIMER , // PC 2 ** 46 ** PWON - NOT_ON_TIMER , // PD 4 ** 47 ** FREE PIN - NOT_ON_TIMER , // PG 2 ** 48 ** RTC_PW + NOT_ON_TIMER , // PD 2 ** 43 ** GPS/Socket1/Aux1/Aux2_RX + NOT_ON_TIMER , // PD 3 ** 44 ** GPS/Socket1/Aux1/Aux2_TX + NOT_ON_TIMER , // PA 7 ** 45 ** XBEE_MON + NOT_ON_TIMER , // PC 2 ** 46 ** GPRS_PIN + NOT_ON_TIMER , // PD 4 ** 47 ** XBEE_SLEEP + NOT_ON_TIMER , // PG 2 ** 48 ** MUX0_PW (v15) or RTC_PW (v12) NOT_ON_TIMER , // PG 1 ** 49 ** RTC_SLEEP - NOT_ON_TIMER , // PG 0 ** 50 ** LOW_BAT_MON + NOT_ON_TIMER , // PG 0 ** 50 ** MAIN POWER_3V3 + NOT_ON_TIMER , // PG 3 ** 51 ** CHG_IND (v15) + NOT_ON_TIMER , // PG 4 ** 52 ** SPI_ON (v15) }; diff --git a/waspmote-api/pins_waspmote.h b/waspmote-api/pins_waspmote.h index 7266d6b..d1ee14b 100755 --- a/waspmote-api/pins_waspmote.h +++ b/waspmote-api/pins_waspmote.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2005 David A. Mellis * Revised for Waspmote by D. Cuartielles & A. Bielsa, 2009 - * Revised for Waspmote by Libelium, 2014 + * Revised for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -16,9 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * Design: David Gascón - * Implementation: D.Mellis, D. Cuartielles, A. Bielsa, Y. Carmona + * Implementation: D.Mellis, D. Cuartielles, M. Yarza, Y. Carmona */ #ifndef Pins_Waspmote_h @@ -27,58 +27,62 @@ #include // GIVE NAMES TO THE WHOLE PINOUT FOR WASP -// DESCRIPTION WASP API PIN PORT PIN WASP API PIN DESCRIPTION -#define USB_XBEE_RX 0 // PE 0 ** 0 ** USB_XBEE_RX -#define USB_XBEE_TX 1 // PE 1 ** 1 ** USB_XBEE_TX -#define DIGITAL1 2 // PE 3 ** 2 ** DIGITAL1 -- PWM1 BEFORE -#define DIGITAL0 3 // PE 4 ** 3 ** DIGITAL0 -- PWM2 BEFORE -#define DIGITAL7 4 // PC 4 ** 4 ** DIGITAL7 -- DIG0 BEFORE -#define DIGITAL8 5 // PC 5 ** 5 ** DIGITAL8 -- DIG1 BEFORE -#define DIGITAL6 6 // PC 6 ** 6 ** DIGITAL6 -- DIG2 BEFORE -#define DIGITAL5 7 // PC 7 ** 7 ** DIGITAL5 -- DIG3 BEFORE -#define DIGITAL2 8 // PA 2 ** 8 ** DIGITAL2 -- DIG4 BEFORE -#define DIGITAL4 9 // PA 3 ** 9 ** DIGITAL4 -- DIG5 BEFORE -#define DIGITAL3 10 // PA 4 ** 10 ** DIGITAL3 -- DIG6 BEFORE +// DESCRIPTION PIN PORT PIN WASP API PIN DESCRIPTION +#define USB_XBEE_RX 0 // PE 0 ** 0 ** USB_XBEE_RX +#define USB_XBEE_TX 1 // PE 1 ** 1 ** USB_XBEE_TX +#define DIGITAL1 2 // PE 3 ** 2 ** DIGITAL1 -- PWM1 BEFORE +#define DIGITAL0 3 // PE 4 ** 3 ** DIGITAL0 -- PWM2 BEFORE +#define DIGITAL7 4 // PC 4 ** 4 ** DIGITAL7 -- DIG0 BEFORE +#define DIGITAL8 5 // PC 5 ** 5 ** DIGITAL8 -- DIG1 BEFORE +#define DIGITAL6 6 // PC 6 ** 6 ** DIGITAL6 -- DIG2 BEFORE +#define DIGITAL5 7 // PC 7 ** 7 ** DIGITAL5 -- DIG3 BEFORE +#define DIGITAL2 8 // PA 2 ** 8 ** DIGITAL2 -- DIG4 BEFORE +#define DIGITAL4 9 // PA 3 ** 9 ** DIGITAL4 -- DIG5 BEFORE +#define DIGITAL3 10 // PA 4 ** 10 ** DIGITAL3 -- DIG6 BEFORE #define MUX_USB_XBEE 11 // PD 5 ** 11 ** DIGITAL9 -- DIG7 BEFORE -#define LED0 12 // PD 6 ** 12 ** LED0 -#define LED1 13 // PC 1 ** 13 ** LED1 -#define ANA0 14 // PF 1 ** 14 ** ANA0 -#define ANA1 15 // PF 2 ** 15 ** ANA1 -#define ANA2 16 // PF 3 ** 16 ** ANA2 -#define ANA3 17 // PF 4 ** 17 ** ANA3 -#define ANA4 18 // PF 5 ** 18 ** ANA4 -#define ANA5 19 // PF 6 ** 19 ** ANA5 -#define ANA6 20 // PF 7 ** 20 ** ANA6 -#define BAT_MONITOR 21 // PF 0 ** 21 ** BAT_MONITOR -#define XBEE_PW 22 // PA 1 ** 22 ** XBEE_PW -#define MUX_PW 23 // PD 7 ** 23 ** MUX_PW -#define SENS_PW_5V 24 // PE 5 ** 24 ** SENS_PW_5V +#define LED0 12 // PD 6 ** 12 ** LED0 +#define LED1 13 // PC 1 ** 13 ** LED1 +#define ANA0 14 // PF 1 ** 14 ** ANA0 +#define ANA1 15 // PF 2 ** 15 ** ANA1 +#define ANA2 16 // PF 3 ** 16 ** ANA2 +#define ANA3 17 // PF 4 ** 17 ** ANA3 +#define ANA4 18 // PF 5 ** 18 ** ANA4 +#define ANA5 19 // PF 6 ** 19 ** ANA5 +#define ANA6 20 // PF 7 ** 20 ** ANA6 +#define BAT_MONITOR 21 // PF 0 ** 21 ** BAT_MONITOR +#define SOCKET0_PW 22 // PA 1 ** 22 ** SOCKET0_PW +#define MUX_PW 23 // PD 7 ** 23 ** MUX_PW (Waspmote v12) +#define MUX1_PW 23 // PD 7 ** 23 ** MUX1_PW (Waspmote v15) +#define SENS_PW_5V 24 // PE 5 ** 24 ** SENS_PW_5V #define BAT_MONITOR_PW 25 // PA 6 ** 25 ** BAT_MONITOR_PW -#define SENS_PW_3V3 26 // PE 2 ** 26 ** SENS_PW_3v3 -#define MEM_PW 27 // PA 5 ** 27 ** MEM_PW -#define SD_PRESENT 28 // PC 0 ** 28 ** SD_PRESENT -#define SD_SS 29 // PB 0 ** 29 ** SD_SS -#define SD_SCK 30 // PB 1 ** 30 ** SD_SCK -#define SD_MOSI 31 // PB 2 ** 31 ** SD_MOSI -#define SD_MISO 32 // PB 3 ** 32 ** SD_MISO -#define HIB_PIN 33 // PB 4 ** 33 ** SERID_PW -#define SOCKET0_SS 34 // PB 5 ** 34 ** SERID_IN -#define GPS_PW 35 // PA 0 ** 35 ** GPS_PW -#define MUX_0 36 // PB 6 ** 36 ** MUX_0 -#define MUX_1 37 // PB 7 ** 37 ** MUX_1 -#define RDY_ACC 38 // PE 6 ** 38 ** RDY_ACC -#define RST_RTC 39 // PE 7 ** 39 ** RST_RTC -#define I2C_SCL 40 // PD 0 ** 40 ** I2C_SCL -#define I2C_SDA 41 // PD 1 ** 41 ** I2C_SDA -#define GPRS_PW 42 // PC 3 ** 42 ** GPRS_PW -#define MUX_RX 43 // PD 2 ** 43 ** GPS/GPRS/SER1/SER2_RX -#define MUX_TX 44 // PD 3 ** 44 ** GPS/GPRS/SER1/SER2_TX -#define XBEE_MON 45 // PA 7 ** 45 ** XBEE_MON -#define GPRS_PIN 46 // PC 2 ** 46 ** GPRS_PIN -#define XBEE_SLEEP 47 // PD 4 ** 47 ** XBEE_SLEEP -#define RTC_PW 48 // PG 2 ** 48 ** RTC_PW -#define RTC_SLEEP 49 // PG 1 *** 49 ** RTC_SLEEP -#define LOW_BAT_MON 50 // PG 0 ** 50 ** LOW_BAT_MON +#define SENS_PW_3V3 26 // PE 2 ** 26 ** SENS_PW_3v3 +#define MEM_PW 27 // PA 5 ** 27 ** MEM_PW +#define SD_PRESENT 28 // PC 0 ** 28 ** SD_PRESENT +#define SD_SS 29 // PB 0 ** 29 ** SD_SS +#define SD_SCK 30 // PB 1 ** 30 ** SD_SCK +#define SD_MOSI 31 // PB 2 ** 31 ** SD_MOSI +#define SD_MISO 32 // PB 3 ** 32 ** SD_MISO +#define HIB_PIN 33 // PB 4 ** 33 ** HIB_PIN +#define SOCKET0_SS 34 // PB 5 ** 34 ** SOCKET0_SS +#define GPS_PW 35 // PA 0 ** 35 ** GPS_PW +#define MUX1_0 36 // PB 6 ** 36 ** MUX1_0 +#define MUX1_1 37 // PB 7 ** 37 ** MUX1_1 +#define RDY_ACC 38 // PE 6 ** 38 ** RDY_ACC +#define RST_RTC 39 // PE 7 ** 39 ** RST_RTC +#define I2C_SCL 40 // PD 0 ** 40 ** I2C_SCL +#define I2C_SDA 41 // PD 1 ** 41 ** I2C_SDA +#define GPRS_PW 42 // PC 3 ** 42 ** GPRS_PW +#define MUX_RX 43 // PD 2 ** 43 ** GPS/Socket1/Aux1/Aux2_RX +#define MUX_TX 44 // PD 3 ** 44 ** GPS/Socket1/Aux1/Aux2_TX +#define XBEE_MON 45 // PA 7 ** 45 ** XBEE_MON +#define GPRS_PIN 46 // PC 2 ** 46 ** GPRS_PIN +#define XBEE_SLEEP 47 // PD 4 ** 47 ** XBEE_SLEEP +#define MUX0_PW 48 // PG 2 ** 48 ** MUX0_PW (Waspmote v15) +#define RTC_PW 48 // PG 2 ** 48 ** RTC_PW (Waspmote v12) +#define RTC_SLEEP 49 // PG 1 *** 49 ** RTC_SLEEP +#define POWER_3V3 50 // PG 0 ** 50 ** MAIN POWER_3V3 (Waspmote v15) +#define CHG_IND 51 // PG 3 ** 51 ** CHG_IND (Waspmote v15) +#define SPI_ON 52 // PG 4 ** 52 ** SPI_ON (Waspmote v15) #define NOT_A_PIN 0 #define NOT_A_PORT 0 diff --git a/waspmote-api/sd_utilities/Sd2Card.cpp b/waspmote-api/sd_utilities/Sd2Card.cpp index 89853cc..574878d 100644 --- a/waspmote-api/sd_utilities/Sd2Card.cpp +++ b/waspmote-api/sd_utilities/Sd2Card.cpp @@ -1,6 +1,6 @@ /* Arduino Sd2Card Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino Sd2Card Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino Sd2Card Library. If not, see * . + * + * Version: 3.0 + * */ #include "Sd2Card.h" #include "../WaspSPI.h" @@ -265,7 +268,7 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) m_chipSelectPin = chipSelectPin; // 16-bit init start time allows over a minute - uint16_t t0 = (uint16_t)millis(); + uint32_t t0 = millis(); uint32_t arg; int retries = 512; @@ -283,12 +286,12 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) // command to go idle in SPI mode while (cardCommand(CMD0, 0) != R1_IDLE_STATE) { - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) + if ((millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } - if(t0>millis()) t0 = (uint16_t)millis(); + if(t0>millis()) t0 = millis(); } #if USE_SD_CRC @@ -300,7 +303,7 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) #endif // USE_SD_CRC // check SD version - + // do not need a timeout because there is a counter while( retries > 0) { retries--; @@ -316,12 +319,12 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) type(SD_CARD_TYPE_SD2); break; } - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) + if ((millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD8); goto fail; } - if(t0>millis()) t0 = (uint16_t)millis(); + if(t0>millis()) t0 = millis(); } // initialize card and send host supports SDHC if SD2 @@ -330,12 +333,12 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) while (cardAcmd(ACMD41, arg) != R1_READY_STATE) { // check for timeout - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) + if ((millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } - if(t0>millis()) t0 = (uint16_t)millis(); + if(t0>millis()) t0 = millis(); } // if SD2 read OCR register to check for SDHC card if (type() == SD_CARD_TYPE_SD2) @@ -401,15 +404,15 @@ bool Sd2Card::readData(uint8_t* dst, size_t count) { #endif // USE_SD_CRC // wait for start block token - uint16_t t0 = millis(); + uint32_t t0 = millis(); while ((m_status = SPI.receive()) == 0XFF) { - if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) + if ((millis() - t0) > SD_READ_TIMEOUT) { error(SD_CARD_ERROR_READ_TIMEOUT); goto fail; } - if(t0>millis()) t0 = (uint16_t)millis(); + if(t0>millis()) t0 = millis(); } if (m_status != DATA_START_BLOCK) { error(SD_CARD_ERROR_READ); @@ -500,13 +503,13 @@ bool Sd2Card::readStop() { } //------------------------------------------------------------------------------ // wait for card to go not busy -bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) +bool Sd2Card::waitNotBusy(uint32_t timeoutMillis) { - uint16_t t0 = millis(); + uint32_t t0 = millis(); while (SPI.receive() != 0XFF) { - if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; - if(t0>millis()) t0 = (uint16_t)millis(); + if ((millis() - t0) >= timeoutMillis) goto fail; + if(t0>millis()) t0 = millis(); } return true; diff --git a/waspmote-api/sd_utilities/Sd2Card.h b/waspmote-api/sd_utilities/Sd2Card.h index 38aea14..8f6c5b8 100644 --- a/waspmote-api/sd_utilities/Sd2Card.h +++ b/waspmote-api/sd_utilities/Sd2Card.h @@ -1,6 +1,6 @@ /* Arduino Sd2Card Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino Sd2Card Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino Sd2Card Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SpiCard_h #define SpiCard_h @@ -47,13 +50,13 @@ uint8_t const SPI_EIGHTH_SPEED = 16; uint8_t const SPI_SIXTEENTH_SPEED = 32; //------------------------------------------------------------------------------ /** init timeout ms */ -uint16_t const SD_INIT_TIMEOUT = 2000; +uint32_t const SD_INIT_TIMEOUT = 2000; /** erase timeout ms */ -uint16_t const SD_ERASE_TIMEOUT = 10000; +uint32_t const SD_ERASE_TIMEOUT = 10000; /** read timeout ms */ -uint16_t const SD_READ_TIMEOUT = 300; +uint32_t const SD_READ_TIMEOUT = 300; /** write time out ms */ -uint16_t const SD_WRITE_TIMEOUT = 600; +uint32_t const SD_WRITE_TIMEOUT = 600; //------------------------------------------------------------------------------ // SD card errors /** timeout error for command CMD0 (initialize card in SPI mode) */ @@ -213,7 +216,7 @@ class Sd2Card { void chipSelectHigh(); void chipSelectLow(); void type(uint8_t value) {m_type = value;} - bool waitNotBusy(uint16_t timeoutMillis); + bool waitNotBusy(uint32_t timeoutMillis); bool writeData(uint8_t token, const uint8_t* src); // private data diff --git a/waspmote-api/sd_utilities/SdBaseFile.cpp b/waspmote-api/sd_utilities/SdBaseFile.cpp index d04b4b8..b2421dc 100644 --- a/waspmote-api/sd_utilities/SdBaseFile.cpp +++ b/waspmote-api/sd_utilities/SdBaseFile.cpp @@ -1,6 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "SdFat.h" @@ -276,26 +279,34 @@ bool SdBaseFile::exists(const char* name) { * \return For success fgets() returns the length of the string in \a str. * If no data is read, fgets() returns zero for EOF or -1 if an error occurred. **/ -int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) { - char ch; - int16_t n = 0; - int16_t r = -1; - while ((n + 1) < num && (r = read(&ch, 1)) == 1) { - // delete CR - if (ch == '\r') continue; - str[n++] = ch; - if (!delim) { - if (ch == '\n') break; - } else { - if (strchr(delim, ch)) break; - } - } - if (r < 0) { - // read error - return -1; - } - str[n] = '\0'; - return n; +int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) +{ + char ch; + int16_t n = 0; + int16_t r = -1; + + // do not need a timeout because there is a counter + while ((n + 1) < num && (r = read(&ch, 1)) == 1) + { + // delete CR + if (ch == '\r') continue; + str[n++] = ch; + if (!delim) + { + if (ch == '\n') break; + } + else + { + if (strchr(delim, ch)) break; + } + } + if (r < 0) + { + // read error + return -1; + } + str[n] = '\0'; + return n; } //------------------------------------------------------------------------------ /** Get a file's name @@ -442,6 +453,7 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) } } + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; @@ -449,7 +461,7 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) if (!make83Name(path, dname, &path)) { DBG_FAIL_MACRO; - USB.println(F("Invalid filename")); + USB.println(F("[SD] Invalid filename")); goto fail; } @@ -646,6 +658,7 @@ bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) } } + // do not need a timeout because there is a counter while( retries > 0) { retries--; @@ -659,7 +672,7 @@ bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) } else { - USB.println(F("Invalid filename")); + USB.println(F("[SD] Invalid filename")); DBG_FAIL_MACRO; goto fail; } @@ -697,13 +710,14 @@ bool SdBaseFile::open( SdBaseFile* dirFile, bool fileFound = false; uint8_t index; dir_t* p; + uint32_t previous = millis(); m_vol = dirFile->m_vol; dirFile->rewind(); // search for file while (dirFile->m_curPosition < dirFile->m_fileSize) - { + { // Cache directory block. if (dirFile->read() < 0) { @@ -739,6 +753,15 @@ bool SdBaseFile::open( SdBaseFile* dirFile, goto done; } } + + if (millis()-previous > 60000) + { + DBG_FAIL_MACRO; + goto fail; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); } done: @@ -973,6 +996,7 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) } m_vol = dirFile->m_vol; + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; @@ -1018,79 +1042,103 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ -bool SdBaseFile::openParent(SdBaseFile* dir) { - dir_t entry; - dir_t* p; - SdBaseFile file; - uint32_t c; - uint32_t cluster; - uint32_t lbn; - cache_t* pc; - // error if already open or dir is root or dir is not a directory - if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) { - DBG_FAIL_MACRO; - goto fail; - } - m_vol = dir->m_vol; - // position to '..' - if (!dir->seekSet(32)) { - DBG_FAIL_MACRO; - goto fail; - } - // read '..' entry - if (dir->read(&entry, sizeof(entry)) != 32) { - DBG_FAIL_MACRO; - goto fail; - } - // verify it is '..' - if (entry.name[0] != '.' || entry.name[1] != '.') { - DBG_FAIL_MACRO; - goto fail; - } - // start cluster for '..' - cluster = entry.firstClusterLow; - cluster |= (uint32_t)entry.firstClusterHigh << 16; - if (cluster == 0) return openRoot(m_vol); - // start block for '..' - lbn = m_vol->clusterStartBlock(cluster); - // first block of parent dir +bool SdBaseFile::openParent(SdBaseFile* dir) +{ + dir_t entry; + dir_t* p; + SdBaseFile file; + uint32_t c; + uint32_t cluster; + uint32_t lbn; + cache_t* pc; + + // error if already open or dir is root or dir is not a directory + if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) + { + DBG_FAIL_MACRO; + goto fail; + } + m_vol = dir->m_vol; + // position to '..' + if (!dir->seekSet(32)) + { + DBG_FAIL_MACRO; + goto fail; + } + // read '..' entry + if (dir->read(&entry, sizeof(entry)) != 32) + { + DBG_FAIL_MACRO; + goto fail; + } + + // verify it is '..' + if (entry.name[0] != '.' || entry.name[1] != '.') + { + DBG_FAIL_MACRO; + goto fail; + } + + // start cluster for '..' + cluster = entry.firstClusterLow; + cluster |= (uint32_t)entry.firstClusterHigh << 16; + if (cluster == 0) return openRoot(m_vol); + + // start block for '..' + lbn = m_vol->clusterStartBlock(cluster); + + // first block of parent dir pc = m_vol->cacheFetch(lbn, SdVolume::CACHE_FOR_READ); - if (!pc) { - DBG_FAIL_MACRO; - goto fail; - } - p = &pc->dir[1]; - // verify name for '../..' - if (p->name[0] != '.' || p->name[1] != '.') { - DBG_FAIL_MACRO; - goto fail; - } - // '..' is pointer to first cluster of parent. open '../..' to find parent - if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) { - if (!file.openRoot(dir->volume())) { - DBG_FAIL_MACRO; - goto fail; - } - } else { - if (!file.openCachedEntry(1, O_READ)) { - DBG_FAIL_MACRO; - goto fail; - } - } - // search for parent in '../..' - do { - if (file.readDir(&entry) != 32) { - DBG_FAIL_MACRO; - goto fail; - } - c = entry.firstClusterLow; - c |= (uint32_t)entry.firstClusterHigh << 16; - } while (c != cluster); - // open parent - return open(&file, file.curPosition()/32 - 1, O_READ); + if (!pc) + { + DBG_FAIL_MACRO; + goto fail; + } + p = &pc->dir[1]; + + // verify name for '../..' + if (p->name[0] != '.' || p->name[1] != '.') + { + DBG_FAIL_MACRO; + goto fail; + } + + // '..' is pointer to first cluster of parent. open '../..' to find parent + if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) + { + if (!file.openRoot(dir->volume())) + { + DBG_FAIL_MACRO; + goto fail; + } + } + else + { + if (!file.openCachedEntry(1, O_READ)) + { + DBG_FAIL_MACRO; + goto fail; + } + } + + // search for parent in '../..' + do + { + if (file.readDir(&entry) != 32) + { + DBG_FAIL_MACRO; + goto fail; + } + c = entry.firstClusterLow; + c |= (uint32_t)entry.firstClusterHigh << 16; + + } while (c != cluster); + + // open parent + return open(&file, file.curPosition()/32 - 1, O_READ); fail: - return false; + return false; } //------------------------------------------------------------------------------ /** Open a volume's root directory. diff --git a/waspmote-api/sd_utilities/SdBaseFile.h b/waspmote-api/sd_utilities/SdBaseFile.h index 575d166..38d7942 100644 --- a/waspmote-api/sd_utilities/SdBaseFile.h +++ b/waspmote-api/sd_utilities/SdBaseFile.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SdBaseFile_h #define SdBaseFile_h diff --git a/waspmote-api/sd_utilities/SdFat.cpp b/waspmote-api/sd_utilities/SdFat.cpp index 6707c1b..5d5dc0f 100644 --- a/waspmote-api/sd_utilities/SdFat.cpp +++ b/waspmote-api/sd_utilities/SdFat.cpp @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "SdFat.h" //------------------------------------------------------------------------------ diff --git a/waspmote-api/sd_utilities/SdFat.h b/waspmote-api/sd_utilities/SdFat.h index 2f67179..b9ee5f2 100644 --- a/waspmote-api/sd_utilities/SdFat.h +++ b/waspmote-api/sd_utilities/SdFat.h @@ -1,6 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SdFat_h #define SdFat_h diff --git a/waspmote-api/sd_utilities/SdFatConfig.h b/waspmote-api/sd_utilities/SdFatConfig.h index f2dba31..0120003 100644 --- a/waspmote-api/sd_utilities/SdFatConfig.h +++ b/waspmote-api/sd_utilities/SdFatConfig.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ /** * \file diff --git a/waspmote-api/sd_utilities/SdFatStructs.h b/waspmote-api/sd_utilities/SdFatStructs.h index 9bcc145..ad24e52 100644 --- a/waspmote-api/sd_utilities/SdFatStructs.h +++ b/waspmote-api/sd_utilities/SdFatStructs.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SdFatStructs_h #define SdFatStructs_h diff --git a/waspmote-api/sd_utilities/SdFile.cpp b/waspmote-api/sd_utilities/SdFile.cpp index 3236a80..5384b51 100644 --- a/waspmote-api/sd_utilities/SdFile.cpp +++ b/waspmote-api/sd_utilities/SdFile.cpp @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "SdFile.h" /** Create a file object and open it in the current working directory. diff --git a/waspmote-api/sd_utilities/SdFile.h b/waspmote-api/sd_utilities/SdFile.h index 39b9dcb..2474f27 100644 --- a/waspmote-api/sd_utilities/SdFile.h +++ b/waspmote-api/sd_utilities/SdFile.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ /** * \file diff --git a/waspmote-api/sd_utilities/SdInfo.h b/waspmote-api/sd_utilities/SdInfo.h index 44d9126..8370443 100644 --- a/waspmote-api/sd_utilities/SdInfo.h +++ b/waspmote-api/sd_utilities/SdInfo.h @@ -1,5 +1,6 @@ /* Arduino Sd2Card Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino Sd2Card Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino Sd2Card Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SdInfo_h #define SdInfo_h diff --git a/waspmote-api/sd_utilities/SdStream.cpp b/waspmote-api/sd_utilities/SdStream.cpp index 9bc7cc9..4bf114f 100644 --- a/waspmote-api/sd_utilities/SdStream.cpp +++ b/waspmote-api/sd_utilities/SdStream.cpp @@ -1,6 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "SdFat.h" @@ -99,6 +102,7 @@ void SdStreamBase::putstr(const char* str) size_t n = 0; int retries = 512; + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; diff --git a/waspmote-api/sd_utilities/SdStream.h b/waspmote-api/sd_utilities/SdStream.h index 19c428c..52bd3de 100644 --- a/waspmote-api/sd_utilities/SdStream.h +++ b/waspmote-api/sd_utilities/SdStream.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef SdStream_h #define SdStream_h diff --git a/waspmote-api/sd_utilities/SdVolume.cpp b/waspmote-api/sd_utilities/SdVolume.cpp index dd70724..438175f 100644 --- a/waspmote-api/sd_utilities/SdVolume.cpp +++ b/waspmote-api/sd_utilities/SdVolume.cpp @@ -1,6 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified in 2016 for Waspmote, by Y. Carmona * * This file is part of the Arduino SdFat Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "SdFat.h" //------------------------------------------------------------------------------ @@ -36,84 +39,103 @@ Sd2Card* SdVolume::m_sdCard; // pointer to SD card object #endif // USE_MULTIPLE_CARDS //------------------------------------------------------------------------------ // find a contiguous group of clusters -bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { - // start of group - uint32_t bgnCluster; - // end of group - uint32_t endCluster; - // last cluster of FAT - uint32_t fatEnd = m_clusterCount + 1; - - // flag to save place to start next search - bool setStart; - - // set search start cluster - if (*curCluster) { - // try to make file contiguous - bgnCluster = *curCluster + 1; - - // don't save new start location - setStart = false; - } else { - // start at likely place for free cluster - bgnCluster = m_allocSearchStart; +bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) +{ + // start of group + uint32_t bgnCluster; + // end of group + uint32_t endCluster; + // last cluster of FAT + uint32_t fatEnd = m_clusterCount + 1; + + // flag to save place to start next search + bool setStart; + + // set search start cluster + if (*curCluster) + { + // try to make file contiguous + bgnCluster = *curCluster + 1; - // save next search start if one cluster - setStart = count == 1; - } - // end of group - endCluster = bgnCluster; + // don't save new start location + setStart = false; + } + else + { + // start at likely place for free cluster + bgnCluster = m_allocSearchStart; - // search the FAT for free clusters - for (uint32_t n = 0;; n++, endCluster++) { - // can't find space checked all clusters - if (n >= m_clusterCount) { - DBG_FAIL_MACRO; - goto fail; - } - // past end - start from beginning of FAT - if (endCluster > fatEnd) { - bgnCluster = endCluster = 2; - } - uint32_t f; - if (!fatGet(endCluster, &f)) { - DBG_FAIL_MACRO; - goto fail; - } + // save next search start if one cluster + setStart = count == 1; + } + // end of group + endCluster = bgnCluster; - if (f != 0) { - // cluster in use try next cluster as bgnCluster - bgnCluster = endCluster + 1; - } else if ((endCluster - bgnCluster + 1) == count) { - // done - found space - break; - } - } - // mark end of chain - if (!fatPutEOC(endCluster)) { - DBG_FAIL_MACRO; - goto fail; - } - // link clusters - while (endCluster > bgnCluster) { - if (!fatPut(endCluster - 1, endCluster)) { - DBG_FAIL_MACRO; - goto fail; - } - endCluster--; - } - if (*curCluster != 0) { - // connect chains - if (!fatPut(*curCluster, bgnCluster)) { - DBG_FAIL_MACRO; - goto fail; - } - } - // return first cluster number to caller - *curCluster = bgnCluster; + // search the FAT for free clusters + for (uint32_t n = 0;; n++, endCluster++) + { + // can't find space checked all clusters + if (n >= m_clusterCount) + { + DBG_FAIL_MACRO; + goto fail; + } + // past end - start from beginning of FAT + if (endCluster > fatEnd) { + bgnCluster = endCluster = 2; + } + uint32_t f; + if (!fatGet(endCluster, &f)) + { + DBG_FAIL_MACRO; + goto fail; + } + + if (f != 0) + { + // cluster in use try next cluster as bgnCluster + bgnCluster = endCluster + 1; + } + else if ((endCluster - bgnCluster + 1) == count) + { + // done - found space + break; + } + } + + // mark end of chain + if (!fatPutEOC(endCluster)) + { + DBG_FAIL_MACRO; + goto fail; + } + + // link clusters + // do not need timeout because there is a counter + while (endCluster > bgnCluster) + { + if (!fatPut(endCluster - 1, endCluster)) + { + DBG_FAIL_MACRO; + goto fail; + } + endCluster--; + } + + if (*curCluster != 0) + { + // connect chains + if (!fatPut(*curCluster, bgnCluster)) + { + DBG_FAIL_MACRO; + goto fail; + } + } + // return first cluster number to caller + *curCluster = bgnCluster; - // remember possible next free cluster - if (setStart) m_allocSearchStart = bgnCluster + 1; + // remember possible next free cluster + if (setStart) m_allocSearchStart = bgnCluster + 1; return true; @@ -429,81 +451,113 @@ bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { } //------------------------------------------------------------------------------ // free a cluster chain -bool SdVolume::freeChain(uint32_t cluster) { - uint32_t next; - - // clear free cluster location - m_allocSearchStart = 2; - - do { - if (!fatGet(cluster, &next)) { - DBG_FAIL_MACRO; - goto fail; - } - // free cluster - if (!fatPut(cluster, 0)) { - DBG_FAIL_MACRO; - goto fail; - } +bool SdVolume::freeChain(uint32_t cluster) +{ + uint32_t next; + uint32_t previous = millis(); + + // clear free cluster location + m_allocSearchStart = 2; - cluster = next; - } while (!isEOC(cluster)); + do + { + if (!fatGet(cluster, &next)) + { + DBG_FAIL_MACRO; + goto fail; + } + + // free cluster + if (!fatPut(cluster, 0)) + { + DBG_FAIL_MACRO; + goto fail; + } + cluster = next; + + if (millis() - previous > 60000) + { + DBG_FAIL_MACRO; + goto fail; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if (millis() < previous) previous = millis(); + } while (!isEOC(cluster)); + - return true; + return true; fail: - return false; + return false; } //------------------------------------------------------------------------------ /** Volume free space in clusters. * * \return Count of free clusters for success or -1 if an error occurs. */ -int32_t SdVolume::freeClusterCount() { - uint32_t free = 0; - uint32_t lba; - uint32_t todo = m_clusterCount + 2; - uint16_t n; +int32_t SdVolume::freeClusterCount() +{ + uint32_t free = 0; + uint32_t lba; + uint32_t todo = m_clusterCount + 2; + uint16_t n; - if (FAT12_SUPPORT && m_fatType == 12) { - for (unsigned i = 2; i < todo; i++) { - uint32_t c; - if (!fatGet(i, &c)) { - DBG_FAIL_MACRO; - goto fail; - } - if (c == 0) free++; - } - } else if (m_fatType == 16 || m_fatType == 32) { - lba = m_fatStartBlock; - while (todo) { - cache_t* pc = cacheFetchFat(lba++, CACHE_FOR_READ); - if (!pc) { - DBG_FAIL_MACRO; - goto fail; - } - n = m_fatType == 16 ? 256 : 128; - if (todo < n) n = todo; - if (m_fatType == 16) { - for (uint16_t i = 0; i < n; i++) { - if (pc->fat16[i] == 0) free++; - } - } else { - for (uint16_t i = 0; i < n; i++) { - if (pc->fat32[i] == 0) free++; - } - } - todo -= n; - } - } else { - // invalid FAT type - DBG_FAIL_MACRO; - goto fail; - } - return free; + if (FAT12_SUPPORT && m_fatType == 12) + { + for (unsigned i = 2; i < todo; i++) + { + uint32_t c; + if (!fatGet(i, &c)) + { + DBG_FAIL_MACRO; + goto fail; + } + if (c == 0) free++; + } + } + else if (m_fatType == 16 || m_fatType == 32) + { + lba = m_fatStartBlock; + + // do not need a timeout because there is a counter + while (todo) + { + cache_t* pc = cacheFetchFat(lba++, CACHE_FOR_READ); + if (!pc) + { + DBG_FAIL_MACRO; + goto fail; + } + n = m_fatType == 16 ? 256 : 128; + if (todo < n) n = todo; + if (m_fatType == 16) + { + for (uint16_t i = 0; i < n; i++) + { + if (pc->fat16[i] == 0) free++; + } + } + else + { + for (uint16_t i = 0; i < n; i++) + { + if (pc->fat32[i] == 0) free++; + } + } + todo -= n; + } + } + else + { + // invalid FAT type + DBG_FAIL_MACRO; + goto fail; + } + return free; fail: - return -1; + return -1; } //------------------------------------------------------------------------------ /** Initialize a FAT volume. diff --git a/waspmote-api/sd_utilities/SdVolume.h b/waspmote-api/sd_utilities/SdVolume.h index 1a678a4..67dd109 100644 --- a/waspmote-api/sd_utilities/SdVolume.h +++ b/waspmote-api/sd_utilities/SdVolume.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Revised for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,8 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 */ #ifndef SdVolume_h #define SdVolume_h diff --git a/waspmote-api/sd_utilities/bufstream.h b/waspmote-api/sd_utilities/bufstream.h index 2c288c7..3b1db45 100644 --- a/waspmote-api/sd_utilities/bufstream.h +++ b/waspmote-api/sd_utilities/bufstream.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef bufstream_h #define bufstream_h diff --git a/waspmote-api/sd_utilities/ios.h b/waspmote-api/sd_utilities/ios.h index f5a333e..b5d3d37 100644 --- a/waspmote-api/sd_utilities/ios.h +++ b/waspmote-api/sd_utilities/ios.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef ios_h #define ios_h diff --git a/waspmote-api/sd_utilities/iostream.h b/waspmote-api/sd_utilities/iostream.h index bcb428a..df65bdb 100644 --- a/waspmote-api/sd_utilities/iostream.h +++ b/waspmote-api/sd_utilities/iostream.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef iostream_h #define iostream_h diff --git a/waspmote-api/sd_utilities/istream.cpp b/waspmote-api/sd_utilities/istream.cpp index 0b149f2..b243783 100644 --- a/waspmote-api/sd_utilities/istream.cpp +++ b/waspmote-api/sd_utilities/istream.cpp @@ -1,6 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman - * Modified in 2014 for Waspmote, by Y. Carmona + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include #include "istream.h" @@ -66,24 +69,30 @@ istream& istream::get(char& c) { * * \return always returns *this. A failure is indicated by the stream state. */ -istream& istream::get(char *str, streamsize n, char delim) { - int c; - FatPos_t pos; - m_gcount = 0; - while ((m_gcount + 1) < n) { - c = getch(&pos); - if (c < 0) { - break; - } - if (c == delim) { - setpos(&pos); - break; - } - str[m_gcount++] = c; - } - if (n > 0) str[m_gcount] = '\0'; - if (m_gcount == 0) setstate(failbit); - return *this; +istream& istream::get(char *str, streamsize n, char delim) +{ + int c; + FatPos_t pos; + m_gcount = 0; + + // do not need a timeout because there is a counter + while ((m_gcount + 1) < n) + { + c = getch(&pos); + if (c < 0) + { + break; + } + if (c == delim) + { + setpos(&pos); + break; + } + str[m_gcount++] = c; + } + if (n > 0) str[m_gcount] = '\0'; + if (m_gcount == 0) setstate(failbit); + return *this; } //------------------------------------------------------------------------------ void istream::getBool(bool *b) @@ -104,6 +113,7 @@ void istream::getBool(bool *b) uint8_t i = 0; int c = readSkip(); + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; @@ -163,6 +173,7 @@ bool istream::getDouble(double* value) c = getch(); } + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; @@ -192,48 +203,68 @@ bool istream::getDouble(double* value) c = getch(&endPos); } - if (!got_digit) goto fail; - if (c == 'e' || c == 'E') { - c = getch(); - expNeg = c == '-'; - if (c == '-' || c == '+') { - c = getch(); - } - while (isdigit(c)) { - if (exp > EXP_LIMIT) goto fail; - exp = exp * 10 + (c - '0'); - c = getch(&endPos); - } - } - v = static_cast(frac); - exp = expNeg ? fracExp - exp : fracExp + exp; - expNeg = exp < 0; - if (expNeg) exp = -exp; - pow10 = 10.0; - while (exp) { - if (exp & 1) { - if (expNeg) { - // check for underflow - if (v < FLT_MIN * pow10 && frac != 0) goto fail; - v /= pow10; - } else { - // check for overflow - if (v > FLT_MAX / pow10) goto fail; - v *= pow10; - } - } - pow10 *= pow10; - exp >>= 1; - } - setpos(&endPos); - *value = neg ? -v : v; - return true; + if (!got_digit) goto fail; + if (c == 'e' || c == 'E') + { + c = getch(); + expNeg = c == '-'; + if (c == '-' || c == '+') + { + c = getch(); + } + + uint32_t previous = millis(); + while (isdigit(c)) + { + if (exp > EXP_LIMIT) goto fail; + exp = exp * 10 + (c - '0'); + c = getch(&endPos); + + if (millis() - previous > 60000) + { + goto fail; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + } + } + v = static_cast(frac); + exp = expNeg ? fracExp - exp : fracExp + exp; + expNeg = exp < 0; + if (expNeg) exp = -exp; + pow10 = 10.0; + + // do not need a timeout because there is a counter + while (exp) + { + if (exp & 1) + { + if (expNeg) + { + // check for underflow + if (v < FLT_MIN * pow10 && frac != 0) goto fail; + v /= pow10; + } + else + { + // check for overflow + if (v > FLT_MAX / pow10) goto fail; + v *= pow10; + } + } + pow10 *= pow10; + exp >>= 1; + } + setpos(&endPos); + *value = neg ? -v : v; + return true; fail: - // error restore position to last good place - setpos(&endPos); - setstate(failbit); - return false; + // error restore position to last good place + setpos(&endPos); + setstate(failbit); + return false; } //------------------------------------------------------------------------------ /** @@ -261,6 +292,7 @@ istream& istream::getline(char *str, streamsize n, char delim) m_gcount = 0; if (n > 0) str[0] = '\0'; + // do not need a timeout because there is a counter while( retries > 0 ) { retries--; @@ -329,6 +361,7 @@ bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) cutlim = cutoff % base; cutoff /= base; + // do not need a timeout because there is a counter while( retries > 0) { retries--; @@ -374,29 +407,35 @@ bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) /** * */ -void istream::getStr(char *str) { - FatPos_t pos; - uint16_t i = 0; - uint16_t m = width() ? width() - 1 : 0XFFFE; - if (m != 0) { - getpos(&pos); - int c = readSkip(); +void istream::getStr(char *str) +{ + FatPos_t pos; + uint16_t i = 0; + uint16_t m = width() ? width() - 1 : 0XFFFE; + if (m != 0) + { + getpos(&pos); + int c = readSkip(); - while (i < m) { - if (c < 0) { - break; - } - if (isspace(c)) { - setpos(&pos); - break; - } - str[i++] = c; - c = getch(&pos); - } - } - str[i] = '\0'; - if (i == 0) setstate(failbit); - width(0); + // do not need a timeout because there is a counter + while (i < m) + { + if (c < 0) + { + break; + } + if (isspace(c)) + { + setpos(&pos); + break; + } + str[i++] = c; + c = getch(&pos); + } + } + str[i] = '\0'; + if (i == 0) setstate(failbit); + width(0); } //------------------------------------------------------------------------------ /** @@ -414,18 +453,32 @@ void istream::getStr(char *str) { * \return *this * */ -istream& istream::ignore(streamsize n, int delim) { - int c; - m_gcount = 0; - while (m_gcount < n) { - c = getch(); - if (c < 0) { - break; - } - m_gcount++; - if (c == delim) break; - } - return *this; +istream& istream::ignore(streamsize n, int delim) +{ + int c; + m_gcount = 0; + uint32_t previous = millis(); + + // do not need a timeout because there is a counter + while (m_gcount < n) + { + c = getch(); + if (c < 0) + { + break; + } + m_gcount++; + if (c == delim) break; + + if (millis() - previous > 60000) + { + break; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + } + return *this; } //------------------------------------------------------------------------------ /** @@ -448,12 +501,24 @@ int istream::peek() { return c; } //------------------------------------------------------------------------------ -int16_t istream::readSkip() { - int16_t c; - do { - c = getch(); - } while (isspace(c) && (flags() & skipws)); - return c; +int16_t istream::readSkip() +{ + int16_t c; + uint32_t previous = millis(); + do + { + c = getch(); + + if (millis() - previous > 60000) + { + break; + } + + // Condition to avoid an overflow (DO NOT REMOVE) + if( millis() < previous) previous = millis(); + + } while (isspace(c) && (flags() & skipws)); + return c; } //------------------------------------------------------------------------------ /** used to implement ws() */ diff --git a/waspmote-api/sd_utilities/istream.h b/waspmote-api/sd_utilities/istream.h index 3f65613..7be46dd 100644 --- a/waspmote-api/sd_utilities/istream.h +++ b/waspmote-api/sd_utilities/istream.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef istream_h #define istream_h diff --git a/waspmote-api/sd_utilities/ostream.cpp b/waspmote-api/sd_utilities/ostream.cpp index 1942392..ca5d753 100644 --- a/waspmote-api/sd_utilities/ostream.cpp +++ b/waspmote-api/sd_utilities/ostream.cpp @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #include "ostream.h" @@ -34,15 +38,17 @@ void ostream::fill_not_left(unsigned len) { } } //------------------------------------------------------------------------------ -char* ostream::fmtNum(uint32_t n, char *ptr, uint8_t base) { - char a = flags() & uppercase ? 'A' - 10 : 'a' - 10; - do { - uint32_t m = n; - n /= base; - char c = m - base * n; - *--ptr = c < 10 ? c + '0' : c + a; - } while (n); - return ptr; +char* ostream::fmtNum(uint32_t n, char *ptr, uint8_t base) +{ + char a = flags() & uppercase ? 'A' - 10 : 'a' - 10; + do + { + uint32_t m = n; + n /= base; + char c = m - base * n; + *--ptr = c < 10 ? c + '0' : c + a; + } while (n); + return ptr; } //------------------------------------------------------------------------------ void ostream::putBool(bool b) { @@ -63,62 +69,74 @@ void ostream::putChar(char c) { do_fill(1); } //------------------------------------------------------------------------------ -void ostream::putDouble(double n) { - uint8_t nd = precision(); - double round = 0.5; - char sign; - char buf[13]; // room for sign, 10 digits, '.', and zero byte - char *end = buf + sizeof(buf) - 1; - char *str = end; - // terminate string - *end = '\0'; +void ostream::putDouble(double n) +{ + uint8_t nd = precision(); + double round = 0.5; + char sign; + char buf[13]; // room for sign, 10 digits, '.', and zero byte + char *end = buf + sizeof(buf) - 1; + char *str = end; + // terminate string + *end = '\0'; - // get sign and make nonnegative - if (n < 0.0) { - sign = '-'; - n = -n; - } else { - sign = flags() & showpos ? '+' : '\0'; - } - // check for larger than uint32_t - if (n > 4.0E9) { - putPgm(PSTR("BIG FLT")); - return; - } - // round up and separate in and fraction parts - for (uint8_t i = 0; i < nd; ++i) round *= 0.1; - n += round; - uint32_t intPart = n; - double fractionPart = n - intPart; + // get sign and make nonnegative + if (n < 0.0) + { + sign = '-'; + n = -n; + } + else + { + sign = flags() & showpos ? '+' : '\0'; + } + + // check for larger than uint32_t + if (n > 4.0E9) + { + putPgm(PSTR("BIG FLT")); + return; + } + + // round up and separate in and fraction parts + for (uint8_t i = 0; i < nd; ++i) round *= 0.1; + n += round; + uint32_t intPart = n; + double fractionPart = n - intPart; - // format intPart and decimal point - if (nd || (flags() & showpoint)) *--str = '.'; - str = fmtNum(intPart, str, 10); + // format intPart and decimal point + if (nd || (flags() & showpoint)) *--str = '.'; + str = fmtNum(intPart, str, 10); - // calculate length for fill - uint8_t len = sign ? 1 : 0; - len += nd + end - str; + // calculate length for fill + uint8_t len = sign ? 1 : 0; + len += nd + end - str; - // extract adjust field - fmtflags adj = flags() & adjustfield; - if (adj == internal) { - if (sign) putch(sign); - do_fill(len); - } else { - // do fill for internal or right - fill_not_left(len); - if (sign) *--str = sign; - } - putstr(str); - // output fraction - while (nd-- > 0) { - fractionPart *= 10.0; - int digit = static_cast(fractionPart); - putch(digit + '0'); - fractionPart -= digit; - } - // do fill if not done above - do_fill(len); + // extract adjust field + fmtflags adj = flags() & adjustfield; + if (adj == internal) + { + if (sign) putch(sign); + do_fill(len); + } + else + { + // do fill for internal or right + fill_not_left(len); + if (sign) *--str = sign; + } + putstr(str); + + // output fraction + while (nd-- > 0) + { + fractionPart *= 10.0; + int digit = static_cast(fractionPart); + putch(digit + '0'); + fractionPart -= digit; + } + // do fill if not done above + do_fill(len); } //------------------------------------------------------------------------------ void ostream::putNum(int32_t n) { @@ -127,36 +145,47 @@ void ostream::putNum(int32_t n) { putNum(n, neg); } //------------------------------------------------------------------------------ -void ostream::putNum(uint32_t n, bool neg) { - char buf[13]; - char* end = buf + sizeof(buf) - 1; - char* num; - char* str; - uint8_t base = flagsToBase(); - *end = '\0'; - str = num = fmtNum(n, end, base); - if (base == 10) { - if (neg) { - *--str = '-'; - } else if (flags() & showpos) { - *--str = '+'; - } - } else if (flags() & showbase) { - if (flags() & hex) { - *--str = flags() & uppercase ? 'X' : 'x'; - } - *--str = '0'; - } - uint8_t len = end - str; - fmtflags adj = flags() & adjustfield; - if (adj == internal) { - while (str < num) putch(*str++); - } - if (adj != left) { - do_fill(len); - } - putstr(str); - do_fill(len); +void ostream::putNum(uint32_t n, bool neg) +{ + char buf[13]; + char* end = buf + sizeof(buf) - 1; + char* num; + char* str; + uint8_t base = flagsToBase(); + *end = '\0'; + str = num = fmtNum(n, end, base); + if (base == 10) + { + if (neg) + { + *--str = '-'; + } + else if (flags() & showpos) + { + *--str = '+'; + } + } + else if (flags() & showbase) + { + if (flags() & hex) + { + *--str = flags() & uppercase ? 'X' : 'x'; + } + *--str = '0'; + } + + uint8_t len = end - str; + fmtflags adj = flags() & adjustfield; + if (adj == internal) + { + while (str < num) putch(*str++); + } + if (adj != left) + { + do_fill(len); + } + putstr(str); + do_fill(len); } //------------------------------------------------------------------------------ void ostream::putPgm(const char* str) { diff --git a/waspmote-api/sd_utilities/ostream.h b/waspmote-api/sd_utilities/ostream.h index d04b7b9..843562c 100644 --- a/waspmote-api/sd_utilities/ostream.h +++ b/waspmote-api/sd_utilities/ostream.h @@ -1,5 +1,6 @@ /* Arduino SdFat Library * Copyright (C) 2012 by William Greiman + * Modified for Waspmote by Libelium, 2016 * * This file is part of the Arduino SdFat Library * @@ -16,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . + * + * Version: 3.0 + * */ #ifndef ostream_h #define ostream_h diff --git a/waspmote-api/twi.c b/waspmote-api/twi.c index 738c8de..bb49f8c 100755 --- a/waspmote-api/twi.c +++ b/waspmote-api/twi.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2006 Nicholas Zambetti. All right reserved. - * Revised for Waspmote by Libelium, 2014-2015 + * Revised for Waspmote by Libelium, 2014-2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.2 + * Version: 3.0 * Implementation: N. Zambetti, A. Bielsa, Y. Carmona */ @@ -387,9 +387,9 @@ void twi_close() cbi(TWCR,TWSTA); cbi(TWCR,TWWC); // switch off TWI depending on wether a sensor board is plugged or not - if( (WaspRegister & REG_GASES) - || (WaspRegister & REG_CITIES_V14) - || (WaspRegister & REG_PROTOTYPING) ) + if( (WaspRegisterSensor & REG_GASES) + || (WaspRegisterSensor & REG_CITIES_V14) + || (WaspRegisterSensor & REG_PROTOTYPING) ) { cbi(TWCR,TWEN); } diff --git a/waspmote-api/twi.h b/waspmote-api/twi.h index c1383c0..9c0042e 100755 --- a/waspmote-api/twi.h +++ b/waspmote-api/twi.h @@ -1,5 +1,5 @@ /* - * Revised for Waspmote by Libelium, 2009-2015 + * Revised for Waspmote by Libelium, 2009-2016 * * Copyright (c) 2006 Nicholas Zambetti. All right reserved. * @@ -15,6 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ diff --git a/waspmote-api/wiring.c b/waspmote-api/wiring.c index fc60e40..87c2f53 100755 --- a/waspmote-api/wiring.c +++ b/waspmote-api/wiring.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2008 D. Cuartielles * Copyright (c) 2005-2006 David A. Mellis - * Modified for Waspmote by Libelium, 2014 + * Modified for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . - * Version: 1.0 + * + * Version: 3.0 * Implementation: D. Mellis, D. Cuartielles, A. Bielsa, Y. Carmona */ @@ -325,25 +326,22 @@ void init() sbi(TCCR3A, WGM30); // configure and enable a2d conversions - //FIXME: this is to turn on ADC!! - //PWR.setIPF(IPADC); //---> the following is taken from WaspPWR - // turn on the power on the ADC - // by writing a zero to the register - cbi(PRR0, PRADC); - - // set a2d reference to AVCC (5 volts) - cbi(ADMUX, REFS1); - sbi(ADMUX, REFS0); - - // set a2d prescale factor to 128 - // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. - // FIXME: this will not work properly for other clock speeds, and - // this code should use F_CPU to determine the prescale factor. - sbi(ADCSRA, ADPS2); - sbi(ADCSRA, ADPS1); - - // enable a2d conversions - sbi(ADCSRA, ADEN); + // turn on the power on the ADC + // by writing a zero to the register + cbi(PRR0, PRADC); + + // set a2d reference to AVCC + cbi(ADMUX, REFS1); + sbi(ADMUX, REFS0); + + // set a2d prescale factor to 128 + // 14745600 Hz / 128 = 115200 Hz, inside the desired 50-200 KHz range + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); // the bootloader connects pins 0 and 1 to the USART; disconnect them diff --git a/waspmote-api/wiring.h b/waspmote-api/wiring.h index c6a0c0e..d411f86 100755 --- a/waspmote-api/wiring.h +++ b/waspmote-api/wiring.h @@ -1,6 +1,6 @@ /* * Modified for Waspmote by D. Cuartielles & A. Bielsa, 2009 - * Modified for Waspmote, 2014 + * Modified for Waspmote, 2016 * * Copyright (c) 2005-2006 David A. Mellis * @@ -16,6 +16,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ @@ -73,6 +75,7 @@ void init(void); void pinMode(uint8_t, uint8_t); void digitalWrite(uint8_t, uint8_t); int digitalRead(uint8_t); +void analogReference(uint8_t mode); int analogRead(uint8_t); void analogWrite(uint8_t, int); diff --git a/waspmote-api/wiring_analog.c b/waspmote-api/wiring_analog.c index a8882c1..eb7c652 100755 --- a/waspmote-api/wiring_analog.c +++ b/waspmote-api/wiring_analog.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis - * Modified for Waspmote by Libelium, 2014 + * Modified for Waspmote by Libelium, 2016 * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -14,12 +14,75 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 + * + * */ #include "wiring_private.h" #include "pins_waspmote.h" + +uint8_t analog_reference = DEFAULT; + + +/*! + * @brief This function sets the analog_reference for ADC conversion + * @param uint8_t mode: Select the voltage reference selections for ADC + * @arg EXTERNAL: AREF, Internal VREF turned off + * @arg DEFAULT: AVCC with external capacitor at AREF pin + * @arg INTERNAL1V1: Internal 1V1 reference with capacitor at AREF pin + * @arg INTERNAL2V56: Internal 2V56 reference with capacitor at AREF pin + * @return void + * + */ +void analogReference(uint8_t mode) +{ + analog_reference = mode; + + // set Reference Selection bits + if (analog_reference == INTERNAL2V56) + { + sbi(ADMUX, REFS1); + sbi(ADMUX, REFS0); + } + else if (analog_reference == INTERNAL1V1) + { + sbi(ADMUX, REFS1); + cbi(ADMUX, REFS0); + } + else if (analog_reference == EXTERNAL) + { + cbi(ADMUX, REFS1); + cbi(ADMUX, REFS0); + } + else + { + // DEFAULT + cbi(ADMUX, REFS1); + sbi(ADMUX, REFS0); + } + + // stabilization time + delay(10); +} + + +/*! + * @brief This function reads the analog pin + * @param uint8_t pin: input analog pin to read from + * @arg ANALOG1 + * @arg ANALOG2 + * @arg ANALOG3 + * @arg ANALOG4 + * @arg ANALOG5 + * @arg ANALOG6 + * @arg ANALOG7 + * @return analog value in bits (from 0 to 1023) as it is using a 10-bit ADC + * + */ int analogRead(uint8_t pin) { uint8_t low, high, ch = analogInPinToBit(pin); @@ -28,7 +91,7 @@ int analogRead(uint8_t pin) uint8_t channel = (ADMUX & (unsigned int) 0x0f); // enables the ADC - sbi(ADCSRA,ADEN); + sbi(ADCSRA, ADEN); // check if there is need to change the channel and wait for stabilization if( channel != ch ) diff --git a/waspmote-api/wiring_digital.c b/waspmote-api/wiring_digital.c index 77ddaad..bdb24af 100755 --- a/waspmote-api/wiring_digital.c +++ b/waspmote-api/wiring_digital.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis + * Modified for Waspmote, 2016. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -13,6 +14,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ diff --git a/waspmote-api/wiring_private.h b/waspmote-api/wiring_private.h index 7771466..e8b8096 100755 --- a/waspmote-api/wiring_private.h +++ b/waspmote-api/wiring_private.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis - * Modified for Waspmote by Libelium, 2014 + * Modified for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * - * Version: 1.0 + * Version: 3.0 * */ @@ -31,6 +31,10 @@ #include "wiring.h" +#ifndef __WASPCONSTANTS_H__ + #include "WaspConstants.h" +#endif + #ifdef __cplusplus extern "C"{ #endif diff --git a/waspmote-api/wiring_pulse.c b/waspmote-api/wiring_pulse.c index bbc255c..7ede380 100755 --- a/waspmote-api/wiring_pulse.c +++ b/waspmote-api/wiring_pulse.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis - * Modified for Waspmote, 2014. + * Modified for Waspmote, 2016. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -14,6 +14,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ diff --git a/waspmote-api/wiring_serial.c b/waspmote-api/wiring_serial.c index ebbad85..c0cceec 100755 --- a/waspmote-api/wiring_serial.c +++ b/waspmote-api/wiring_serial.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis - * Modified for Waspmote by Libelium, 2015 + * Modified for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -14,6 +14,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . + * + * Version: 3.0 */ diff --git a/waspmote-api/wiring_shift.c b/waspmote-api/wiring_shift.c index a151719..4bb73b3 100755 --- a/waspmote-api/wiring_shift.c +++ b/waspmote-api/wiring_shift.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2005-2006 David A. Mellis + * Modified for Waspmote by Libelium, 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -12,7 +13,9 @@ * GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * along with this program. If not, see . + * + * Version: 3.0 */ #include "wiring_private.h"