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,,