diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy
index b26e72b2a..7037309f7 100644
--- a/.ci/arduino.groovy
+++ b/.ci/arduino.groovy
@@ -1,16 +1,16 @@
#!groovy
def buildArduino(config, String buildFlags, String sketch, String key) {
- def root = '/opt/arduino-1.8.2/'
+ def root = '/opt/arduino-1.8.5/'
if (config.nightly_arduino_ide)
{
root = '/opt/arduino-nightly/'
}
- def esp8266_tools = '/opt/arduino-nightly/hardware/esp8266com/esp8266/tools'
+ //def esp8266_tools = '/opt/arduino-nightly/hardware/esp8266com/esp8266/tools'
def jenkins_root = '/var/lib/jenkins/'
def builder = root+'arduino-builder'
- def standard_args = ' -warnings="all"' //-verbose=true
+ def standard_args = ' -warnings=all' //-verbose=true
def builder_specifics = ' -hardware '+root+'hardware -tools '+root+'hardware/tools/avr -tools '+
- root+'tools-builder -tools '+esp8266_tools+' -built-in-libraries '+root+'libraries'
+ root+'tools-builder -built-in-libraries '+root+'libraries'
def jenkins_packages = jenkins_root+'.arduino15/packages'
def site_specifics = ' -hardware '+jenkins_packages+' -tools '+jenkins_packages
def repo_specifics = ' -hardware hardware -libraries . '
@@ -26,7 +26,9 @@ def parseWarnings(String key) {
excludePattern: '''.*/EEPROM\\.h,.*/Dns\\.cpp,.*/socket\\.cpp,.*/util\\.h,.*/Servo\\.cpp,
.*/Adafruit_NeoPixel\\.cpp,.*/UIPEthernet.*,.*/SoftwareSerial\\.cpp,
.*/pins_arduino\\.h,.*/Stream\\.cpp,.*/USBCore\\.cpp,.*/Wire\\.cpp,
- .*/hardware/STM32F1.*,.*/hardware/esp8266.*,.*/libraries/SD/.*''',
+ .*/hardware/STM32F1.*,.*/hardware/esp8266.*,.*/hardware/espressif/esp32.*,
+ .*/libraries/SD/.*''',
+
healthy: '', includePattern: '', messagesPattern: '',
parserConfigurations: [[parserName: 'Arduino/AVR', pattern: 'compiler_'+key+'.log']],
unHealthy: '', unstableNewAll: '0', unstableTotalAll: '0'
@@ -39,13 +41,16 @@ def parseWarnings(String key) {
}
def buildMySensorsMicro(config, sketches, String key) {
- def fqbn = '-fqbn MySensors:avr:MysensorsMicro -prefs build.f_cpu=1000000 -prefs build.mcu=atmega328p'
+ def fqbn = '-fqbn=MySensors:avr:MysensorsMicro:cpu=1Mhz'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsMicro')
}
@@ -60,7 +65,7 @@ def buildMySensorsMicro(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsMicro - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsMicro - '+key+')', 'Build error', '${BUILD_URL}')
@@ -70,7 +75,7 @@ def buildMySensorsMicro(config, sketches, String key) {
}
def buildMySensorsGw(config, sketches, String key) {
- def fqbn = '-fqbn MySensors:samd:mysensors_gw_native -prefs build.f_cpu=48000000 -prefs build.mcu=cortex-m0plus'
+ def fqbn = '-fqbn MySensors:samd:mysensors_gw_native'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
@@ -78,9 +83,12 @@ def buildMySensorsGw(config, sketches, String key) {
sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino') {
- buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGw')
+ buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGW')
}
}
} catch (ex) {
@@ -88,12 +96,12 @@ def buildMySensorsGw(config, sketches, String key) {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}')
throw ex
} finally {
- parseWarnings(key+'_MySensorsGw')
+ parseWarnings(key+'_MySensorsGW')
}
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsGW - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}')
@@ -103,13 +111,15 @@ def buildMySensorsGw(config, sketches, String key) {
}
def buildArduinoUno(config, sketches, String key) {
- def fqbn = '-fqbn arduino:avr:uno -prefs build.f_cpu=16000000 -prefs build.mcu=atmega328p'
+ def fqbn = '-fqbn arduino:avr:uno'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoUno')
}
@@ -124,7 +134,7 @@ def buildArduinoUno(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Arduino Uno - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Uno - '+key+')', 'Build error', '${BUILD_URL}')
@@ -134,13 +144,15 @@ def buildArduinoUno(config, sketches, String key) {
}
def buildArduinoMega(config, sketches, String key) {
- def fqbn = '-fqbn arduino:avr:mega -prefs build.f_cpu=16000000 -prefs build.mcu=atmega2560'
+ def fqbn = '-fqbn arduino:avr:mega:cpu=atmega2560'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoMega')
}
@@ -155,7 +167,7 @@ def buildArduinoMega(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, config, 'ERROR', 'Toll gate (Arduino Mega - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Mega - '+key+')', 'Build error', '${BUILD_URL}')
@@ -172,6 +184,8 @@ def buildSTM32F1(config, sketches, String key) {
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
buildArduino(config, fqbn, sketches[sketch].path, key+'_STM32F1')
}
@@ -186,7 +200,7 @@ def buildSTM32F1(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (STM32F1 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (STM32F1 - '+key+')', 'Build error', '${BUILD_URL}')
@@ -195,8 +209,8 @@ def buildSTM32F1(config, sketches, String key) {
}
}
-def buildEsp8266(config, sketches, String key) {
- def fqbn = '-fqbn esp8266:esp8266:generic -prefs build.f_cpu=80000000 -prefs build.mcu=esp8266'
+def buildESP8266(config, sketches, String key) {
+ def fqbn = '-fqbn=esp8266:esp8266:generic:CpuFrequency=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,FlashSize=512K0,led=2,LwIPVariant=v2mss536,Debug=Disabled,DebugLevel=None____,FlashErase=none,UploadSpeed=115200'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
@@ -206,10 +220,13 @@ def buildEsp8266(config, sketches, String key) {
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' &&
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' &&
sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') {
- buildArduino(config, '-prefs build.flash_ld=eagle.flash.512k0.ld -prefs build.flash_freq=40 -prefs build.flash_size=512K '+fqbn, sketches[sketch].path, key+'_Esp8266')
+ buildArduino(config, fqbn, sketches[sketch].path, key+'_ESP8266')
}
}
} catch (ex) {
@@ -217,12 +234,12 @@ def buildEsp8266(config, sketches, String key) {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}')
throw ex
} finally {
- parseWarnings(key+'_Esp8266')
+ parseWarnings(key+'_ESP8266')
}
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP8266 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}')
@@ -231,8 +248,56 @@ def buildEsp8266(config, sketches, String key) {
}
}
+def buildESP32(config, sketches, String key) {
+ def fqbn = '-fqbn espressif:esp32:esp32:PartitionScheme=default,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none -warnings=default'
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
+ try {
+ for (sketch = 0; sketch < sketches.size(); sketch++) {
+ if (sketches[sketch].path != config.library_root+'examples/BatteryPoweredSensor/BatteryPoweredSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/CO2Sensor/CO2Sensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/DustSensor/DustSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' &&
+ sketches[sketch].path != config.library_root+'examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/LightSensor/LightSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/LogOTANode/LogOTANode.ino' &&
+ sketches[sketch].path != config.library_root+'examples/MotionSensor/MotionSensor.ino' &&
+ sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' &&
+ sketches[sketch].path != config.library_root+'examples/PassiveNode/PassiveNode.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' &&
+ sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' &&
+ sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') {
+ buildArduino(config, fqbn, sketches[sketch].path, key+'_ESP32')
+ }
+ }
+ } catch (ex) {
+ echo "Build failed with: "+ ex.toString()
+ config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}')
+ throw ex
+ } finally {
+ parseWarnings(key+'_ESP32')
+ }
+ if (currentBuild.currentResult == 'UNSTABLE') {
+ config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP32 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
+ if (config.is_pull_request) {
+ error 'Terminated due to warnings found'
+ }
+ } else if (currentBuild.currentResult == 'FAILURE') {
+ config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}')
+ } else {
+ config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (ESP32 - '+key+')', 'Pass', '')
+ }
+}
+
def buildnRF5(config, sketches, String key) {
- def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832 -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4'
+ def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832:softdevice=none,lfclk=lfxo'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
for (sketch = 0; sketch < sketches.size(); sketch++) {
@@ -241,7 +306,10 @@ def buildnRF5(config, sketches, String key) {
sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' &&
+ sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' &&
sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' &&
@@ -260,7 +328,7 @@ def buildnRF5(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF5 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF5 - '+key+')', 'Build error', '${BUILD_URL}')
@@ -270,7 +338,7 @@ def buildnRF5(config, sketches, String key) {
}
def buildnRF52832(config, sketches, String key) {
- def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF52832:bootcode=none,lfclk=lfxo,reset=notenable -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4'
+ def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF52832:bootcode=none,lfclk=lfxo,reset=notenable'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyBoardNRF5/examples/MyBoardNRF5/MyBoardNRF5.ino', key+'_nRF52832')
@@ -284,7 +352,7 @@ def buildnRF52832(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF52832 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF52832 - '+key+')', 'Build error', '${BUILD_URL}')
@@ -294,7 +362,7 @@ def buildnRF52832(config, sketches, String key) {
}
def buildnRF51822(config, sketches, String key) {
- def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF51822:chip=xxaa,bootcode=none,lfclk=lfxo -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m0'
+ def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF51822:chip=xxaa,bootcode=none,lfclk=lfxo'
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
try {
buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyBoardNRF5/examples/MyBoardNRF5/MyBoardNRF5.ino', key+'_nRF51822')
@@ -308,7 +376,7 @@ def buildnRF51822(config, sketches, String key) {
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF51822 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
if (config.is_pull_request) {
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
}
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF51822 - '+key+')', 'Build error', '${BUILD_URL}')
diff --git a/.ci/gitler.groovy b/.ci/butler.groovy
similarity index 56%
rename from .ci/gitler.groovy
rename to .ci/butler.groovy
index 5200411a0..6ae3deb47 100644
--- a/.ci/gitler.groovy
+++ b/.ci/butler.groovy
@@ -1,6 +1,6 @@
#!groovy
def call(config) {
- config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Gitler)', 'Checking...', '${BUILD_URL}flowGraphTable/')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Butler)', 'Checking...', '${BUILD_URL}flowGraphTable/')
if (env.CHANGE_TARGET == 'master' &&
(env.CHANGE_AUTHOR != 'bblacey' && env.CHANGE_AUTHOR != 'd00616' &&
env.CHANGE_AUTHOR != 'fallberg' && env.CHANGE_AUTHOR != 'henrikekblad' &&
@@ -9,13 +9,47 @@ def call(config) {
env.CHANGE_AUTHOR != 'tekka007' && env.CHANGE_AUTHOR != 'user2684' &&
env.CHANGE_AUTHOR != 'Yveaux'))
{
- config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'This pull request targets master. That is not permitted for '+env.CHANGE_AUTHOR, '')
+ config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'This pull request targets master. I am afraid that is not permitted for '+env.CHANGE_AUTHOR, '')
error "This pull request targets master. That is not permitted!"
}
else if (env.CHANGE_TARGET == 'master')
{
echo env.CHANGE_AUTHOR + ' is a valid author for targeting master branch, skipping further validation'
- config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '')
+ dir(config.repository_root) {
+ step([$class: 'GitChangelogRecorder', config: [configFile: 'git-changelog-settings.json',
+ createFileTemplateContent: '''
+# Changelog
+{{#commits}}
+### {{{messageTitle}}}
+{{{messageBody}}}
+[{{hash}}](https://github.com/mysensors/MySensors/commit/{{hash}}) by {{authorName}} at *{{commitTime}}*
+{{/commits}}
+''',
+ createFileTemplateFile: '', createFileUseTemplateContent: true,
+ createFileUseTemplateFile: false, customIssues: [[link: '', name: '', pattern: '', title: ''],
+ [link: '', name: '', pattern: '', title: '']], dateFormat: 'YYYY-MM-dd HH:mm:ss',
+ file: 'ReleaseNotes.md', fromReference: env.CHANGE_TARGET, fromType: 'ref', gitHubApi: '',
+ gitHubApiTokenCredentialsId: '', gitHubIssuePattern: '#([0-9]+)', gitHubToken: '',
+ gitLabApiTokenCredentialsId: '', gitLabProjectName: '', gitLabServer: '', gitLabToken: '',
+ ignoreCommitsIfMessageMatches: '^Merge.*',
+ ignoreCommitsWithoutIssue: false, ignoreTagsIfNameMatches: '',
+ jiraIssuePattern: '\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b', jiraPassword: '', jiraServer: '',
+ jiraUsername: '', jiraUsernamePasswordCredentialsId: '', mediaWikiPassword: '',
+ mediaWikiTemplateContent: '', mediaWikiTemplateFile: '', mediaWikiTitle: '', mediaWikiUrl: '',
+ mediaWikiUseTemplateContent: false, mediaWikiUseTemplateFile: false, mediaWikiUsername: '',
+ noIssueName: 'No issue', readableTagName: '/([^/]+?)$', showSummary: false,
+ showSummaryTemplateContent: '', showSummaryTemplateFile: '', showSummaryUseTemplateContent: false,
+ showSummaryUseTemplateFile: false, subDirectory: '', timeZone: 'UTC',
+ toReference: config.git_sha, toType: 'commit', untaggedName: 'Unreleased',
+ useConfigFile: false, useFile: true, useGitHub: true, useGitHubApiTokenCredentials: false,
+ useGitLab: false, useGitLabApiTokenCredentials: false, useIgnoreTagsIfNameMatches: false,
+ useJira: false, useJiraUsernamePasswordCredentialsId: false, useMediaWiki: false,
+ useReadableTagName: false, useSubDirectory: false]
+ ])
+ }
+
+ config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done!', '')
+ config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Release changelog)', '', '${BUILD_URL}execution/node/3/ws/MySensors/ReleaseNotes.md/*view*/')
return
}
@@ -51,7 +85,7 @@ def call(config) {
createFileTemplateContent: '''
{{#commits}}
{{#messageBodyItems}}
-{{.}}
+{{.}}
{{/messageBodyItems}}
{{/commits}}
''',
@@ -81,31 +115,35 @@ def call(config) {
ret = sh(returnStatus: true,
script:"""#!/bin/bash
cd ${config.repository_root}/.ci
- ./gitler.sh""")
+ ./butler.sh""")
if (fileExists(config.repository_root+'restyling.patch')) {
emailext (
- subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} [PR#${env.CHANGE_ID}]' failed due to bad code styling",
- body: """
Job '${env.JOB_NAME} [PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}]' failed because code style does not follow the standards.
- A patch to rectify the errors is attached. You apply the patch using:
+ subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} has unfortunate code styling",
+ body: """Greetings!
+ I am afraid your pull request does not follow the MySensors standards with respect to coding style.
+ That is ok, you are perhaps a first time committer to this repository. Please read the code contribution guidelines for help on how to format your code.
+ To assist you, I have prepared a patch for you that will reformat the code according to the coding style required.
+ The patch is attached. You may apply the patch using:
git apply restyling.patch
- If you disagree to this, please discuss it here.
- Yours sincerely, Gitler, on behalf of Jenkins""",
- mimeType: 'text/html', to: '${env.CHANGE_AUTHOR_EMAIL}',
+ If you disagree with me, please discuss it here.
+ --
+ Yours sincerely, The Butler, serving the MySensors community""",
+ mimeType: 'text/html', to: env.CHANGE_AUTHOR_EMAIL,
attachLog: false, compressLog: false, attachmentsPattern: config.repository_root+'restyling.patch'
)
}
publishHTML([allowMissing: true, alwaysLinkToLastBuild: false, keepAll: true,
reportDir: config.repository_root,
- reportFiles: 'gitler.html', reportName: 'Gitler report', reportTitles: ''])
+ reportFiles: 'butler.html', reportName: 'The Butler report', reportTitles: ''])
if (ret == 1) {
- config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'Commit(s) does not meet coding standards', '${BUILD_URL}Gitler_report/gitler.html')
+ config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'I am afraid the commit(s) needs some touchup, please check the details...', '${BUILD_URL}The_20Butler_20report/butler.html')
currentBuild.currentResult == 'FAILURE'
- echo "Termiated due to Gitler assert" // For BFA
- echo "You can read the detailed error report here: "+env.BUILD_URL+"Gitler_report/"
- error 'Termiated due to Gitler assert'
+ echo "Terminated due to Butler assert" // For BFA
+ echo "You can read the detailed error report here: "+env.BUILD_URL+"The_20Butler_20report/"
+ error 'Terminated due to Butler assert'
} else {
- config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '')
+ config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done!', '${BUILD_URL}The_20Butler_20report/butler.html')
}
}
diff --git a/.ci/butler.sh b/.ci/butler.sh
new file mode 100755
index 000000000..3fdce1710
--- /dev/null
+++ b/.ci/butler.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+# Yes, this script can be improved immensly...
+cd ..
+
+result=0
+
+echo "No subjects are of invalid size
" > too_long_subjects.txt
+echo "No subjects with leading lower case characters
" > leading_lowercases.txt
+echo "No subjects with trailing periods
" > trailing_periods.txt
+echo "No body lines are too wide
" > too_long_body_lines.txt
+echo "No keywords are missing in keywords.txt
" > missing_keywords.txt
+echo "No occurences of the deprecated boolean data type
" >> booleans.txt
+
+too_long_subjects=`awk 'length > 72' subjects.txt`
+if [ -n "$too_long_subjects" ]; then
+ echo "Commit subjects that are too wide (>72 characters):" > too_long_subjects.txt
+ echo "$too_long_subjects" >> too_long_subjects.txt
+ sed -i -e 's/$/
/' too_long_subjects.txt
+ result=1
+fi
+leading_lowercases=`awk '/^[[:lower:][:punct:]]/' subjects.txt`
+if [ -n "$leading_lowercases" ]; then
+ echo "Commit subjects with leading lowercase characters:" > leading_lowercases.txt
+ echo "$leading_lowercases" >> leading_lowercases.txt
+ sed -i -e 's/$/
/' leading_lowercases.txt
+ result=1
+fi
+trailing_periods=`awk '/(\.)$/' subjects.txt`
+if [ -n "$trailing_periods" ]; then
+ echo "Commit subjects with trailing periods:" > trailing_periods.txt
+ echo "$trailing_periods" >> trailing_periods.txt
+ sed -i -e 's/$/
/' trailing_periods.txt
+ result=1
+fi
+
+too_long_body_lines=`awk 'length > 72' bodies.txt`
+if [ -n "$too_long_body_lines" ]; then
+ echo "Body lines that are too wide (>72 characters):" > too_long_body_lines.txt
+ echo "$too_long_body_lines" >> too_long_body_lines.txt
+ sed -i -e 's/$/
/' too_long_body_lines.txt
+ result=1
+fi
+
+missing_keywords=$(for keyword in $(grep -A999 '#if DOXYGEN' MyConfig.h | grep -B999 '#endif' | grep '#define' | awk '{ print $2 '} | grep -e '^MY_'); do grep -q $keyword keywords.txt || echo $keyword; done)
+if [ -n "$missing_keywords" ]; then
+ echo "Keywords that are missing from keywords.txt:" > missing_keywords.txt
+ echo "$missing_keywords" >> missing_keywords.txt
+ sed -i -e 's/$/
/' missing_keywords.txt
+ result=1
+fi
+
+# Evaluate if there exists booleans in the code tree (not counting this file)
+if git grep -q boolean -- `git ls-files | grep -v butler.sh`; then
+ echo "You have added at least one occurence of the deprecated boolean data type. Please use bool instead.
" > booleans.txt
+ result=1
+fi
+
+printf "%s" "" > butler.html
+echo "Greetings! Here is my evaluation of your pull request:
" >> butler.html
+awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt missing_keywords.txt booleans.txt >> butler.html
+echo "
" >> butler.html
+if [ $result -ne 0 ]; then
+ echo "I am afraid there are some issues with your commit messages and/or use of keywords.
" >> butler.html
+ echo "I highly recommend reading this guide for tips on how to write a good commit message.
" >> butler.html
+ echo "More specifically, MySensors have some code contribution guidelines that I am afraid all contributers need to follow.
" >> butler.html
+ echo "
" >> butler.html
+ echo "I can help guide you in how to change the commit message for a single-commit pull request:
" >> butler.html
+ echo "git checkout <your_branch>
" >> butler.html
+ echo "git commit --amend
" >> butler.html
+ echo "git push origin HEAD:<your_branch_on_github> -f
" >> butler.html
+ echo "
" >> butler.html
+ echo "To change the commit messages for a multiple-commit pull request:
" >> butler.html
+ echo "git checkout <your_branch>
" >> butler.html
+ echo "git rebase -i <sha_of_parent_to_the_earliest_commit_you_want_to_change>
" >> butler.html
+ echo "Replace \"pick\" with \"r\" or \"reword\" on the commits you need to change message for
" >> butler.html
+ echo "git push origin HEAD:<your_branch_on_github> -f
" >> butler.html
+ echo "
" >> butler.html
+fi
+
+# Evaluate coding style
+astyle --options=.mystools/astyle/config/style.cfg -nq --recursive "*.h" "*.c" "*.cpp"
+git diff > restyling.patch
+if [ -s restyling.patch ]; then
+ echo "I am afraid your coding style is not entirely in line with the MySensors preffered style.
A mail with a patch has been sent to you that, if applied to your PR, will make it follow the MySensors coding standards.
" >> butler.html
+ echo "You can apply the patch using:
" >> butler.html
+ echo "git apply restyling.patch
" >> butler.html
+ echo "
" >> butler.html
+ result=1
+else
+ echo "This commit is meeting the coding standards, well done!
" >> butler.html
+ echo "
" >> butler.html
+ rm restyling.patch
+fi
+
+if [ $result -ne 0 ]; then
+ echo "If you have any questions, please first read the code contribution guidelines.
" >> butler.html
+ echo "If you disagree to this, please discuss it in the GitHub pull request thread.
" >> butler.html
+ echo "
" >> butler.html
+fi
+echo "Yours sincerely, The Butler, serving the MySensors community
" >> butler.html
+printf "%s" "" >> butler.html
+exit $result
diff --git a/.ci/doxygen.groovy b/.ci/doxygen.groovy
index efab0234a..9e68b3817 100644
--- a/.ci/doxygen.groovy
+++ b/.ci/doxygen.groovy
@@ -6,7 +6,7 @@ def call(config) {
Documentation/doxygen.sh"""
warnings canComputeNew: false, canResolveRelativePaths: false,
defaultEncoding: '',
- excludePattern: '''.*/sha204_library\\.h,.*/drivers/Linux/.*,.*/cores/esp8266/.*,hardware/.*''',
+ excludePattern: '''.*/sha204_library\\.h,.*/drivers/Linux/.*,.*/drivers/TinyGSM/.*,.*/cores/esp8266/.*,hardware/.*''',
failedTotalAll: '', healthy: '', includePattern: '', messagesPattern: '',
parserConfigurations: [[parserName: 'Doxygen', pattern: config.repository_root+'doxygen.log']],
unHealthy: '', unstableTotalAll: '0'
@@ -19,7 +19,7 @@ def call(config) {
// Publish docs to API server
if (env.BRANCH_NAME == 'master') {
sh """#!/bin/bash
- scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io"""
+ scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io:"""
} else if (env.BRANCH_NAME == 'development') {
sh """#!/bin/bash
scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io:beta"""
diff --git a/.ci/gitler.sh b/.ci/gitler.sh
deleted file mode 100755
index 5d815e609..000000000
--- a/.ci/gitler.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-# Yes, this script can be improved immensly...
-cd ..
-
-result=0
-
-echo "No subjects are of invalid size
" > too_long_subjects.txt
-echo "No subjects with leading lower case characters
" > leading_lowercases.txt
-echo "No subjects with trailing periods
" > trailing_periods.txt
-echo "No body lines are too wide
" > too_long_body_lines.txt
-
-too_long_subjects=`awk 'length > 72' subjects.txt`
-if [ -n "$too_long_subjects" ]; then
- echo "Commit subjects that are too wide (>72 characters):" > too_long_subjects.txt
- echo "$too_long_subjects" >> too_long_subjects.txt
- sed -i -e 's/$/
/' too_long_subjects.txt
- result=1
-fi
-leading_lowercases=`awk '/^[[:lower:][:punct:]]/' subjects.txt`
-if [ -n "$leading_lowercases" ]; then
- echo "Commit subjects with leading lowercase characters:" > leading_lowercases.txt
- echo "$leading_lowercases" >> leading_lowercases.txt
- sed -i -e 's/$/
/' leading_lowercases.txt
- result=1
-fi
-trailing_periods=`awk '/(\.)$/' subjects.txt`
-if [ -n "$trailing_periods" ]; then
- echo "Commit subjects with trailing periods:" > trailing_periods.txt
- echo "$trailing_periods" >> trailing_periods.txt
- sed -i -e 's/$/
/' trailing_periods.txt
- result=1
-fi
-
-too_long_body_lines=`awk 'length > 72' bodies.txt`
-if [ -n "$too_long_body_lines" ]; then
- echo "Body lines that are too wide (>72 characters):" > too_long_body_lines.txt
- echo "$too_long_body_lines" >> too_long_body_lines.txt
- sed -i -e 's/$/
/' too_long_body_lines.txt
- result=1
-fi
-
-printf "%s" "" > gitler.html
-awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt >> gitler.html
-echo "
" >> gitler.html
-if [ $result -ne 0 ]; then
- echo "You should follow this guide when writing your commit messages.
" >> gitler.html
- echo "
" >> gitler.html
- echo "To change the commit message for a single-commit pull request:
" >> gitler.html
- echo "git checkout <your_branch>
" >> gitler.html
- echo "git commit --amend
" >> gitler.html
- echo "git push origin HEAD:<your_branch_on_github> -f
" >> gitler.html
- echo "
" >> gitler.html
- echo "To change the commit messages for a multiple-commit pull request:
" >> gitler.html
- echo "git checkout <your_branch>
" >> gitler.html
- echo "git rebase -i <sha_of_parent_to_the_earliest_commit_you_want_to_change>
" >> gitler.html
- echo "Replace \"pick\" with \"r\" or \"reword\" on the commits you need to change message for
" >> gitler.html
- echo "git push origin HEAD:<your_branch_on_github> -f
" >> gitler.html
- echo "
" >> gitler.html
-fi
-
-# Evaluate coding style
-astyle --options=.mystools/astyle/config/style.cfg -nq --recursive "*.h" "*.c" "*.cpp"
-git diff > restyling.patch
-if [ -s restyling.patch ]; then
- echo "This commit is not meeting the coding standards, a mail with a patch has been sent to you that if applied to your PR, will make it meet the coding standards.
" >> gitler.html
- echo "You apply the patch using:
" >> gitler.html
- echo "git apply restyling.patch
" >> gitler.html
- echo "
" >> gitler.html
- result=1
-else
- echo "This commit is meeting the coding standards, congratulations!
" >> gitler.html
- echo "
" >> gitler.html
- rm restyling.patch
-fi
-
-# Evaluate if there exists booleans in the code tree (not counting this file)
-if git grep -q boolean -- `git ls-files | grep -v gitler.sh`
-then
- echo "This repository currently contain the boolean keyword. This should be avoided.
" >> gitler.html
- echo "
" >> gitler.html
- result=1
-else
- echo "This repository does not contain any boolean keywords. This is good.
" >> gitler.html
- echo "
" >> gitler.html
-fi
-
-if [ $result -ne 0 ]; then
- echo "If you disagree to this, please discuss it in the GitHub pull request thread.
" >> gitler.html
- echo "
" >> gitler.html
-fi
-echo "Yours sincerely, Gitler, on behalf of Jenkins
" >> gitler.html
-printf "%s" "" >> gitler.html
-exit $result
diff --git a/.ci/linux.groovy b/.ci/linux.groovy
index 672a530bf..991fed117 100644
--- a/.ci/linux.groovy
+++ b/.ci/linux.groovy
@@ -34,7 +34,7 @@ def buildSerial(config) {
buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=serial', 'Serial')
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Serial GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Serial GW)', 'Build error', '${BUILD_URL}')
} else {
@@ -47,7 +47,7 @@ def buildEthernet(config) {
buildLinux(config, '--my-debug=enable --my-transport=rs485 --my-gateway=ethernet', 'Ethernet')
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Ethernet GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Ethernet GW)', 'Build error', '${BUILD_URL}')
} else {
@@ -60,7 +60,7 @@ def buildMQTT(config) {
buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=mqtt', 'MQTT')
if (currentBuild.currentResult == 'UNSTABLE') {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - MQTT GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
- error 'Termiated due to warnings found'
+ error 'Terminated due to warnings found'
} else if (currentBuild.currentResult == 'FAILURE') {
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - MQTT GW)', 'Build error', '${BUILD_URL}')
} else {
diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy
index 36b99516f..78e36e3df 100644
--- a/.ci/pipeline.groovy
+++ b/.ci/pipeline.groovy
@@ -12,11 +12,43 @@ def call(Closure body) {
if (env.CHANGE_ID) {
config.is_pull_request = true
- echo "Building pull request: #"+env.CHANGE_ID+"\nTarget branch: "+env.CHANGE_TARGET
+ echo "Building pull request: #"+env.CHANGE_ID+"\nTarget branch: "+env.CHANGE_TARGET+"\nAuthor: "+env.CHANGE_AUTHOR+" ("+env.CHANGE_AUTHOR_EMAIL+")"
config.git_sha = sh(returnStdout: true,
script: """#!/bin/bash
cd ${config.repository_root}
git log -n 1 --pretty=format:'%H' refs/remotes/origin/PR-${env.CHANGE_ID}""").trim()
+ // Pre-register all build statues so github shows what is going to happen
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate', 'Validating...', '${BUILD_URL}flowGraphTable/')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Butler)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Code analysis - Cppcheck)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Documentation)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Serial GW)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Ethernet GW)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - MQTT GW)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (STM32F1 - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - Tests)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - Examples)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - Examples)', 'Not run yet...', '')
+/*
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - Examples)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - Examples)', 'Not run yet...', '')
+*/
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - Examples)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - Examples)', 'Not run yet...', '')
+/*
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - Examples)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (STM32F1 - Examples)', 'Not run yet...', '')
+*/
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - Examples)', 'Not run yet...', '')
+ config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - Examples)', 'Not run yet...', '')
} else {
config.is_pull_request = false
echo "Building branch: "+env.BRANCH_NAME
@@ -24,15 +56,14 @@ def call(Closure body) {
script: """#!/bin/bash
cd ${config.repository_root}
git log -n 1 --pretty=format:'%H' refs/remotes/origin/${env.BRANCH_NAME}""").trim()
- config.pr.setBuildStatus(config, 'PENDING', 'Toll gate', 'Validating...', '${BUILD_URL}flowGraphTable/')
}
try {
ansiColor('xterm') {
if (config.is_pull_request) {
- def gitler = load(config.repository_root+'.ci/gitler.groovy')
- stage('Gitler') {
- gitler(config)
+ def butler = load(config.repository_root+'.ci/butler.groovy')
+ stage('Butler') {
+ butler(config)
}
}
@@ -58,7 +89,7 @@ def call(Closure body) {
config.tests = findFiles(glob: config.library_root+'tests/**/*.ino')
config.examples = findFiles(glob: config.library_root+'examples/**/*.ino')
-
+
}
parallel Doxygen: {
@@ -97,6 +128,9 @@ def call(Closure body) {
stage('MySensorsGW (tests)') {
arduino.buildMySensorsGw(config, config.tests, 'Tests')
}
+ stage('ESP32 (tests)') {
+ arduino.buildESP32(config, config.tests, 'Tests')
+ }
stage('nRF52832 (tests)') {
arduino.buildnRF52832(config, config.tests, 'Tests')
}
@@ -107,7 +141,7 @@ def call(Closure body) {
arduino.buildnRF5(config, config.tests, 'Tests')
}
stage('ESP8266 (tests)') {
- arduino.buildEsp8266(config, config.tests, 'Tests')
+ arduino.buildESP8266(config, config.tests, 'Tests')
}
stage('STM32F1 (tests)') {
arduino.buildSTM32F1(config, config.tests, 'Tests')
@@ -140,13 +174,18 @@ def call(Closure body) {
arduino.buildnRF5(config, config.examples, 'Examples')
}
stage('ESP8266 (examples)') {
- arduino.buildEsp8266(config, config.examples, 'Examples')
+ arduino.buildESP8266(config, config.examples, 'Examples')
}
+ // No point in building examples for ESP32 yet
+ /*
+ stage('ESP32 (examples)') {
+ arduino.buildESP32(config, config.examples, 'Examples')
+ }
+ */
// No point in building examples for STM32F1 yet
/*
stage('STM32F1 (Examples)') {
arduino.buildSTM32F1(config, config.tests, 'Examples')
- }
*/
stage('ArduinoUno (examples)') {
arduino.buildArduinoUno(config, config.examples, 'Examples')
@@ -166,20 +205,37 @@ def call(Closure body) {
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate', 'Failed', '${BUILD_URL}flowGraphTable/')
if (config.is_pull_request) {
slackSend color: 'danger',
- message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>' failed with result ${currentBuild.result}."
+ message: "Failed to build <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}."
emailext (
- subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER}' failed",
- body: """Job '${env.JOB_NAME} #${env.BUILD_NUMBER} (PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE})' ended with result ${currentBuild.result}.
-
Check attached console output or here for a hint on what the problem might be.""",
+ subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} failed to build",
+ body: '''Greetings!
+ I am The Butler. My task is to help you create a pull request that fit the MySensors organizations coding style and builds for all supported platforms.
+ I am afraid I failed to validate your pull request. Result was '''+currentBuild.result+'''.
+
Please check the attached build log or here for a hint on what the problem might be.
+ If you have difficulties determining the cause for the failure, feel free to ask questions here.
+ Changes:
+ ${CHANGES}
+ Notable build log lines:
+ ${BUILD_LOG_REGEX, regex="^.*?Terminated.*?$", linesBefore=0, linesAfter=0, maxMatches=5, showTruncatedLines=false, escapeHtml=true}
+ My personal evaluation of your pull request is available here.
+ --
+ Yours sincerely, The Butler, serving the MySensors community''',
mimeType: 'text/html', to: env.CHANGE_AUTHOR_EMAIL, attachLog: true, compressLog: false
)
} else {
slackSend color: 'danger',
- message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> ${env.BRANCH_NAME}]' failed with result ${currentBuild.result}."
+ message: "Failed to build branch ${env.BRANCH_NAME}. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}."
emailext (
- subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} ${env.BRANCH_NAME}' failed",
- body: """Job '${env.JOB_NAME} #${env.BUILD_NUMBER} (${env.BRANCH_NAME})' ended with result ${currentBuild.result}.
-
Check attached console output or here for a hint on what the problem might be.""",
+ subject: "MySensors branch ${env.BRANCH_NAME} failed to build",
+ body: '''I am afraid I failed to build branch ${BRANCH_NAME}. Result was '''+currentBuild.result+'''.
+
Please check the attached build log or here for a hint on what the problem might be.
+ Changes:
+ ${CHANGES}
+ Notable build log lines:
+ ${BUILD_LOG_REGEX, regex="^.*?Terminated.*?$", linesBefore=0, linesAfter=0, maxMatches=5, showTruncatedLines=false, escapeHtml=true}
+ My personal evaluation of your pull request is available here.
+ --
+ Yours sincerely, The Butler, serving the MySensors community''',
mimeType: 'text/html', to: 'builds@mysensors.org', attachLog: true, compressLog: false
)
}
@@ -190,4 +246,4 @@ def call(Closure body) {
}
}
}
-return this
\ No newline at end of file
+return this
diff --git a/.ci/static_analysis.groovy b/.ci/static_analysis.groovy
index fbd3fe5ca..642176e1a 100644
--- a/.ci/static_analysis.groovy
+++ b/.ci/static_analysis.groovy
@@ -29,7 +29,7 @@ def cppCheck(config) {
"grep -q \"
0 | total | \" cppcheck-avr_cppcheck_reports/index.html || exit_code=\$?\n"+
"exit \$((exit_code == 0 ? 0 : 1))")
if (ret == 1) {
- config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Code analysis - Cppcheck)', 'Issues found', '${BUILD_URL}CppCheck_AVR/index.html')
+ config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Code analysis - Cppcheck)', 'Issues found', '${BUILD_URL}CppCheck_20AVR/index.html')
error 'Terminating due to Cppcheck error'
} else {
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Code analysis - Cppcheck)', 'Pass', '')
diff --git a/.mystools/cppcheck/config/suppressions.cfg b/.mystools/cppcheck/config/suppressions.cfg
index 6a8b58500..18171c423 100644
--- a/.mystools/cppcheck/config/suppressions.cfg
+++ b/.mystools/cppcheck/config/suppressions.cfg
@@ -1,4 +1,4 @@
ConfigurationNotChecked
unmatchedSuppression
// This suppression is because the problem is in an in-lined macro so in-line-suppressions does not appear to take effect
-unreadVariable:*/MyHwNRF5.cpp
\ No newline at end of file
+unreadVariable:*/MyHwNRF5.cpp
diff --git a/.mystools/hooks/commit-msg.sh b/.mystools/hooks/commit-msg.sh
new file mode 100644
index 000000000..4b5f780ab
--- /dev/null
+++ b/.mystools/hooks/commit-msg.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+too_long_lines=$(awk 'length>72' $1)
+if [[ ! -z $too_long_lines ]]; then
+ echo "Too long commit message lines:" $too_long_lines
+ has_failed=1
+fi
+
+leading_lowercases=$(awk 'NR==1' $1 | awk '/^[[:lower:][:punct:]]/')
+if [[ ! -z $leading_lowercases ]]; then
+ echo "Leading lowercase in subject:" $leading_lowercases
+ has_failed=1
+fi
+
+trailing_periods=$(awk 'NR==1' $1 | awk '/(\.)$/')
+if [[ ! -z $trailing_periods ]]; then
+ echo "Trailing periods in subject:" $trailing_periods
+ has_failed=1
+fi
+
+if [[ ! -z $has_failed ]]; then
+ echo "Please recommit with a new commit message."
+ exit 1
+fi
diff --git a/Documentation/doxygen.sh b/Documentation/doxygen.sh
index a724bd161..8fcf4de09 100755
--- a/Documentation/doxygen.sh
+++ b/Documentation/doxygen.sh
@@ -3,17 +3,11 @@
# Generate doxygen file for Raspberry Pi configure command
echo -e "/**\n * @defgroup RaspberryPiGateway Raspberry Pi Gateway\n * @ingroup MyConfigGrp\n * @brief Configuration options for the Raspberry Pi Gateway\n@{\n@verbatim" > configure.h
- grep -A999 '<> configure.h
- echo -e "@endverbatim\n@}*/\n" >> configure.h
+./configure --help >> configure.h
+echo -e "@endverbatim\n@}*/\n" >> configure.h
# Generate version information
-export PROJECTNUMBER=$(
- if [[ $(git rev-parse --abbrev-ref HEAD) == "master" ]]; then
- git describe --tags ;
- else
- git rev-parse --short HEAD ;
- fi
-)
+export PROJECTNUMBER=$(git fetch --tags; git describe --tags;)
# Generate any UML diagrams in the code tree that has the proper tags
export PLANTUML_JAR_PATH=Documentation/plantuml.jar
diff --git a/Documentation/mainpage.dox b/Documentation/mainpage.dox
index 273f2cb63..7d16379ea 100644
--- a/Documentation/mainpage.dox
+++ b/Documentation/mainpage.dox
@@ -5,7 +5,7 @@ Are you a sketch developer/user, see @ref publics
Are you a core/library developer, see @ref internals
-@copyright (C) 2013-2017 Sensnology AB
+@copyright (C) 2013-2018 Sensnology AB
Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*/
diff --git a/MyConfig.h b/MyConfig.h
index 598b686bc..5c2098725 100644
--- a/MyConfig.h
+++ b/MyConfig.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -243,6 +243,8 @@
/**
* @def MY_RS485_HWSERIAL
* @brief Define this if RS485 is connected to a hardware serial port.
+ *
+ * Example: @code #define MY_RS485_HWSERIAL Serial1 @endcode
*/
//#define MY_RS485_HWSERIAL (Serial1)
/** @}*/ // End of RS485SettingGrpPub group
@@ -572,7 +574,7 @@
/**
* @def MY_RADIO_RFM69
- * @brief Define this to use RFM69 based radios for sensor network communication.
+ * @brief Define this to use %RFM69 based radios for sensor network communication.
*/
//#define MY_RADIO_RFM69
@@ -600,6 +602,7 @@
* @def MY_RFM69_FREQUENCY
* @brief The frequency to use.
*
+ * - RFM69_315MHZ
* - RFM69_433MHZ
* - RFM69_868MHZ
* - RFM69_915MHZ
@@ -641,7 +644,7 @@
/**
* @def MY_RFM69_ATC_TARGET_RSSI_DBM
- * @brief Target RSSI level (in dBm) for RFM69 ATC mode.
+ * @brief Target RSSI level (in dBm) for %RFM69 ATC mode.
*/
#ifndef MY_RFM69_ATC_TARGET_RSSI_DBM
#define MY_RFM69_ATC_TARGET_RSSI_DBM (-80)
@@ -649,7 +652,7 @@
/**
* @def MY_RFM69_ATC_MODE_DISABLED
- * @brief Define to disable ATC mode of RFM69 driver.
+ * @brief Define to disable ATC mode of %RFM69 driver.
*/
//#define MY_RFM69_ATC_MODE_DISABLED
@@ -668,7 +671,7 @@
/**
* @def MY_RFM69_NETWORKID
- * @brief RFM69 Network ID. Use the same for all nodes that will talk to each other.
+ * @brief %RFM69 Network ID. Use the same for all nodes that will talk to each other.
*/
#ifndef MY_RFM69_NETWORKID
#define MY_RFM69_NETWORKID (100)
@@ -682,6 +685,7 @@
#ifdef MY_RF69_RESET
// legacy, older board files
+// not enabled now: #warning MY_RF69_RESET is depreciated, please use MY_RFM69_RST_PIN instead.
#define MY_RFM69_RST_PIN MY_RF69_RESET
#endif
@@ -693,11 +697,12 @@
/**
* @def MY_RFM69_IRQ_PIN
- * @brief Define this to use the %RFM69 IRQ pin (optional).
+ * @brief Define this to override the default %RFM69 IRQ pin assignment.
*/
#ifndef MY_RFM69_IRQ_PIN
#ifdef MY_RF69_IRQ_PIN
// legacy, older board files
+// not enabled now: #warning MY_RF69_IRQ_PIN is depreciated, please use MY_RFM69_IRQ_PIN instead.
#define MY_RFM69_IRQ_PIN MY_RF69_IRQ_PIN
#else
#define MY_RFM69_IRQ_PIN DEFAULT_RFM69_IRQ_PIN
@@ -711,19 +716,21 @@
#ifndef MY_RFM69_IRQ_NUM
#ifdef MY_RF69_IRQ_NUM
// legacy, older board files
+// not enabled now: #warning MY_RF69_IRQ_NUM is depreciated, please use MY_RFM69_IRQ_NUM instead.
#define MY_RFM69_IRQ_NUM MY_RF69_IRQ_NUM
#else
-#define MY_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_NUM
+#define MY_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN)
#endif
#endif
/**
* @def MY_RFM69_CS_PIN
- * @brief RFM69 SPI chip select pin.
+ * @brief %RFM69 SPI chip select pin.
*/
#ifndef MY_RFM69_CS_PIN
#ifdef MY_RF69_SPI_CS
// legacy, older board files
+// not enabled now: #warning MY_RF69_SPI_CS is depreciated, please use MY_RFM69_CS_PIN instead.
#define MY_RFM69_CS_PIN MY_RF69_SPI_CS
#else
#define MY_RFM69_CS_PIN DEFAULT_RFM69_CS_PIN
@@ -764,29 +771,29 @@
#define MY_RFM69_DEFAULT_LISTEN_IDLE_US (1*1000000ul)
#endif
-#if !defined(MY_RFM69_BITRATE_MSB) && !defined(MY_RFM69_BITRATE_LSB)
/**
- * @def MY_RFM69_BITRATE_MSB
- * @brief %RFM69 bit rate (most significant bits)
+ * @def MY_RFM69_MODEM_CONFIGURATION
+ * @brief %RFM69 modem configuration, default is %RFM69_FSK_BR55_5_FD50
*
- * Bitrate between the transmitter and the receiver must be better than 6.5.
- * Refer to RFM69registers_old.h (L.153) or RFM69registers_new.h (L.154) for settings or
- * http://www.semtech.com/apps/filedown/down.php?file=sx1231.pdf
- * @note RFM69_FOSC(Hz)/MSB_LSBVALUE = Bitrate in kbits
+ * | Configuration | Modulation (xxx) | Bit rate | FD | RXBW | Additional settings
+ * |-------------------------|------------------|----------|--------|----------|---------------------------
+ * | RFM69_xxx_BR2_FD5 | FSK/GFSK/OOK | 2000 | 5000 | 111_24_4 | Whitening
+ * | RFM69_xxx_BR2_4_FD4_8 | FSK/GFSK/OOK | 2400 | 4800 | 111_24_4 | Whitening
+ * | RFM69_xxx_BR4_8_FD9_6 | FSK/GFSK/OOK | 4800 | 9600 | 111_24_4 | Whitening
+ * | RFM69_xxx_BR9_6_FD19_2 | FSK/GFSK/OOK | 9600 | 19200 | 111_24_4 | Whitening
+ * | RFM69_xxx_BR19_2_FD38_4 | FSK/GFSK/OOK | 19200 | 38400 | 111_24_3 | Whitening
+ * | RFM69_xxx_BR38_4_FD76_8 | FSK/GFSK/OOK | 38400 | 76800 | 111_24_2 | Whitening
+ * | RFM69_xxx_BR55_5_FD50 | FSK/GFSK/OOK | 55555 | 50000 | 111_16_2 | Whitening
+ * | RFM69_xxx_BR57_6_FD120 | FSK/GFSK/OOK | 57600 | 120000 | 111_16_1 | Whitening
+ * | RFM69_xxx_BR125_FD125 | FSK/GFSK/OOK | 125000 | 125000 | 010_16_2 | Whitening
+ * | RFM69_xxx_BR250_FD250 | FSK/GFSK/OOK | 250000 | 250000 | 111_16_0 | Whitening
*
- */
-#define MY_RFM69_BITRATE_MSB (RFM69_BITRATEMSB_55555)
-/**
- * @def MY_RFM69_BITRATE_LSB
- * @brief %RFM69 bit rate (least significant bits)
+ * https://www.semtech.com/uploads/documents/sx1231.pdf
*
- * Bitrate between the transmitter and the receiver must be better than 6.5.
- * Refer to RFM69registers_old.h (L.153) or RFM69registers_new.h (L.154) for settings or
- * http://www.semtech.com/apps/filedown/down.php?file=sx1231.pdf
- * @note RFM69_FOSC(Hz)/MSB_LSBVALUE = Bitrate in kbits
*/
-#define MY_RFM69_BITRATE_LSB (RFM69_BITRATELSB_55555)
-#endif
+//#define MY_RFM69_MODEM_CONFIGURATION (RFM69_FSK_BR55_5_FD50)
+
+
/** @}*/ // End of RFM69SettingGrpPub group
/**
@@ -811,6 +818,18 @@
*/
//#define MY_DEBUG_VERBOSE_RFM95
+/**
+ * @def MY_RFM95_ENABLE_ENCRYPTION
+ * @brief Define this to enable software based %AES encryption.
+ *
+ * All nodes and gateway must have this enabled, and all must be personalized with the same %AES
+ * key.
+ * @see @ref personalization
+ *
+ * @warning This driver always sets the initialization vector to 0 so encryption is weak.
+ */
+//#define MY_RFM95_ENABLE_ENCRYPTION
+
/**
* @def MY_RFM95_FREQUENCY
* @brief The frequency to use.
@@ -863,7 +882,7 @@
/**
* @def MY_RFM95_IRQ_PIN
- * @brief Define this to use the RFM95 IRQ pin (optional).
+ * @brief Define this to use the RFM95 IRQ pin.
*/
#ifndef MY_RFM95_IRQ_PIN
#define MY_RFM95_IRQ_PIN DEFAULT_RFM95_IRQ_PIN
@@ -874,7 +893,7 @@
* @brief RFM95 IRQ number.
*/
#ifndef MY_RFM95_IRQ_NUM
-#define MY_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_NUM
+#define MY_RFM95_IRQ_NUM digitalPinToInterrupt(MY_RFM95_IRQ_PIN)
#endif
/**
@@ -914,7 +933,7 @@
* @brief Target RSSI level (in dBm) for RFM95 ATC mode
*/
#ifndef MY_RFM95_ATC_TARGET_RSSI
-#define MY_RFM95_ATC_TARGET_RSSI (-60)
+#define MY_RFM95_ATC_TARGET_RSSI (-70)
#endif
/**
@@ -1338,14 +1357,26 @@
* @brief Define this for Ethernet GW based on the ENC28J60 module.
* @def MY_GATEWAY_ESP8266
* @brief Define this for Ethernet GW based on the ESP8266.
+ * @def MY_GATEWAY_ESP32
+ * @brief Define this for Ethernet GW based on the ESP32.
* @def MY_GATEWAY_LINUX
* @brief Define this for Ethernet GW based on Linux.
+ * @def MY_GATEWAY_TINYGSM
+ * @brief Define this for Ethernet GW based on GSM modems supported by TinyGSM library.
+ * @def MY_GATEWAY_MQTT_CLIENT
+ * @brief Define this for MQTT client GW.
+ * @def MY_GATEWAY_SERIAL
+ * @brief Define this for Serial GW.
*/
// The gateway options available
//#define MY_GATEWAY_W5100
//#define MY_GATEWAY_ENC28J60
//#define MY_GATEWAY_ESP8266
+//#define MY_GATEWAY_ESP32
//#define MY_GATEWAY_LINUX
+//#define MY_GATEWAY_TINYGSM
+//#define MY_GATEWAY_MQTT_CLIENT
+//#define MY_GATEWAY_SERIAL
/**
@@ -1354,6 +1385,30 @@
*/
//#define MY_DEBUG_VERBOSE_GATEWAY
+/**
+* @def MY_WIFI_SSID
+* @brief SSID of your WiFi network
+*/
+//#define MY_WIFI_SSID "MySSID"
+
+/**
+* @def MY_WIFI_BSSID
+* @brief BSSID of your WiFi network
+*/
+//#define MY_WIFI_BSSID "MyBSSID"
+
+/**
+* @def MY_WIFI_PASSWORD
+* @brief Password of your WiFi network
+*/
+//#define MY_WIFI_PASSWORD "MyVerySecretPassword"
+
+/**
+* @def MY_HOSTNAME
+* @brief Hostname of your device
+*/
+//#define MY_HOSTNAME "MyHostname"
+
/**
* @def MY_PORT
* @brief The Ethernet TCP/UDP port to open on controller or gateway.
@@ -1372,12 +1427,77 @@
*/
//#define MY_MQTT_CLIENT_PUBLISH_RETAIN
+/**
+ * @def MY_MQTT_PASSWORD
+ * @brief Used for authenticated MQTT connections.
+ *
+ * Set if your MQTT broker requires username/password.
+ * Example: @code #define MY_MQTT_PASSWORD "secretpassword" @endcode
+ * @see MY_MQTT_USER
+ */
+//#define MY_MQTT_PASSWORD "secretpassword"
+
+/**
+ * @def MY_MQTT_USER
+ * @brief Used for authenticated MQTT connections.
+ *
+ * Set if your MQTT broker requires username/password.
+ * Example: @code #define MY_MQTT_USER "username" @endcode
+ * @see MY_MQTT_PASSWORD
+ */
+//#define MY_MQTT_USER "username"
+
+/**
+ * @def MY_MQTT_CLIENT_ID
+ * @brief Set client ID for MQTT connections
+ *
+ * This define is mandatory for all MQTT client gateways.
+ * Example: @code #define MY_MQTT_CLIENT_ID "mysensors-1" @endcode
+ */
+//#define MY_MQTT_CLIENT_ID "mysensors-1"
+
+/**
+ * @def MY_MQTT_PUBLISH_TOPIC_PREFIX
+ * @brief Set prefix for MQTT topic to publish to.
+ *
+ * This define is mandatory for all MQTT client gateways.
+ * Example: @code #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" @endcode
+ */
+//#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
+
+/**
+ * @def MY_MQTT_SUBSCRIBE_TOPIC_PREFIX
+ * @brief Set prefix for MQTT topic to subscribe to.
+ *
+ * This define is mandatory for all MQTT client gateways.
+ * Example: @code #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" @endcode
+ */
+//#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
+
/**
* @def MY_IP_ADDRESS
- * @brief Static ip address of gateway (if this is not defined, DHCP will be used).
+ * @brief Static ip address of gateway. If not defined, DHCP will be used.
+ *
+ * Example: @code #define MY_IP_ADDRESS 192,168,178,66 @endcode
*/
//#define MY_IP_ADDRESS 192,168,178,66
+/**
+ * @def MY_IP_GATEWAY_ADDRESS
+ * @brief IP address of your broadband router/gateway, if not using DHCP.
+ *
+ * Example: @code #define MY_IP_GATEWAY_ADDRESS 192,168,1,1 @endcode
+ */
+//#define MY_IP_GATEWAY_ADDRESS 192,168,1,1
+
+/**
+ * @def MY_IP_SUBNET_ADDRESS
+ * @brief Subnet address of your local network, if not using DHCP.
+ *
+ * Example: @code #define MY_IP_SUBNET_ADDRESS 255,255,255,0 @endcode
+ */
+//#define MY_IP_SUBNET_ADDRESS 255,255,255,0
+
/**
* @def MY_USE_UDP
* @brief Enables UDP mode for Ethernet gateway.
@@ -1407,9 +1527,25 @@
* @brief If this is defined, gateway will act as a client trying to contact controller on
* @ref MY_PORT using this IP address.
*
+ * Example: @code #define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 @endcode
+ *
* If left un-defined, gateway acts as server allowing incoming connections.
+ * @see MY_CONTROLLER_URL_ADDRESS
*/
//#define MY_CONTROLLER_IP_ADDRESS 192,168,178,254
+
+/**
+ * @def MY_CONTROLLER_URL_ADDRESS
+ * @brief If this is defined, gateway will act as a client (ethernet or MQTT) trying to
+ * contact controller on the given URL.
+ *
+ * If left un-defined, gateway acts as server allowing incoming connections.
+ * Example: @code #define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org" @endcode
+ * @see MY_CONTROLLER_IP_ADDRESS
+ * @see MY_GATEWAY_MQTT_CLIENT
+ */
+//#define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org"
+
/** @}*/ // End of GatewaySettingGrpPub group
/**
@@ -1476,12 +1612,46 @@
* @ingroup MyConfigGrp
* @brief These options control security related configurations.
*
- * Note that some encryption configurations are on a per-radio basis as these are specific to each
- * radio.
+ * Overview over all security related settings and how/where to apply them:
+ * | Setting | Description | Arduino | Raspberry PI @c configure argument
+ * |--------------------------|-------------|---------|-------------
+ * | @ref MY_SECURITY_SIMPLE_PASSWD | Enables security (signing and encryption) without the need for @ref personalization | "#define" in the top of your sketch | Not supported (use the other two "simple" options)
+ * | @ref MY_SIGNING_SIMPLE_PASSWD | Enables signing without the need for @ref personalization | "#define" in the top of your sketch | @verbatim --my-signing=password --my-security-password= @endverbatim
+ * | @ref MY_ENCRYPTION_SIMPLE_PASSWD | Enables encryption without the need for @ref personalization | "#define" in the top of your sketch | @verbatim --my-security-password= @endverbatim and encryption enabled on the chosen transport
+ * | @ref MY_DEBUG_VERBOSE_SIGNING | Enables verbose signing debugging | "#define" in the top of your sketch | @verbatim --my-signing-debug @endverbatim
+ * | @ref MY_SIGNING_ATSHA204 | Enables support to sign messages backed by ATSHA204A hardware | "#define" in the top of your sketch | Not supported
+ * | @ref MY_SIGNING_SOFT | Enables support to sign messages backed by software | "#define" in the top of your sketch | @verbatim --my-signing=software @endverbatim
+ * | @ref MY_SIGNING_REQUEST_SIGNATURES | Enables node/gw to require signed messages | "#define" in the top of your sketch | @verbatim --my-signing-request-signatures @endverbatim
+ * | @ref MY_SIGNING_WEAK_SECURITY | Weakens signing security, useful for testing before deploying signing "globally" | "#define" in the top of your sketch | @verbatim --my-signing-weak_security @endverbatim
+ * | @ref MY_VERIFICATION_TIMEOUT_MS | Change default signing timeout | "#define" in the top of your sketch | @verbatim --my-signing-verification-timeout-ms= @endverbatim
+ * | @ref MY_SIGNING_NODE_WHITELISTING | Defines a whitelist of trusted nodes | "#define" in the top of your sketch | @verbatim --my-signing-whitelist="" @endverbatim
+ * | @ref MY_SIGNING_ATSHA204_PIN | Change default ATSHA204A communication pin | "#define" in the top of your sketch | Not supported
+ * | @ref MY_SIGNING_SOFT_RANDOMSEED_PIN | Change default software RNG seed pin | "#define" in the top of your sketch | Not supported
+ * | @ref MY_RF24_ENABLE_ENCRYPTION | Enables encryption on RF24 radios | "#define" in the top of your sketch | @verbatim --my-rf24-encryption-enabled @endverbatim
+ * | @ref MY_RFM69_ENABLE_ENCRYPTION | Enables encryption on %RFM69 radios | "#define" in the top of your sketch | @verbatim --my-rfm69-encryption-enabled @endverbatim
+ * | @ref MY_NRF5_ESB_ENABLE_ENCRYPTION | Enables encryption on nRF5 radios | "#define" in the top of your sketch | Not supported
+ * | @ref MY_NODE_LOCK_FEATURE | Enables the node locking feature | "#define" in the top of your sketch | Not supported
+ * | @ref MY_NODE_UNLOCK_PIN | Change default unlock pin | "#define" in the top of your sketch | Not supported
+ * | @ref MY_NODE_LOCK_COUNTER_MAX | Change default "malicious activity" counter max value | "#define" in the top of your sketch | Not supported
*
- * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION
* @{
*/
+/**
+ * @def MY_SECURITY_SIMPLE_PASSWD
+ * @brief Enables SW backed signing functionality and encryption functionality in library and uses
+ * provided password as key.
+ *
+ * Example: @code #define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword" @endcode
+ *
+ * For details on the effects, see the references.
+ * @see MY_SIGNING_SIMPLE_PASSWD, MY_ENCRYPTION_SIMPLE_PASSWD
+ */
+//#define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword"
+#if defined(MY_SECURITY_SIMPLE_PASSWD)
+#define MY_SIGNING_SIMPLE_PASSWD MY_SECURITY_SIMPLE_PASSWD
+#define MY_ENCRYPTION_SIMPLE_PASSWD MY_SECURITY_SIMPLE_PASSWD
+#endif
+
/**
* @defgroup SigningSettingGrpPub Signing
* @ingroup SecuritySettingGrpPub
@@ -1500,8 +1670,10 @@
* @def MY_SIGNING_SIMPLE_PASSWD
* @brief Enables SW backed signing functionality in library and uses provided password as key.
*
- * This flag will enable signing, signature requests and encryption. It has to be identical on ALL
- * nodes in the network.
+ * This flag is automatically set if @ref MY_SECURITY_SIMPLE_PASSWD is used.
+ *
+ * This flag will enable signing and signature requests. It has to be identical on ALL nodes in the
+ * network.
*
* Whitelisting is supported and serial will be the first 8 characters of the password, the ninth
* character will be the node ID (to make each node have a unique serial).
@@ -1509,22 +1681,24 @@
* As with the regular signing modes, whitelisting is only activated if a whitelist is specified in
* the sketch.
*
- * No personalization is required for this mode.
+ * No @ref personalization is required for this mode.
*
* It is allowed to set @ref MY_SIGNING_WEAK_SECURITY for deployment purposes in this mode as it is
* with the regular software and ATSHA204A based modes.
*
- * If the provided password is shorter than the size of the HMAC or %AES key, it will be null-padded
+ * If the provided password is shorter than the size of the HMAC key, it will be null-padded
* to accommodate the key size in question. A 32 character password is the maximum length. Any
* password longer than that will be truncated.
+ *
+ * Example: @code #define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword" @endcode
+ *
+ * @see MY_SECURITY_SIMPLE_PASSWD
+ *
*/
//#define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword"
#if defined(MY_SIGNING_SIMPLE_PASSWD)
#define MY_SIGNING_SOFT
#define MY_SIGNING_REQUEST_SIGNATURES
-#define MY_RF24_ENABLE_ENCRYPTION
-#define MY_RFM69_ENABLE_ENCRYPTION
-#define MY_NRF5_ESB_ENABLE_ENCRYPTION
#endif
/**
@@ -1595,6 +1769,8 @@
* the signed message.
*
* It is legal to only have one node with a whitelist for this reason but it is not required.
+ *
+ * Example: @code #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} @endcode
*/
//#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}}
@@ -1616,23 +1792,87 @@
#define MY_SIGNING_SOFT_RANDOMSEED_PIN (7)
#endif
+/**
+ * @def MY_LOCK_DEVICE
+ * @brief Enable read back protection
+ *
+ * Enable read back protection feature. Currently only supported by NRF51+NRF52.
+ * Use this flag to protect signing and encryption keys stored in the MCU.
+ *
+ * Set this flag, when you use softsigning in MySensors. Don't set this
+ * in SecurityPersonalizer.
+ *
+ * @warning YOU CAN BRICK YOUR DEVICE!!!
+ * Don't set this flag without having an boot loader, OTA firmware update and
+ * an Gateway connection. To reset an device, you can try >>
+ * openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c "program dap apreg 1 0x04 0x01"
+ */
+//#define MY_LOCK_DEVICE
+
/**
* @def MY_SIGNING_FEATURE
* @ingroup internals
- * @brief Helper flag to indicate that some signing feature is enabled
+ * @brief Helper flag to indicate that some signing feature is enabled, set automatically
*/
#if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT)
#define MY_SIGNING_FEATURE
#endif
+/** @}*/ // End of SigningSettingGrpPub group
+
+/**
+ * @defgroup EncryptionSettingGrpPub Encryption
+ * @ingroup SecuritySettingGrpPub
+ * @brief These options control encryption related configurations.
+ *
+ * Note that encryption is toggled on a per-radio basis.
+ * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION, MY_RFM95_ENABLE_ENCRYPTION
+ * @{
+ */
+
+/**
+ * @def MY_ENCRYPTION_SIMPLE_PASSWD
+ * @brief Enables encryption on all radio transports that supports it and uses provided password as key.
+ *
+ * This flag is automatically set if @ref MY_SECURITY_SIMPLE_PASSWD is used.
+ *
+ * This flag will enable encryption. It has to be identical on ALL nodes in the network.
+ *
+ * No @ref personalization is required for this mode.
+ *
+ * If the provided password is shorter than the size of the %AES key, it will be null-padded
+ * to accommodate the key size in question. A 16 character password is the maximum length. Any
+ * password longer than that will be truncated.
+ *
+ * Example: @code #define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" @endcode
+ *
+ * @see MY_SECURITY_SIMPLE_PASSWD
+ */
+//#define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword"
+#if defined(MY_ENCRYPTION_SIMPLE_PASSWD)
+#ifndef MY_RF24_ENABLE_ENCRYPTION
+#define MY_RF24_ENABLE_ENCRYPTION
+#endif
+#ifndef MY_RFM69_ENABLE_ENCRYPTION
+#define MY_RFM69_ENABLE_ENCRYPTION
+#endif
+#ifndef MY_NRF5_ESB_ENABLE_ENCRYPTION
+#define MY_NRF5_ESB_ENABLE_ENCRYPTION
+#endif
+#ifndef MY_RFM95_ENABLE_ENCRYPTION
+#define MY_RFM95_ENABLE_ENCRYPTION
+#endif
+#endif
+
/**
* @def MY_ENCRYPTION_FEATURE
* @ingroup internals
- * @brief Helper flag to indicate that some encryption feature is enabled
+ * @brief Helper flag to indicate that some encryption feature is enabled, set automatically
+ * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION, MY_RFM95_ENABLE_ENCRYPTION
*/
-#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
+#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) || defined(MY_RFM95_ENABLE_ENCRYPTION)
#define MY_ENCRYPTION_FEATURE
#endif
-/** @}*/ // End of SigningSettingGrpPub group
+/** @}*/ // End of EncryptionSettingGrpPub group
/**
* @defgroup MyLockgrppub Node locking
@@ -1724,35 +1964,58 @@
#endif
/** @}*/ // End of ESP8266SettingGrpPub group
+/**
+* @defgroup ESP32SettingGrpPub ESP32
+* @ingroup PlatformSettingGrpPub
+* @brief These options control ESP32 specific configurations.
+* @{
+*/
+
+//
+// no ESP32 settings
+//
+
+/** @}*/ // End of ESP32SettingGrpPub group
+
/**
* @defgroup LinuxSettingGrpPub Linux
* @ingroup PlatformSettingGrpPub
* @brief These options control Linux specific configurations.
* @{
*/
+
/**
* @def MY_LINUX_SERIAL_PORT
* @brief Serial device port
*/
-#ifndef MY_LINUX_SERIAL_PORT
-#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0"
+//#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0"
+
+/**
+ * @def MY_LINUX_SERIAL_PTY
+ * @brief deprecated option
+ */
+#ifdef MY_LINUX_SERIAL_PTY
+#warning MY_LINUX_SERIAL_PTY is deprecated, please use MY_LINUX_SERIAL_PORT
+#define MY_LINUX_SERIAL_PORT MY_LINUX_SERIAL_PTY
#endif
/**
* @def MY_LINUX_IS_SERIAL_PTY
- * @brief Set serial as a pseudo terminal.
- *
- * Enable this if you need to connect to a controller running on the same device.
+ * @brief deprecated option
*/
-//#define MY_LINUX_IS_SERIAL_PTY
+#ifdef MY_LINUX_IS_SERIAL_PTY
+#warning MY_LINUX_IS_SERIAL_PTY is deprecated, please use MY_LINUX_SERIAL_IS_PTY
+#define MY_LINUX_SERIAL_IS_PTY
+#endif
/**
- * @def MY_LINUX_SERIAL_PTY
- * @brief Symlink name for the PTY device.
+ * @def MY_LINUX_SERIAL_IS_PTY
+ * @brief Set serial as a pseudo terminal.
+ *
+ * Enable this if you need to connect to a controller running on the same device.
+ * You also need to define MY_LINUX_SERIAL_PORT with the symlink name for the PTY device.
*/
-#ifndef MY_LINUX_SERIAL_PTY
-#define MY_LINUX_SERIAL_PTY "/dev/ttyMySensorsGateway"
-#endif
+//#define MY_LINUX_SERIAL_IS_PTY
/**
* @def MY_LINUX_SERIAL_GROUPNAME
@@ -1767,7 +2030,7 @@
* @note For now the configuration file is only used to store the emulated eeprom state.
*/
#ifndef MY_LINUX_CONFIG_FILE
-#define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat"
+#define MY_LINUX_CONFIG_FILE "/etc/mysensors.conf"
#endif
/** @}*/ // End of LinuxSettingGrpPub group
/** @}*/ // End of PlatformSettingGrpPub group
@@ -1782,7 +2045,7 @@
* MY_IS_GATEWAY is true when @ref MY_GATEWAY_FEATURE is set.
* MY_NODE_TYPE contain a string describing the class of sketch/node (gateway/repeater/node).
*/
-#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT)
+#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)|| defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) || defined(MY_GATEWAY_TINYGSM)
#define MY_GATEWAY_FEATURE
#define MY_IS_GATEWAY (true)
#define MY_NODE_TYPE "GW"
@@ -1908,7 +2171,10 @@
#define MY_DISABLED_SERIAL
#define MY_SPLASH_SCREEN_DISABLED
// linux
+#define MY_LINUX_SERIAL_PORT
+#define MY_LINUX_SERIAL_IS_PTY
#define MY_LINUX_SERIAL_GROUPNAME
+#define MY_LINUX_SERIAL_PTY
#define MY_LINUX_IS_SERIAL_PTY
// inclusion mode
#define MY_INCLUSION_MODE_FEATURE
@@ -1925,12 +2191,18 @@
#define MY_REPEATER_FEATURE
#define MY_PASSIVE_NODE
#define MY_MQTT_CLIENT_PUBLISH_RETAIN
+#define MY_MQTT_PASSWORD
+#define MY_MQTT_USER
+#define MY_MQTT_CLIENT_ID
+#define MY_MQTT_PUBLISH_TOPIC_PREFIX
+#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX
#define MY_SIGNAL_REPORT_ENABLED
// general
#define MY_WITH_LEDS_BLINKING_INVERSE
#define MY_INDICATION_HANDLER
#define MY_DISABLE_REMOTE_RESET
#define MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
+#define MY_LOCK_DEVICE
// core
#define MY_CORE_ONLY
// GW
@@ -1940,21 +2212,75 @@
#define MY_GATEWAY_W5100
#define MY_GATEWAY_ENC28J60
#define MY_GATEWAY_ESP8266
+#define MY_GATEWAY_ESP32
+#define MY_WIFI_SSID
+#define MY_WIFI_BSSID
+#define MY_WIFI_PASSWORD
+#define MY_HOSTNAME
#define MY_GATEWAY_LINUX
-#define MY_IP_ADDRESS 192,168,178,66
+#define MY_GATEWAY_TINYGSM
+#define MY_GATEWAY_MQTT_CLIENT
+#define MY_GATEWAY_SERIAL
+#define MY_IP_ADDRESS
+#define MY_IP_GATEWAY_ADDRESS
+#define MY_IP_SUBNET_ADDRESS
#define MY_USE_UDP
-#define MY_CONTROLLER_IP_ADDRESS 192,168,178,254
+#define MY_CONTROLLER_IP_ADDRESS
+#define MY_CONTROLLER_URL_ADDRESS
+// TinyGSM
+/**
+ * @def MY_GSM_APN
+ * @brief APN from your cell carrier / mobile provider. Example: 4g.tele2.se
+ */
+#define MY_GSM_APN
+/**
+ * @def MY_GSM_BAUDRATE
+ * @brief Baudrate for your GSM modem. If left undefined, TinyGSM will try to auto detect the correct rate
+ */
+#define MY_GSM_BAUDRATE
+/**
+ * @def MY_GSM_PIN
+ * @brief PIN code for your SIM card, if PIN lock is active.
+ */
+#define MY_GSM_PIN
+/**
+ * @def MY_GSM_PSW
+ * @brief If using a GSM modem, this is the password supplied by your cell carrier / mobile provider. If using ESP8266 as a WiFi modem, this is your WiFi network password
+ */
+#define MY_GSM_PSW
+/**
+ * @def MY_GSM_RX
+ * @brief If defined, uses softSerial using defined pins (must also define MY_GSM_TX)
+ */
+#define MY_GSM_RX
+/**
+ * @def MY_GSM_SSID
+ * @brief If using ESP8266 as WiFi modem, this is your network SSID
+ */
+#define MY_GSM_SSID
+/**
+ * @def MY_GSM_TX
+ * @brief If defined, uses softSerial using defined pins (must also define MY_GSM_RX)
+ */
+#define MY_GSM_TX
+/**
+ * @def MY_GSM_USR
+ * @brief Supplied by your cell carrier / mobile operator. If not required, leave undefined.
+ */
+#define MY_GSM_USR
// LED
#define MY_DEFAULT_ERR_LED_PIN
#define MY_DEFAULT_TX_LED_PIN
#define MY_DEFAULT_RX_LED_PIN
// signing
-#define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword"
+#define MY_SECURITY_SIMPLE_PASSWD
+#define MY_SIGNING_SIMPLE_PASSWD
+#define MY_ENCRYPTION_SIMPLE_PASSWD
#define MY_SIGNING_ATSHA204
#define MY_SIGNING_SOFT
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_WEAK_SECURITY
-#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}}
+#define MY_SIGNING_NODE_WHITELISTING
#define MY_DEBUG_VERBOSE_SIGNING
#define MY_SIGNING_FEATURE
#define MY_ENCRYPTION_FEATURE
@@ -1963,7 +2289,7 @@
#define MY_OTA_USE_I2C_EEPROM
// RS485
#define MY_RS485
-#define MY_RS485_HWSERIAL (Serial1)
+#define MY_RS485_HWSERIAL
// RF24
#define MY_RADIO_RF24
#define MY_DEBUG_VERBOSE_RF24
@@ -1983,6 +2309,7 @@
#define MY_IS_RFM69HW
#define MY_RFM69_NEW_DRIVER
#define MY_RFM69_POWER_PIN
+#define MY_RFM69_MODEM_CONFIGURATION
#define MY_RFM69_ENABLE_ENCRYPTION
#define MY_RFM69_ATC_MODE_DISABLED
#define MY_RFM69_MAX_POWER_LEVEL_DBM
@@ -1993,6 +2320,7 @@
// RFM95
#define MY_RADIO_RFM95
#define MY_DEBUG_VERBOSE_RFM95
+#define MY_RFM95_ENABLE_ENCRYPTION
#define MY_RFM95_ATC_MODE_DISABLED
#define MY_RFM95_RST_PIN
#define MY_RFM95_MODEM_CONFIGRUATION
diff --git a/MySensors.h b/MySensors.h
index 28676c573..0033d5df1 100644
--- a/MySensors.h
+++ b/MySensors.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -59,6 +59,8 @@
#include "hal/architecture/MyHw.h"
#if defined(ARDUINO_ARCH_ESP8266)
#include "hal/architecture/ESP8266/MyHwESP8266.cpp"
+#elif defined(ARDUINO_ARCH_ESP32)
+#include "hal/architecture/ESP32/MyHwESP32.cpp"
#elif defined(ARDUINO_ARCH_AVR)
#include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h"
#include "hal/architecture/AVR/MyHwAVR.cpp"
@@ -75,6 +77,8 @@
#include "hal/architecture/Teensy3/MyHwTeensy3.cpp"
#elif defined(__linux__)
#include "hal/architecture/Linux/MyHwLinuxGeneric.cpp"
+#else
+#error Hardware abstraction not defined (unsupported platform)
#endif
// OTA Debug second part, depends on HAL
@@ -126,11 +130,13 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
// FLASH
#if defined(MY_OTA_FIRMWARE_FEATURE)
+#ifndef MCUBOOT_PRESENT
#if defined(MY_OTA_USE_I2C_EEPROM)
#include "drivers/I2CEeprom/I2CEeprom.cpp"
#else
#include "drivers/SPIFlash/SPIFlash.cpp"
#endif
+#endif
#include "core/MyOTAFirmwareUpdate.cpp"
#endif
@@ -147,14 +153,19 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#if defined(MY_SENSOR_NETWORK)
// We assume that a gateway having a radio also should act as repeater
#define MY_REPEATER_FEATURE
-
#endif
+
// GATEWAY - COMMON FUNCTIONS
-// We support MQTT Client using W5100, ESP8266 and Linux
-#if !defined(MY_GATEWAY_CLIENT_MODE)
+// We support MQTT Client using W5100, ESP8266, GSM modems supported by TinyGSM library and Linux
+#if !defined(MY_GATEWAY_CLIENT_MODE) && !defined(MY_GATEWAY_TINYGSM)
#error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS
#endif
+#if defined(MY_GATEWAY_TINYGSM) && !defined(MY_GATEWAY_MQTT_CLIENT)
+// TinyGSM currently only supports MQTTClient mode.
+#error MY_GATEWAY_TINYGSM only works with MY_GATEWAY_MQTT_CLIENT
+#endif
+
#if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX)
#error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client
#endif
@@ -170,6 +181,10 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#include "core/MyGatewayTransport.cpp"
#include "core/MyProtocolMySensors.cpp"
+#if defined(MY_GATEWAY_TINYGSM)
+#include "drivers/TinyGSM/TinyGsmClient.h"
+#endif
+
#if defined(MY_GATEWAY_LINUX)
#include "drivers/Linux/EthernetClient.h"
#include "drivers/Linux/EthernetServer.h"
@@ -188,11 +203,12 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
// We assume that a gateway having a radio also should act as repeater
#define MY_REPEATER_FEATURE
#endif
+
#if !defined(MY_PORT)
-#error You must define MY_PORT (controller or gatway port to open)
+#error You must define MY_PORT (controller or gateway port to open)
#endif
-#if defined(MY_GATEWAY_ESP8266)
-// GATEWAY - ESP8266
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
+// GATEWAY - ESP8266 / ESP32
#include "core/MyGatewayTransportEthernet.cpp"
#elif defined(MY_GATEWAY_LINUX)
// GATEWAY - Generic Linux
@@ -268,13 +284,13 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#endif
#if defined(MY_TRANSPORT_DONT_CARE_MODE)
-#error This directive is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead!
+#error MY_TRANSPORT_DONT_CARE_MODE is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead!
#endif
// RAM ROUTING TABLE
#if defined(MY_RAM_ROUTING_TABLE_FEATURE) && defined(MY_REPEATER_FEATURE)
// activate feature based on architecture
-#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__)
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__)
#define MY_RAM_ROUTING_TABLE_ENABLED
#elif defined(ARDUINO_ARCH_AVR)
#if defined(__avr_atmega1280__) || defined(__avr_atmega1284__) || defined(__avr_atmega2560__)
@@ -304,6 +320,15 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#include "drivers/AVR/DigitalIO/DigitalIO.h"
#endif
+// SOFTSERIAL
+#if defined(MY_GSM_TX) != defined(MY_GSM_RX)
+#error Both, MY_GSM_TX and MY_GSM_RX need to be defined when using SoftSerial
+#endif
+
+#if defined(MY_GATEWAY_TINYGSM) && !defined(SerialAT) && (!defined(MY_GSM_TX) || !defined(MY_GSM_RX))
+#error You need to define either SerialAT or MY_GSM_RX and MY_GSM_TX pins
+#endif
+
// POWER PIN
#ifndef DOXYGEN
#if defined(MY_RF24_POWER_PIN) || defined(MY_RFM69_POWER_PIN) || defined(MY_RFM95_POWER_PIN) || defined(MY_RADIO_NRF5_ESB)
@@ -315,21 +340,15 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
// Transport drivers
#if defined(MY_RADIO_RF24)
-#if defined(MY_RF24_ENABLE_ENCRYPTION)
-#include "drivers/AES/AES.cpp"
-#endif
#include "drivers/RF24/RF24.cpp"
-#include "hal/transport/MyTransportRF24.cpp"
+#include "hal/transport/RF24/MyTransportRF24.cpp"
#elif defined(MY_RADIO_NRF5_ESB)
#if !defined(ARDUINO_ARCH_NRF5)
#error No support for nRF5 radio on this platform
#endif
-#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
-#include "drivers/AES/AES.cpp"
-#endif
#include "drivers/NRF5/Radio.cpp"
#include "drivers/NRF5/Radio_ESB.cpp"
-#include "hal/transport/MyTransportNRF5_ESB.cpp"
+#include "hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp"
#elif defined(MY_RS485)
#if !defined(MY_RS485_HWSERIAL)
#if defined(__linux__)
@@ -337,20 +356,17 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#endif
#include "drivers/AltSoftSerial/AltSoftSerial.cpp"
#endif
-#include "hal/transport/MyTransportRS485.cpp"
+#include "hal/transport/RS485/MyTransportRS485.cpp"
#elif defined(MY_RADIO_RFM69)
#if defined(MY_RFM69_NEW_DRIVER)
#include "drivers/RFM69/new/RFM69_new.cpp"
#else
#include "drivers/RFM69/old/RFM69_old.cpp"
#endif
-#include "hal/transport/MyTransportRFM69.cpp"
+#include "hal/transport/RFM69/MyTransportRFM69.cpp"
#elif defined(MY_RADIO_RFM95)
-#if defined(MY_RFM95_ENABLE_ENCRYPTION)
-#include "drivers/AES/AES.cpp"
-#endif
#include "drivers/RFM95/RFM95.cpp"
-#include "hal/transport/MyTransportRFM95.cpp"
+#include "hal/transport/RFM95/MyTransportRFM95.cpp"
#endif
// PASSIVE MODE
@@ -396,7 +412,6 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#include "core/MySensorsCore.cpp"
// HW mains
-#if !defined(MY_CORE_ONLY)
#if defined(ARDUINO_ARCH_AVR)
#include "hal/architecture/AVR/MyMainAVR.cpp"
#elif defined(ARDUINO_ARCH_SAMD)
@@ -405,14 +420,15 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#include "hal/architecture/ESP8266/MyMainESP8266.cpp"
#elif defined(ARDUINO_ARCH_NRF5)
#include "hal/architecture/NRF5/MyMainNRF5.cpp"
+#elif defined(ARDUINO_ARCH_ESP32)
+#include "hal/architecture/ESP32/MyMainESP32.cpp"
#elif defined(__linux__)
-#include "hal/architecture/Linux/MyMainLinux.cpp"
+#include "hal/architecture/Linux/MyMainLinuxGeneric.cpp"
#elif defined(ARDUINO_ARCH_STM32F1)
#include "hal/architecture/STM32F1/MyMainSTM32F1.cpp"
#elif defined(TEENSYDUINO)
#include "hal/architecture/Teensy3/MyMainTeensy3.cpp"
#endif
-#endif
#endif
diff --git a/README.md b/README.md
index 2c497169b..ed896fa45 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-MySensors Library v2.2.0
+MySensors Library v2.3.0
Please visit www.mysensors.org for more information
diff --git a/configure b/configure
index 8618eefe0..ddf766658 100755
--- a/configure
+++ b/configure
@@ -37,7 +37,7 @@ Installation options:
MySensors options:
--my-debug=[enable|disable] Enables or disables MySensors core debugging. [enable]
- --my-config-file= Config file path. [/etc/mysensors.dat]
+ --my-config-file= Config file path. [/etc/mysensors.conf]
--my-gateway=[none|ethernet|serial|mqtt]
Set the protocol used to communicate with the controller. [ethernet]
--my-node-id= Disable gateway feature and run as a node with the specified id.
@@ -47,11 +47,12 @@ MySensors options:
Controller or MQTT broker ip.
--my-port= The port to keep open on gateway mode.
If gateway is set to mqtt, it sets the broker port.
- --my-serial-port= Serial port. [/dev/ttyACM0]
+ --my-serial-port= Serial port.
--my-serial-baudrate= Serial baud rate. [115200]
--my-serial-is-pty Set the serial port to be a pseudo terminal. Use this if you want
to connect to a controller running on the same device.
- --my-serial-pty= Symlink name for the PTY device. [/dev/ttyMySensorsGateway]
+ You also need to set the symlink name for the PTY device with
+ the --my-serial-port option.
--my-serial-groupname=
Grant access to the specified system group for the serial device.
--my-mqtt-client-id= MQTT client id.
@@ -72,7 +73,7 @@ MySensors options:
--my-rf24-encryption-enabled
Enables RF24 encryption.
All nodes and gateway must have this enabled, and all must be
- personalized with the same AES key
+ personalized with the same AES key.
--my-rx-message-buffer-size=
Buffer size for incoming messages when using rf24 interrupts. [20]
--my-rfm69-frequency=[315|433|868|915]
@@ -80,6 +81,18 @@ MySensors options:
--my-is-rfm69hw Enable high-powered rfm69hw.
--my-rfm69-irq-pin= Pin number connected to RFM69 IRQ pin.
--my-rfm69-cs-pin= Pin number to use for RFM69 Chip-Select.
+ --my-rfm69-encryption-enabled
+ Enables RFM69 encryption.
+ All nodes and gateway must have this enabled, and all must be
+ personalized with the same AES key.
+ --my-rfm95-frequency=[169|315|434|868|915]
+ RFM95 Module Frequency. [868]
+ --my-rfm95-irq-pin= Pin number connected to RFM95 IRQ pin.
+ --my-rfm95-cs-pin= Pin number to use for RFM95 Chip-Select.
+ --my-rfm95-encryption-enabled
+ Enables RFM95 encryption.
+ All nodes and gateway must have this enabled, and all must be
+ personalized with the same AES key.
--my-rs485-serial-port=
RS485 serial port. You must provide a port.
--my-rs485-baudrate= RS485 baudrate. [9600]
@@ -98,13 +111,30 @@ MySensors options:
gateway signature.
--my-signing-weak_security Enable this to permit downgrade of security preferences and
relaxed gateway signing requirements.
- --my-signing-password=
- If you are using password as the signature type, set your password here.
+ --my-signing-whitelist=
+ If you want to use a whitelist, provide it here, make sure to avoid
+ spaces in the expression.
+ --my-signing-verification-timeout-ms=
+ Signing timeout. [5000]
+ --my-security-password=
+ If you are using password for signing/encryption, set your password here.
EOF
}
+# Colors
+GREEN='\033[0;32m'
+RED='\033[0;31m'
+YELLOW='\033[1;33m'
+LIGHT_BLUE='\033[1;34m'
+NO_COLOR='\033[0m'
+
+OK="${GREEN}[OK]${NO_COLOR}"
+ERROR="${RED}[ERROR]${NO_COLOR}"
+FAILED="${YELLOW}[FAILED]${NO_COLOR}"
+SECTION="${LIGHT_BLUE}[SECTION]${NO_COLOR}"
+
function die {
- echo "[ERROR] $1"
+ printf "${ERROR} $1 \n"
exit $2
}
@@ -258,6 +288,7 @@ gateway_type=ethernet
transport_type=nrf24
signing=none
signing_request_signatures=false
+encryption=false
params="SOC CFLAGS CXXFLAGS CPPFLAGS LDFLAGS PREFIX CC CXX ARDUINO_LIB_DIR BUILDDIR BINDIR GATEWAY_DIR INIT_SYSTEM SPI_DRIVER"
@@ -338,10 +369,6 @@ for opt do
--my-transport=*)
transport_type=${optarg}
;;
- --my-radio=*)
- echo "Warning: --my-radio is deprecated, please use --my-transport"
- transport_type=${optarg}
- ;;
--my-serial-port=*)
CPPFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CPPFLAGS"
;;
@@ -349,10 +376,11 @@ for opt do
CPPFLAGS="-DMY_BAUD_RATE=${optarg} $CPPFLAGS"
;;
--my-serial-is-pty*)
- CPPFLAGS="-DMY_LINUX_IS_SERIAL_PTY $CPPFLAGS"
+ CPPFLAGS="-DMY_LINUX_SERIAL_IS_PTY $CPPFLAGS"
;;
--my-serial-pty=*)
- CPPFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CPPFLAGS"
+ echo "Warning: --my-serial-pty is deprecated, please use --my-serial-port"
+ CPPFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CPPFLAGS"
;;
--my-serial-groupname=*)
CPPFLAGS="-DMY_LINUX_SERIAL_GROUPNAME=\\\"${optarg}\\\" $CPPFLAGS"
@@ -398,6 +426,7 @@ for opt do
CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CPPFLAGS"
;;
--my-rf24-encryption-enabled*)
+ encryption=true
CPPFLAGS="-DMY_RF24_ENABLE_ENCRYPTION $CPPFLAGS"
;;
--my-rx-message-buffer-size=*)
@@ -425,6 +454,35 @@ for opt do
--my-rfm69-cs-pin=*)
CPPFLAGS="-DMY_RFM69_CS_PIN=${optarg} $CPPFLAGS"
;;
+ --my-rfm69-encryption-enabled*)
+ encryption=true
+ CPPFLAGS="-DMY_RFM69_ENABLE_ENCRYPTION $CPPFLAGS"
+ ;;
+ --my-rfm95-frequency=*)
+ if [[ ${optarg} == "169" ]]; then
+ CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_169MHZ $CPPFLAGS"
+ elif [[ ${optarg} == "315" ]]; then
+ CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_315MHZ $CPPFLAGS"
+ elif [[ ${optarg} == "434" ]]; then
+ CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_434MHZ $CPPFLAGS"
+ elif [[ ${optarg} == "868" ]]; then
+ CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_868MHZ $CPPFLAGS"
+ elif [[ ${optarg} == "915" ]]; then
+ CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_915MHZ $CPPFLAGS"
+ else
+ echo "[WARNING] Illegal value for --my-rfm95-frequency=${optarg}, ignored"
+ fi
+ ;;
+ --my-rfm95-irq-pin=*)
+ CPPFLAGS="-DMY_RFM95_IRQ_NUM=${optarg} $CPPFLAGS"
+ ;;
+ --my-rfm95-cs-pin=*)
+ CPPFLAGS="-DMY_RFM95_CS_PIN=${optarg} $CPPFLAGS"
+ ;;
+ --my-rfm95-encryption-enabled*)
+ encryption=true
+ CPPFLAGS="-DMY_RFM95_ENABLE_ENCRYPTION $CPPFLAGS"
+ ;;
--my-rs485-serial-port=*)
CPPFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CPPFLAGS"
;;
@@ -461,8 +519,14 @@ for opt do
--my-signing-weak_security*)
CPPFLAGS="-DMY_SIGNING_WEAK_SECURITY $CPPFLAGS"
;;
- --my-signing-password=*)
- signing_password=${optarg}
+ --my-signing-whitelist*)
+ CPPFLAGS="-DMY_SIGNING_NODE_WHITELISTING=${optarg} $CPPFLAGS"
+ ;;
+ --my-signing-verification-timeout-ms*)
+ CPPFLAGS="-DMY_VERIFICATION_TIMEOUT_MS=${optarg} $CPPFLAGS"
+ ;;
+ --my-security-password=*)
+ security_password=${optarg}
;;
*)
echo "[WARNING] Unknown option detected:$opt, ignored"
@@ -478,12 +542,12 @@ CC=${CC:-gcc}
CXX=${CXX:-g++}
if [ -z "${SOC}" ]; then
- echo "[SECTION] Detecting target machine."
+ printf "${SECTION} Detecting target machine.\n"
info=($(detect_machine))
SOC=${info[0]}
TYPE=${info[1]}
CPU=${info[2]}
- echo " [OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}."
+ printf " ${OK} machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}.\n"
fi
if [ -z "${CPUFLAGS}" ]; then
@@ -493,23 +557,23 @@ fi
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then
CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS"
else
- echo "[SECTION] Checking GPIO Sysfs."
+ printf "${SECTION} Checking GPIO Sysfs.\n"
if [[ $(eval 'ls /sys/class/gpio/export 2>/dev/null') ]]; then
- echo " [OK] /sys/class/gpio/export found"
+ printf " ${OK} /sys/class/gpio/export found.\n"
else
echo " [WARNING] /sys/class/gpio/export not found."
fi
fi
if [ -z "${SPI_DRIVER}" ]; then
- echo "[SECTION] Detecting SPI driver."
+ printf "${SECTION} Detecting SPI driver.\n"
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then
SPI_DRIVER=BCM
elif [[ $(eval 'ls /dev/spidev* 2>/dev/null') ]]; then
SPI_DRIVER=SPIDEV
fi
if [ -n "${SPI_DRIVER}" ]; then
- echo " [OK] SPI driver detected:${SPI_DRIVER}."
+ printf " ${OK} SPI driver detected:${SPI_DRIVER}.\n"
else
echo " [WARNING] No supported SPI driver detected. Using SPIDEV."
SPI_DRIVER=SPIDEV
@@ -532,6 +596,8 @@ if [ -n "${SPI_DRIVER}" ]; then
esac
fi
+printf "${SECTION} Gateway configuration.\n"
+
if [[ ${debug} == "enable" ]]; then
CPPFLAGS="-DMY_DEBUG $CPPFLAGS"
fi
@@ -548,6 +614,7 @@ elif [[ ${gateway_type} == "mqtt" ]]; then
else
die "Invalid gateway type." 2
fi
+printf " ${OK} Type: ${gateway_type}.\n"
if [[ ${transport_type} == "none" ]]; then
# Transport disabled
@@ -563,53 +630,68 @@ elif [[ ${transport_type} == "rfm95" ]]; then
else
die "Invalid transport type." 3
fi
+printf " ${OK} Transport: ${transport_type}.\n"
if [[ ${signing} == "none" ]]; then
# Signing disabled
- :
+ printf " ${OK} Signing: Disabled.\n"
elif [[ ${signing} == "software" ]]; then
CPPFLAGS="-DMY_SIGNING_SOFT $CPPFLAGS"
if [[ ${signing_request_signatures} == true ]]; then
CPPFLAGS="-DMY_SIGNING_REQUEST_SIGNATURES $CPPFLAGS"
fi
+ printf " ${OK} Signing: Enabled - Using key from config file.\n"
elif [[ ${signing} == "password" ]]; then
- if [ -z "${signing_password}" ]; then
- die "You need to set the password for signing with --my-signing-password= option" 6
+ if [ -z "${security_password}" ]; then
+ die "You need to set the password for signing with --my-security-password option" 6
fi
- echo "Simplified signing using password"
- CPPFLAGS="-DMY_SIGNING_SIMPLE_PASSWD=\\\"${signing_password}\\\" $CPPFLAGS"
+ printf " ${OK} Signing: Enabled - Simplified signing using password.\n"
+ CPPFLAGS="-DMY_SIGNING_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS"
else
die "Invalid signing type." 7
fi
+if [[ ${encryption} == true ]]; then
+ # Encryption enabled on some transport
+ if [ -z "${security_password}" ]; then
+ printf " ${OK} Encryption: Enabled - Using key from config file.\n"
+ else
+ printf " ${OK} Encryption: Enabled - Simplified encryption using password.\n"
+ CPPFLAGS="-DMY_ENCRYPTION_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS"
+ fi
+else
+ printf " ${OK} Encryption: Disabled.\n"
+fi
+
LDFLAGS="-pthread $LDFLAGS"
CPPFLAGS="$CPUFLAGS $CPPFLAGS"
-echo "[SECTION] Detecting init system."
+printf "${SECTION} Detecting init system.\n"
if [ "${NO_INIT}" ]; then
- echo " [OK] no init system chosen."
+ printf " ${OK} No init system chosen.\n"
elif [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then
INIT_SYSTEM=systemd
- echo " [OK] init system detected: systemd."
+ printf " ${OK} Init system detected: systemd.\n"
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
INIT_SYSTEM=sysvinit
- echo " [OK] init system detected: sysvinit."
+ printf " ${OK} Init system detected: sysvinit.\n"
else
- echo " [FAILED] unknown init system."
+ printf " ${FAILED} Unknown init system."
fi
-echo "[SECTION] Saving configuration."
+printf "${SECTION} Saving configuration.\n"
echo -n "" > Makefile.inc
for param in ${params}; do
if [[ ${!param} ]]; then
echo "${param}=${!param}" >> Makefile.inc
fi
done
+printf " ${OK} Saved.\n"
if [ -z "${NO_CLEAN}" ]; then
- echo "[SECTION] Cleaning previous builds."
+ printf "${SECTION} Cleaning previous builds.\n"
make clean >/dev/null
fi
-echo "[OK] Finished."
+printf " ${OK} Finished.\n"
diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h
index 68408989b..629ea6b64 100644
--- a/core/MyCapabilities.h
+++ b/core/MyCapabilities.h
@@ -160,6 +160,8 @@
#define MY_CAP_ARCH "N"
#elif defined(ARDUINO_ARCH_ESP8266)
#define MY_CAP_ARCH "E"
+#elif defined(ARDUINO_ARCH_ESP32)
+#define MY_CAP_ARCH "F"
#elif defined(ARDUINO_ARCH_AVR)
#define MY_CAP_ARCH "A"
#elif defined(ARDUINO_ARCH_STM32F1)
@@ -216,14 +218,14 @@
* @def MY_CAP_ENCR
* @brief Indicate the encryption setting.
*
- * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION
+ * @see MY_ENCRYPTION_FEATURE
*
* | Setting | Indicator
* |------------|----------
* | Enabled | X
* | Disabled | -
*/
-#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined (MY_NRF5_ESB_ENABLE_ENCRYPTION)
+#if defined(MY_ENCRYPTION_FEATURE)
#define MY_CAP_ENCR "X"
#else
#define MY_CAP_ENCR "-"
diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp
index 9ec451254..6d1f576ae 100644
--- a/core/MyGatewayTransportEthernet.cpp
+++ b/core/MyGatewayTransportEthernet.cpp
@@ -22,6 +22,35 @@
// global variables
extern MyMessage _msgTmp;
+// housekeeping, remove for 3.0.0
+#ifdef MY_ESP8266_SSID
+#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead!
+#define MY_WIFI_SSID MY_ESP8266_SSID
+#undef MY_ESP8266_SSID // cleanup
+#endif
+
+#ifdef MY_ESP8266_PASSWORD
+#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead!
+#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD
+#undef MY_ESP8266_PASSWORD // cleanup
+#endif
+
+#ifdef MY_ESP8266_BSSID
+#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead!
+#define MY_WIFI_BSSID MY_ESP8266_BSSID
+#undef MY_ESP8266_BSSID // cleanup
+#endif
+
+#ifdef MY_ESP8266_HOSTNAME
+#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead!
+#define MY_HOSTNAME MY_ESP8266_HOSTNAME
+#undef MY_ESP8266_HOSTNAME // cleanup
+#endif
+
+#ifndef MY_WIFI_BSSID
+#define MY_WIFI_BSSID NULL
+#endif
+
#if defined(MY_CONTROLLER_IP_ADDRESS)
IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
#endif
@@ -30,14 +59,14 @@ IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
IPAddress _ethernetGatewayIP(MY_IP_ADDRESS);
#if defined(MY_IP_GATEWAY_ADDRESS)
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
-#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */
+#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
// Assume the gateway will be the machine on the same network as the local IP
// but with last octet being '1'
IPAddress _gatewayIp(_ethernetGatewayIP[0], _ethernetGatewayIP[1], _ethernetGatewayIP[2], 1);
#endif /* End of MY_IP_GATEWAY_ADDRESS */
#if defined(MY_IP_SUBNET_ADDRESS)
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
-#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */
+#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
IPAddress _subnetIp(255, 255, 255, 0);
#endif /* End of MY_IP_SUBNET_ADDRESS */
#endif /* End of MY_IP_ADDRESS */
@@ -57,12 +86,12 @@ typedef struct {
uint8_t idx;
} inputBuffer;
-#if defined(MY_GATEWAY_ESP8266)
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
// Some re-defines to make code more readable below
#define EthernetServer WiFiServer
#define EthernetClient WiFiClient
#define EthernetUDP WiFiUDP
-#endif /* End of MY_GATEWAY_ESP8266 */
+#endif
#if defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_USE_UDP)
@@ -81,7 +110,7 @@ static inputBuffer inputString;
#else
static EthernetClient client = EthernetClient();
#endif /* End of MY_USE_UDP */
-#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_CLIENT_MODE */
+#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || defined(MY_GATEWAY_LINUX)
static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS];
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS];
@@ -116,29 +145,31 @@ void _w5100_spi_en(bool enable)
bool gatewayTransportInit(void)
{
_w5100_spi_en(true);
-#if defined(MY_GATEWAY_ESP8266)
-#if defined(MY_ESP8266_SSID)
+
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
+#if defined(MY_WIFI_SSID)
// Turn off access point
WiFi.mode(WIFI_STA);
-#if defined(MY_ESP8266_HOSTNAME)
- WiFi.hostname(MY_ESP8266_HOSTNAME);
-#endif /* End of MY_ESP8266_HOSTNAME */
-#if defined(MY_IP_ADDRESS)
+#if defined(MY_HOSTNAME)
+#if defined(MY_GATEWAY_ESP8266)
+ WiFi.hostname(MY_HOSTNAME);
+#elif defined(MY_GATEWAY_ESP32)
+ WiFi.setHostname(MY_HOSTNAME);
+#endif
+#endif
+#ifdef MY_IP_ADDRESS
WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp);
-#endif /* End of MY_IP_ADDRESS */
-#ifndef MY_ESP8266_BSSID
-#define MY_ESP8266_BSSID NULL
#endif
- (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID);
+ (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
while (WiFi.status() != WL_CONNECTED) {
wait(500);
GATEWAY_DEBUG(PSTR("GWT:TIN:CONNECTING...\n"));
}
- GATEWAY_DEBUG(PSTR("GWT:TIN:IP=%s\n"), WiFi.localIP().toString().c_str());
-#endif /* End of MY_ESP8266_SSID */
-#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */
+ GATEWAY_DEBUG(PSTR("GWT:TIN:IP: %s\n"), WiFi.localIP().toString().c_str());
+#endif
+#elif defined(MY_GATEWAY_LINUX)
// Nothing to do here
-#else /* Else part of MY_GATEWAY_ESP8266 */
+#else
#if defined(MY_IP_GATEWAY_ADDRESS) && defined(MY_IP_SUBNET_ADDRESS)
// DNS server set to gateway ip
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP, _gatewayIp, _gatewayIp, _subnetIp);
@@ -157,7 +188,7 @@ bool gatewayTransportInit(void)
Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]);
// give the Ethernet interface a second to initialize
delay(1000);
-#endif /* End of MY_GATEWAY_ESP8266 */
+#endif /* MY_GATEWAY_ESP8266 / MY_GATEWAY_ESP32 */
#if defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_USE_UDP)
@@ -236,7 +267,7 @@ bool gatewayTransportSend(MyMessage &message)
#endif /* End of MY_USE_UDP */
#else /* Else part of MY_GATEWAY_CLIENT_MODE */
// Send message to connected clients
-#if defined(MY_GATEWAY_ESP8266)
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
if (clients[i] && clients[i].connected()) {
nbytes += clients[i].write((uint8_t*)_ethernetMsg, strlen(_ethernetMsg));
@@ -253,7 +284,7 @@ bool gatewayTransportSend(MyMessage &message)
#if defined(MY_USE_UDP)
// Nothing to do here
#else
-#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE)
+#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE)
bool _readFromClient(uint8_t i)
{
while (clients[i].connected() && clients[i].available()) {
@@ -366,7 +397,7 @@ bool gatewayTransportAvailable(void)
}
#endif /* End of MY_USE_UDP */
#else /* Else part of MY_GATEWAY_CLIENT_MODE */
-#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || defined(MY_GATEWAY_LINUX)
// ESP8266: Go over list of clients and stop any that are no longer connected.
// If the server has a new client connection it will be assigned to a free slot.
bool allSlotsOccupied = true;
@@ -443,7 +474,7 @@ MyMessage& gatewayTransportReceive(void)
return _ethernetMsg;
}
-#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_LINUX)
+#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_ESP32) && !defined(MY_GATEWAY_LINUX)
void gatewayTransportRenewIP(void)
{
/* renew/rebind IP address
diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp
index 4a92ae9f1..1c96dab96 100644
--- a/core/MyGatewayTransportMQTTClient.cpp
+++ b/core/MyGatewayTransportMQTTClient.cpp
@@ -22,6 +22,35 @@
#include "MyGatewayTransport.h"
+// housekeeping, remove for 3.0.0
+#ifdef MY_ESP8266_SSID
+#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead!
+#define MY_WIFI_SSID MY_ESP8266_SSID
+#undef MY_ESP8266_SSID // cleanup
+#endif
+
+#ifdef MY_ESP8266_PASSWORD
+#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead!
+#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD
+#undef MY_ESP8266_PASSWORD // cleanup
+#endif
+
+#ifdef MY_ESP8266_BSSID
+#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead!
+#define MY_WIFI_BSSID MY_ESP8266_BSSID
+#undef MY_ESP8266_BSSID // cleanup
+#endif
+
+#ifdef MY_ESP8266_HOSTNAME
+#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead!
+#define MY_HOSTNAME MY_ESP8266_HOSTNAME
+#undef MY_ESP8266_HOSTNAME // cleanup
+#endif
+
+#ifndef MY_WIFI_BSSID
+#define MY_WIFI_BSSID NULL
+#endif
+
#if defined MY_CONTROLLER_IP_ADDRESS
IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS);
#endif
@@ -30,19 +59,20 @@ IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS);
IPAddress _MQTT_clientIp(MY_IP_ADDRESS);
#if defined(MY_IP_GATEWAY_ADDRESS)
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
-#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */
+#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
// Assume the gateway will be the machine on the same network as the local IP
// but with last octet being '1'
IPAddress _gatewayIp(_MQTT_clientIp[0], _MQTT_clientIp[1], _MQTT_clientIp[2], 1);
#endif /* End of MY_IP_GATEWAY_ADDRESS */
+
#if defined(MY_IP_SUBNET_ADDRESS)
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
-#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */
+#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
IPAddress _subnetIp(255, 255, 255, 0);
#endif /* End of MY_IP_SUBNET_ADDRESS */
#endif /* End of MY_IP_ADDRESS */
-#if defined(MY_GATEWAY_ESP8266)
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
#define EthernetClient WiFiClient
#elif defined(MY_GATEWAY_LINUX)
// Nothing to do here
@@ -50,8 +80,24 @@ IPAddress _subnetIp(255, 255, 255, 0);
uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
#endif /* End of MY_GATEWAY_ESP8266 */
+#if defined(MY_GATEWAY_TINYGSM)
+#if defined(MY_GSM_RX) && defined(MY_GSM_TX)
+SoftwareSerial SerialAT(MY_GSM_RX, MY_GSM_TX);
+#endif
+static TinyGsm modem(SerialAT);
+static TinyGsmClient _MQTT_gsmClient(modem);
+static PubSubClient _MQTT_client(_MQTT_gsmClient);
+#if defined(MY_GSM_BAUDRATE)
+uint32_t rate = MY_GSM_BAUDRATE;
+#else /* Else part of MY_GSM_BAUDRATE */
+uint32_t rate = 0;
+#endif /* End of MY_GSM_BAUDRATE */
+#else /* Else part of MY_GATEWAY_TINYGSM */
static EthernetClient _MQTT_ethClient;
static PubSubClient _MQTT_client(_MQTT_ethClient);
+#endif /* End of MY_GATEWAY_TINYGSM */
+
+
static bool _MQTT_connecting = true;
static bool _MQTT_available = false;
static MyMessage _MQTT_msg;
@@ -104,17 +150,19 @@ bool reconnectMQTT(void)
bool gatewayTransportConnect(void)
{
-#if defined(MY_GATEWAY_ESP8266)
+#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
while (WiFi.status() != WL_CONNECTED) {
wait(500);
GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING...\n"));
}
GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"),WiFi.localIP().toString().c_str());
-#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */
+#elif defined(MY_GATEWAY_LINUX)
#if defined(MY_IP_ADDRESS)
_MQTT_ethClient.bind(_MQTT_clientIp);
#endif /* End of MY_IP_ADDRESS */
-#else /* Else part of MY_GATEWAY_ESP8266 */
+#elif defined(MY_GATEWAY_TINYGSM)
+ GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"), modem.getLocalIP().c_str());
+#else
#if defined(MY_IP_ADDRESS)
Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp);
#else /* Else part of MY_IP_ADDRESS */
@@ -130,13 +178,53 @@ bool gatewayTransportConnect(void)
Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]);
// give the Ethernet interface a second to initialize
delay(1000);
-#endif /* End of MY_GATEWAY_ESP8266 */
+#endif
return true;
}
bool gatewayTransportInit(void)
{
_MQTT_connecting = true;
+
+#if defined(MY_GATEWAY_TINYGSM)
+
+#if !defined(MY_GSM_BAUDRATE)
+ rate = TinyGsmAutoBaud(SerialAT);
+#endif /* End of MY_GSM_BAUDRATE */
+
+ SerialAT.begin(rate);
+ delay(3000);
+
+ modem.restart();
+
+#if defined(MY_GSM_PIN) && !defined(TINY_GSM_MODEM_ESP8266)
+ modem.simUnlock(MY_GSM_PIN);
+#endif /* End of MY_GSM_PIN */
+
+#ifndef TINY_GSM_MODEM_ESP8266
+ if (!modem.waitForNetwork()) {
+ GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
+ while (true);
+ }
+ GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
+
+ if (!modem.gprsConnect(MY_GSM_APN, MY_GSM_USR, MY_GSM_PSW)) {
+ GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
+ while (true);
+ }
+ GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
+ delay(1000);
+#else /* Else part of TINY_GSM_MODEM_ESP8266 */
+ if (!modem.networkConnect(MY_GSM_SSID, MY_GSM_PSW)) {
+ GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
+ while (true);
+ }
+ GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
+ delay(1000);
+#endif /* End of TINY_GSM_MODEM_ESP8266 */
+
+#endif /* End of MY_GATEWAY_TINYGSM */
+
#if defined(MY_CONTROLLER_IP_ADDRESS)
_MQTT_client.setServer(_brokerIp, MY_PORT);
#else
@@ -148,17 +236,30 @@ bool gatewayTransportInit(void)
#if defined(MY_GATEWAY_ESP8266)
// Turn off access point
WiFi.mode(WIFI_STA);
-#if defined(MY_ESP8266_HOSTNAME)
- WiFi.hostname(MY_ESP8266_HOSTNAME);
+#if defined(MY_HOSTNAME)
+ WiFi.hostname(MY_HOSTNAME);
#endif /* End of MY_ESP8266_HOSTNAME */
#if defined(MY_IP_ADDRESS)
WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp);
#endif /* End of MY_IP_ADDRESS */
-#ifndef MY_ESP8266_BSSID
-#define MY_ESP8266_BSSID NULL
+#ifndef MY_WIFI_BSSID
+#define MY_WIFI_BSSID NULL
+#endif
+ (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
+#elif defined(MY_GATEWAY_ESP32)
+ // Turn off access point
+ WiFi.mode(WIFI_STA);
+#if defined(MY_HOSTNAME)
+ WiFi.setHostname(MY_HOSTNAME);
+#endif /* End of MY_HOSTNAME */
+#if defined(MY_IP_ADDRESS)
+ WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp);
+#endif /* End of MY_IP_ADDRESS */
+#ifndef MY_WIFI_BSSID
+#define MY_WIFI_BSSID NULL
+#endif
+ (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
#endif
- (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID);
-#endif /* End of MY_GATEWAY_ESP8266 */
gatewayTransportConnect();
diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp
index 1cea59273..838272589 100644
--- a/core/MyMessage.cpp
+++ b/core/MyMessage.cpp
@@ -76,7 +76,6 @@ const char* MyMessage::getString() const
}
}
-// handles single character hex (0 - 15)
char MyMessage::i2h(uint8_t i) const
{
uint8_t k = i & 0x0F;
diff --git a/core/MyMessage.h b/core/MyMessage.h
index 91c08cb24..bdd465420 100644
--- a/core/MyMessage.h
+++ b/core/MyMessage.h
@@ -50,6 +50,7 @@ typedef enum {
C_STREAM = 4 //!< For firmware and other larger chunks of data that need to be divided into pieces.
} mysensor_command;
+#if !DOXYGEN // Hide until we migrate
/// @brief Type of sensor (used when presenting sensors)
typedef enum {
S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED
@@ -158,6 +159,7 @@ typedef enum {
V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA)
V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
} mysensor_data;
+#endif
/// @brief Type of internal messages (for internal messages)
@@ -206,7 +208,9 @@ typedef enum {
ST_FIRMWARE_REQUEST = 2, //!< Request FW block
ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
ST_SOUND = 4, //!< Sound
- ST_IMAGE = 5 //!< Image
+ ST_IMAGE = 5, //!< Image
+ ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
+ ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data
} mysensor_stream;
/// @brief Type of payload
@@ -275,23 +279,37 @@ typedef enum {
#define miGetPayloadType() (uint8_t)BF_GET(command_ack_payload, 5, 3) //!< Internal getter for payload type field
-#if !DOXYGEN
-#ifdef __cplusplus
+#if defined(__cplusplus) || defined(DOXYGEN)
+/**
+ * @brief MyMessage is used to create, manipulate, send and read MySensors messages
+ */
class MyMessage
{
private:
char* getCustomString(char *buffer) const;
public:
- // Constructors
+ /**
+ * Default constructor
+ */
MyMessage();
+ /**
+ * Constructor
+ * @param sensor id of the child sensor for this message
+ * @param type see http://korturl.nu/stupidurl
+ */
MyMessage(uint8_t sensor, uint8_t type);
+ /**
+ * Single character hex (0 - 15) conversion
+ * @param i byte (only lower 4 bits will be considered)
+ * @return single char with the hex representation (0 to F) of the parameter
+ */
char i2h(uint8_t i) const;
/**
- * Clear message contents.
+ * @brief Clear message contents.
*/
void clear();
@@ -299,42 +317,158 @@ class MyMessage
* If payload is something else than P_STRING you can have the payload value converted
* into string representation by supplying a buffer with the minimum size of
* 2*MAX_PAYLOAD+1. This is to be able to fit hex-conversion of a full binary payload.
+ * @param buffer pointer to a buffer that's at least 2*MAX_PAYLOAD+1 bytes large
*/
char* getStream(char *buffer) const;
+
+ /**
+ * @brief Copy the payload into the supplied buffer
+ */
char* getString(char *buffer) const;
+
+ /**
+ * @brief Get payload as string
+ * @return pointer to a char array storing the string
+ */
const char* getString() const;
+
+ /**
+ * @brief Get custom payload
+ * @return pointer to the raw payload
+ */
void* getCustom() const;
+
+ /**
+ * @brief Get bool payload
+ * @return a bool with the value of the payload (true/false)
+ */
bool getBool() const;
+
+ /**
+ * @brief Get unsigned 8-bit integer payload
+ * @return the value of the payload, 0 to 255
+ */
uint8_t getByte() const;
+
+ /**
+ * @brief Get float payload
+ * @return the floating-point value of the payload
+ */
float getFloat() const;
+
+ /**
+ * @brief Get signed 16-bit integer payload
+ * @return the value of the payload, –32768 to 32767
+ */
int16_t getInt() const;
+
+ /**
+ * @brief Get unsigned 16-bit integer payload
+ * @return the value of the payload, 0 to 65535
+ */
uint16_t getUInt() const;
+
+ /**
+ * @brief Get signed 32-bit integer payload
+ * @return the value of the payload, –2147483648 to 2147483647
+ */
int32_t getLong() const;
+
+ /**
+ * @brief Get unsigned 32-bit integer payload
+ * @return the value of the payload, 0 to 4294967295
+ */
uint32_t getULong() const;
- // Getter for command type
+ /**
+ * @brief Getter for command type
+ * @return #mysensor_command
+ */
uint8_t getCommand() const;
- // Getter for ack-flag. True if this is an ack message.
+ /**
+ * @brief Getter for ack-flag.
+ * @return true if this is an ack message
+ */
bool isAck() const;
- // Setters for building message "on the fly"
+ /**
+ * @brief Set message type
+ * @param type see http://korturl.nu/stupidurl
+ */
MyMessage& setType(uint8_t type);
+
+ /**
+ * @brief Set which child sensor this message belongs to
+ */
MyMessage& setSensor(uint8_t sensor);
+
+ /**
+ * @brief Set final destination node id for this message
+ */
MyMessage& setDestination(uint8_t destination);
- // Setters for payload
+ /**
+ * @brief Set entire payload
+ * @param payload pointer to the buffer where the payload is stored
+ * @param length of the payload
+ */
MyMessage& set(void* payload, uint8_t length);
+
+ /**
+ * @brief Set payload to character array
+ * @param value pointer to the character array. The array must be null-terminated.
+ */
MyMessage& set(const char* value);
#if !defined(__linux__)
+ /**
+ * @brief Set payload to character array from flash
+ * @param value pointer to the character array. The array must be null-terminated.
+ */
MyMessage& set(const __FlashStringHelper* value);
#endif
+
+ /**
+ * @brief Set payload to decimal number
+ * @param value float
+ * @param decimals number of decimals to include
+ */
MyMessage& set(float value, uint8_t decimals);
+
+ /**
+ * @brief Set payload to bool value
+ * @param value true or false
+ */
MyMessage& set(bool value);
+
+ /**
+ * @brief Set payload to unsigned 8-bit integer value
+ * @param value (0 to 255)
+ */
MyMessage& set(uint8_t value);
+
+ /**
+ * @brief Set payload to unsigned 32-bit integer value
+ * @param value (0 to 4294967295)
+ */
MyMessage& set(uint32_t value);
+
+ /**
+ * @brief Set payload to signed 32-bit integer value
+ * @param value (–2147483648 to 2147483647)
+ */
MyMessage& set(int32_t value);
+
+ /**
+ * @brief Set payload to unsigned 16-bit integer value
+ * @param value (0 to 65535)
+ */
MyMessage& set(uint16_t value);
+
+ /**
+ * @brief Set payload to signed 16-bit integer value
+ * @param value (–32768 to 32767)
+ */
MyMessage& set(int16_t value);
#else
@@ -343,47 +477,56 @@ typedef union {
struct {
#endif
- uint8_t last; // 8 bit - Id of last node this message passed
- uint8_t sender; // 8 bit - Id of sender node (origin)
- uint8_t destination; // 8 bit - Id of destination node
-
- uint8_t version_length; // 2 bit - Protocol version
- // 1 bit - Signed flag
- // 5 bit - Length of payload
- uint8_t command_ack_payload; // 3 bit - Command type
- // 1 bit - Request an ack - Indicator that receiver should send an ack back.
- // 1 bit - Is ack message - Indicator that this is the actual ack message.
- // 3 bit - Payload data type
- uint8_t type; // 8 bit - Type varies depending on command
- uint8_t sensor; // 8 bit - Id of sensor that this message concerns.
-
- // Each message can transfer a payload. We add one extra byte for string
- // terminator \0 to be "printable" this is not transferred OTA
- // This union is used to simplify the construction of the binary data types transferred.
+ uint8_t last; ///< 8 bit - Id of last node this message passed
+ uint8_t sender; ///< 8 bit - Id of sender node (origin)
+ uint8_t destination; ///< 8 bit - Id of destination node
+
+ /**
+ * 2 bit - Protocol version
+ * 1 bit - Signed flag
+ * 5 bit - Length of payload
+ */
+ uint8_t version_length;
+
+ /**
+ * 3 bit - Command type
+ * 1 bit - Request an ack - Indicator that receiver should send an ack back
+ * 1 bit - Is ack message - Indicator that this is the actual ack message
+ * 3 bit - Payload data type
+ */
+ uint8_t command_ack_payload;
+
+ uint8_t type; ///< 8 bit - Type varies depending on command
+ uint8_t sensor; ///< 8 bit - Id of sensor that this message concerns.
+
+ /*
+ * Each message can transfer a payload. We add one extra byte for string
+ * terminator \0 to be "printable" this is not transferred OTA
+ * This union is used to simplify the construction of the binary data types transferred.
+ */
union {
- uint8_t bValue;
- uint16_t uiValue;
- int16_t iValue;
- uint32_t ulValue;
- int32_t lValue;
- struct { // Float messages
+ uint8_t bValue; ///< unsigned byte value (8-bit)
+ uint16_t uiValue; ///< unsigned integer value (16-bit)
+ int16_t iValue; ///< signed integer value (16-bit)
+ uint32_t ulValue; ///< unsigned long value (32-bit)
+ int32_t lValue; ///< signed long value (32-bit)
+ struct { //< Float messages
float fValue;
- uint8_t fPrecision; // Number of decimals when serializing
+ uint8_t fPrecision; ///< Number of decimals when serializing
};
- struct { // Presentation messages
- uint8_t version; // Library version
- uint8_t sensorType; // Sensor type hint for controller, see table above
+ struct { //< Presentation messages
+ uint8_t version; ///< Library version
+ uint8_t sensorType; ///< Sensor type hint for controller, see table above
};
- char data[MAX_PAYLOAD + 1];
- } __attribute__((packed));
-#ifdef __cplusplus
+ char data[MAX_PAYLOAD + 1]; ///< Buffer for raw payload data
+ } __attribute__((packed)); ///< Doxygen will complain without this comment
+#if defined(__cplusplus) || defined(DOXYGEN)
} __attribute__((packed));
#else
};
-uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
+uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; ///< buffer for entire message
} __attribute__((packed)) MyMessage;
#endif
-#endif
#endif
/** @}*/
diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp
index 1b2aca889..35e3ce7cd 100644
--- a/core/MyOTAFirmwareUpdate.cpp
+++ b/core/MyOTAFirmwareUpdate.cpp
@@ -26,15 +26,30 @@ extern MyMessage _msgTmp;
// local variables
#ifdef MY_OTA_USE_I2C_EEPROM
I2CEeprom _flash(MY_OTA_I2C_ADDR);
-#else
+#elif !defined(MCUBOOT_PRESENT)
SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
#endif
+// Map flash functions
+#ifndef MCUBOOT_PRESENT
+#define _flash_initialize() _flash.initialize()
+#define _flash_readByte(addr) _flash.readByte(addr)
+#define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size)
+#define _flash_blockErase32K(num) _flash.blockErase32K(num)
+#define _flash_busy() _flash.busy()
+#else
+#define _flash_initialize() true
+#define _flash_readByte(addr) (*((uint8_t *)(addr)))
+#define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0)
+#define _flash_busy() false
+#endif
+
LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig;
LOCAL bool _firmwareUpdateOngoing = false;
LOCAL uint32_t _firmwareLastRequest;
LOCAL uint16_t _firmwareBlock;
LOCAL uint8_t _firmwareRetry;
+LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data);
LOCAL void readFirmwareSettings(void)
{
@@ -83,15 +98,15 @@ LOCAL bool firmwareOTAUpdateProcess(void)
// copy new FW config
(void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
// Init flash
- if (!_flash.initialize()) {
+ if (!_flash_initialize()) {
setIndication(INDICATION_ERR_FW_FLASH_INIT);
OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
_firmwareUpdateOngoing = false;
} else {
// erase lower 32K -> max flash size for ATMEGA328
- _flash.blockErase32K(0);
+ _flash_blockErase32K(0);
// wait until flash erased
- while ( _flash.busy() ) {}
+ while ( _flash_busy() ) {}
_firmwareBlock = _nodeFirmwareConfig.blocks;
_firmwareUpdateOngoing = true;
// reset flags
@@ -102,68 +117,46 @@ LOCAL bool firmwareOTAUpdateProcess(void)
}
OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
- if (_firmwareUpdateOngoing) {
- // extract FW block
- replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
-
- OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), firmwareResponse->block); // received FW block
- if (firmwareResponse->block != _firmwareBlock - 1) {
- OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
- // wrong firmware block received
- setIndication(INDICATION_FW_UPDATE_RX_ERR);
- // no further processing required
- return true;
- }
- setIndication(INDICATION_FW_UPDATE_RX);
- // Save block to flash
- _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
- firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
- // wait until flash written
- while (_flash.busy()) {}
-#ifdef OTA_EXTRA_FLASH_DEBUG
- {
- char prbuf[8];
- uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
- OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
- sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
- MY_SERIALDEVICE.print(prbuf);
- for(uint8_t i=0; iblock, firmwareResponse->data);
+#ifdef FIRMWARE_PROTOCOL_31
+ } else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) {
+ // RLE encoded block
+ // extract FW block
+ replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data;
+ uint8_t data[FIRMWARE_BLOCK_SIZE];
+ for (uint8_t i=0; idata;
+ }
+ while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) {
+ _firmwareResponse(firmwareResponse->block, data);
+ firmwareResponse->number_of_blocks--;
+ firmwareResponse->block--;
+ }
+ return true;
#endif
- _firmwareBlock--;
- if (!_firmwareBlock) {
- // We're done! Do a checksum and reboot.
- OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
- _firmwareUpdateOngoing = false;
- if (transportIsValidFirmware()) {
- OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
- // Write the new firmware config to eeprom
- hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
- sizeof(nodeFirmwareConfig_t));
- // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
- const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks;
- const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'};
- _flash.writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
- // wait until flash ready
- while (_flash.busy()) {}
- hwReboot();
- } else {
- setIndication(INDICATION_ERR_FW_CHECKSUM);
- OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
+ } else {
+#ifdef MCUBOOT_PRESENT
+ if (_msg.type == ST_FIRMWARE_CONFIRM) {
+ if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) {
+ if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) {
+ // Calculate data word to write
+ uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise
+ uint32_t img_ok_data = *img_ok_base_addr;
+ // Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01)
+ uint8_t * img_ok_array = (uint8_t*)(&img_ok_data);
+ img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE;
+ // Write word back
+ Flash.write(img_ok_base_addr, img_ok_data);
}
+ OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n"));
+ } else {
+ OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n"));
}
- // reset flags
- _firmwareRetry = MY_OTA_RETRY + 1;
- _firmwareLastRequest = 0;
- } else {
- OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
}
- return true;
+#endif
}
return false;
}
@@ -178,6 +171,18 @@ LOCAL void presentBootloaderInformation(void)
(void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t));
// add bootloader information
requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
+#ifdef FIRMWARE_PROTOCOL_31
+ requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE;
+#ifndef MCUBOOT_PRESENT
+ requestFirmwareConfig->img_commited = 0x2;
+ requestFirmwareConfig->img_revision = 0x00;
+ requestFirmwareConfig->img_build_num = 0x00;
+#else
+ requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR));
+ requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR));
+ requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR));
+#endif
+#endif
_firmwareUpdateOngoing = false;
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
ST_FIRMWARE_CONFIG_REQUEST, false));
@@ -192,8 +197,8 @@ LOCAL bool transportIsValidFirmware(void)
{
// init crc
uint16_t crc = ~0;
- for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
- crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET);
+ for (uint32_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
+ crc ^= _flash_readByte(i + FIRMWARE_START_OFFSET);
for (int8_t j = 0; j < 8; ++j) {
if (crc & 1) {
crc = (crc >> 1) ^ 0xA001;
@@ -207,3 +212,76 @@ LOCAL bool transportIsValidFirmware(void)
_nodeFirmwareConfig.crc);
return crc == _nodeFirmwareConfig.crc;
}
+
+LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data)
+{
+ if (_firmwareUpdateOngoing) {
+ OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block
+ if (block != _firmwareBlock - 1) {
+ OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
+ // wrong firmware block received
+ setIndication(INDICATION_FW_UPDATE_RX_ERR);
+ // no further processing required
+ return true;
+ }
+ setIndication(INDICATION_FW_UPDATE_RX);
+ // Save block to flash
+#ifdef MCUBOOT_PRESENT
+ uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)(
+ FIRMWARE_START_OFFSET));
+ if (addr>2);
+ }
+#else
+ _flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
+ data, FIRMWARE_BLOCK_SIZE);
+#endif
+ // wait until flash written
+ while (_flash_busy()) {}
+#ifdef OTA_EXTRA_FLASH_DEBUG
+ {
+ char prbuf[8];
+ uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
+ OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
+ sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
+ MY_SERIALDEVICE.print(prbuf);
+ for(uint8_t i=0; i> 8), (uint8_t)(firmwareSize & 0xff),':'};
+ _flash_writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
+ // wait until flash ready
+ while (_flash_busy()) {}
+#endif
+ hwReboot();
+ } else {
+ setIndication(INDICATION_ERR_FW_CHECKSUM);
+ OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
+ }
+ }
+ // reset flags
+ _firmwareRetry = MY_OTA_RETRY + 1;
+ _firmwareLastRequest = 0;
+ } else {
+ OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
+ }
+ return true;
+}
diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h
index 3e011df0e..321ffd340 100644
--- a/core/MyOTAFirmwareUpdate.h
+++ b/core/MyOTAFirmwareUpdate.h
@@ -58,17 +58,36 @@
#define MyOTAFirmwareUpdate_h
#include "MySensorsCore.h"
+#ifdef MCUBOOT_PRESENT
+#include "generated_dts_board.h"
+#define FIRMWARE_PROTOCOL_31
+#endif
#define LOCAL static //!< static
+#if MAX_PAYLOAD >= 22
#define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block
+#else
+#define FIRMWARE_BLOCK_SIZE (8u) //!< Size of each firmware block
+#ifndef FIRMWARE_PROTOCOL_31
+#define FIRMWARE_PROTOCOL_31
+#endif
+#endif
#define FIRMWARE_MAX_REQUESTS (5u) //!< Number of times a firmware block should be requested before giving up
#define MY_OTA_RETRY (5u) //!< Number of times to request a fw block before giving up
#define MY_OTA_RETRY_DELAY (500u) //!< Number of milliseconds before re-requesting a FW block
+#ifndef MCUBOOT_PRESENT
#define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first)
+#else
+#define FIRMWARE_START_OFFSET (FLASH_AREA_IMAGE_1_OFFSET_0) //!< Use offset from generated_dts_board.h (mcuboot)
+#endif
#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major
+#ifdef FIRMWARE_PROTOCOL_31
+#define MY_OTA_BOOTLOADER_MINOR_VERSION (1u) //!< Bootloader version minor
+#else
#define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor
+#endif
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version
#if defined(MY_DEBUG_VERBOSE_OTA_UPDATE)
@@ -77,6 +96,18 @@
#else
#define OTA_DEBUG(x,...) //!< debug NULL
#endif
+
+#if defined(DOXYGEN) && !defined(FIRMWARE_PROTOCOL_31)
+/**
+ * @brief Enabled FOTA 3.1 protocol extensions
+ *
+ * Supports smaller FIRMWARE_BLOCK_SIZE, RLE and NVM for nRF5 with mcuboot. The
+ * extension is enabled per default when mcuboot is present or full FIRMWARE_BLOCK_SIZE
+ * exeeds MAX_PAYLOAD.
+ */
+#define FIRMWARE_PROTOCOL_31
+#endif
+
/**
* @brief FW config structure, stored in eeprom
*/
@@ -96,6 +127,12 @@ typedef struct {
uint16_t blocks; //!< Number of blocks
uint16_t crc; //!< CRC of block data
uint16_t BLVersion; //!< Bootloader version
+#ifdef FIRMWARE_PROTOCOL_31
+ uint8_t blockSize; //!< Blocksize, when protocol version >= 3.1 is reported. Otherwhise the blocksize is 16
+ uint8_t img_commited; //!< mcuboot image_ok attribute commited firmware=0x01(mcuboot)|0x02(DualOptiboot), when protocol version >= 3.1 is reported
+ uint16_t img_revision; //!< mcuboot revision attribute, when protocol version >= 3.1 is reported
+ uint32_t img_build_num; //!< mcuboot build_num attribute, when protocol version >= 3.1 is reported
+#endif
} __attribute__((packed)) requestFirmwareConfig_t;
/**
@@ -117,6 +154,16 @@ typedef struct {
uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data
} __attribute__((packed)) replyFirmwareBlock_t;
+/**
+* @brief FW block reply structure (RLE)
+*/
+typedef struct {
+ uint16_t type; //!< Type of config
+ uint16_t version; //!< Version of config
+ uint16_t block; //!< Block index
+ uint16_t number_of_blocks; //!< Number of blocks to fill with data
+ uint8_t data; //!< Block data
+} __attribute__((packed)) replyFirmwareBlockRLE_t;
/**
* @brief Read firmware settings from EEPROM
diff --git a/core/MyOTALogging.cpp b/core/MyOTALogging.cpp
index 179934dfa..693290f83 100644
--- a/core/MyOTALogging.cpp
+++ b/core/MyOTALogging.cpp
@@ -36,11 +36,7 @@ void OTALog(uint8_t logNode, bool enableAck, const char *fmt, ... )
// create message
va_start (args, fmt );
-#ifdef vsnprintf_P
int n = vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
-#else
- int n = vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
-#endif
va_end (args);
// Check number of chars
@@ -92,14 +88,9 @@ void OTALogPrintPrefix()
{
char prefix[37];
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
-#ifdef snprintf_P
snprintf_P(prefix, sizeof(prefix),
PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "),
OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis());
-#else
- snprintf(prefix, sizeof(prefix), PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "),
- OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis());
-#endif
MY_SERIALDEVICE.print(prefix);
}
diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp
index c97157994..eb1f1aba9 100644
--- a/core/MySensorsCore.cpp
+++ b/core/MySensorsCore.cpp
@@ -32,6 +32,7 @@
#endif
// message buffers
+
MyMessage _msg; // Buffer for incoming messages
MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others)
@@ -88,6 +89,14 @@ void _infiniteLoop(void)
void _begin(void)
{
+#if defined(MY_CORE_ONLY)
+ // initialize HW and run setup if present
+ (void)hwInit();
+ if (setup) {
+ setup();
+ }
+ return;
+#endif
// reset wdt
hwWatchdogReset();
@@ -168,7 +177,7 @@ void _begin(void)
setup();
}
#if defined(MY_SENSOR_NETWORK)
- CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady());
+ CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady() && transportSanityCheck());
#else
// no sensor network defined, call presentation & registration
_callbackTransportReady();
@@ -585,7 +594,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in
#endif // MY_OTA_FIRMWARE_FEATURE
if (smartSleep) {
// sleeping time left?
- if (sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
+ if (sleepingTimeMS > 0 && sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
wait(sleepingMS);
CORE_DEBUG(PSTR("!MCO:SLP:NTL\n")); // sleeping not possible, no time left
return MY_SLEEP_NOT_POSSIBLE;
diff --git a/core/MySigning.h b/core/MySigning.h
index cce63093f..ecc3b172d 100644
--- a/core/MySigning.h
+++ b/core/MySigning.h
@@ -177,6 +177,16 @@
* personalization has finished, you just program the sketch you plan to use (with the appropriate
* signing flags set).
*
+ * If you are using a Raspberry PI-based gateway, personalizaion is done slightly differently:
+ * 1. Generate keys, execute @c mysgw with arguments
+ * * To generate HMAC key @verbatim --gen-soft-hmac-key @endverbatim
+ * * To generate %AES key @verbatim --gen-aes-key @endverbatim
+ * * To generate a soft serial number @verbatim --gen-soft-serial @endverbatim
+ * 2. Update the gateway config file with the generated keys/valeus
+ * * For HMAC key @verbatim soft_hmac_key= @endverbatim
+ * * For %AES key @verbatim aes_key= @endverbatim
+ * * For soft serial number @verbatim soft_serial_key= @endverbatim
+ *
* You are now set and ready to use message signing in your network.
* As of now, the following restrictions will be applied to your nodes:
* * If a node does require signing, any unsigned message sent to the node will be rejected.
@@ -393,8 +403,7 @@
* is to set your preferences in your sketch and personalize accordingly.
* That is enough to enable protection from both Eve and Mallory in your network
* although if you do not also enable encryption, Eve can eavesdrop, but not do anything about,
- * your messages (except possibly preventing them from arriving). @ref MY_SIGNING_SIMPLE_PASSWD also
- * enable encryption automatically.
+ * your messages (except possibly preventing them from arriving).
*
* How are the messages actually affected by the signing?
* The following illustration shows what part of the message is signed, and where the signature is
diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp
index 19c5f6591..acd7bca06 100644
--- a/core/MySigningAtsha204Soft.cpp
+++ b/core/MySigningAtsha204Soft.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp
index 5059510f9..06f0c1450 100644
--- a/core/MyTransport.cpp
+++ b/core/MyTransport.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
diff --git a/core/Version.h b/core/Version.h
index 5cffbecd1..0107653fc 100644
--- a/core/Version.h
+++ b/core/Version.h
@@ -47,9 +47,9 @@
#define STR(x) STR_HELPER(x) //!< Helper macro, STR()
#define MYSENSORS_LIBRARY_VERSION_MAJOR 2 //!< Major release version
-#define MYSENSORS_LIBRARY_VERSION_MINOR 2 //!< Minor release version
+#define MYSENSORS_LIBRARY_VERSION_MINOR 3 //!< Minor release version
#define MYSENSORS_LIBRARY_VERSION_PATCH 0 //!< Patch version
-#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc
+#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "alpha" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc
#define MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER 0xFF //!< incremental counter, starting at 0x00. 0xFF for final release
diff --git a/drivers/AES/AES_config.h b/drivers/AES/AES_config.h
index ab3848960..aa608a1a4 100644
--- a/drivers/AES/AES_config.h
+++ b/drivers/AES/AES_config.h
@@ -31,6 +31,8 @@ typedef unsigned char byte;
#define PSTR(x) (x)
#elif defined(ARDUINO_ARCH_ESP8266)
#include
+#elif defined(ARDUINO_ARCH_ESP32)
+#include
#elif defined(ARDUINO_ARCH_SAMD)
#define printf_P printf
#else
diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp
index c5686e84b..446e7177f 100644
--- a/drivers/Linux/EthernetClient.cpp
+++ b/drivers/Linux/EthernetClient.cpp
@@ -220,9 +220,8 @@ void EthernetClient::stop()
gettimeofday(&startTime, NULL);
// wait up to a second for the connection to close
- uint8_t s;
do {
- s = status();
+ uint8_t s = status();
if (s == ETHERNETCLIENT_W5100_CLOSED) {
break; // exit the loop
}
@@ -231,10 +230,8 @@ void EthernetClient::stop()
} while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) <
1000000);
- // if it hasn't closed, close it forcefully
- if (s != ETHERNETCLIENT_W5100_CLOSED) {
- ::close(_sock);
- }
+ // free up the socket descriptor
+ ::close(_sock);
_sock = -1;
}
diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp
index 9bbeb0eb7..58d0b5c0a 100644
--- a/drivers/Linux/EthernetServer.cpp
+++ b/drivers/Linux/EthernetServer.cpp
@@ -155,13 +155,11 @@ size_t EthernetServer::write(uint8_t b)
size_t EthernetServer::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
- size_t i = 0;
- while (i < clients.size()) {
+ for (size_t i = 0; i < clients.size(); ++i) {
EthernetClient client(clients[i]);
if (client.status() == ETHERNETCLIENT_W5100_ESTABLISHED) {
n += client.write(buffer, size);
- i++;
}
}
diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp
index 4c04f5ddc..f7980c295 100644
--- a/drivers/Linux/SoftEeprom.cpp
+++ b/drivers/Linux/SoftEeprom.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -26,84 +26,95 @@
#include "log.h"
#include "SoftEeprom.h"
-SoftEeprom::SoftEeprom(const char *fileName, size_t length)
+SoftEeprom::SoftEeprom() : _length(0), _fileName(NULL), _values(NULL)
+{
+}
+
+SoftEeprom::SoftEeprom(const SoftEeprom& other)
+{
+ _fileName = strdup(other._fileName);
+
+ _length = other._length;
+ _values = new uint8_t[_length];
+ for (size_t i = 0; i < _length; ++i) {
+ _values[i] = other._values[i];
+ }
+}
+
+SoftEeprom::~SoftEeprom()
+{
+ destroy();
+}
+
+int SoftEeprom::init(const char *fileName, size_t length)
{
struct stat fileInfo;
+ destroy();
+
_fileName = strdup(fileName);
if (_fileName == NULL) {
logError("Error: %s\n", strerror(errno));
- exit(1);
+ return -1;
}
_length = length;
_values = new uint8_t[_length];
- for (size_t i = 0; i < _length; ++i) {
- _values[i] = 0xFF;
- }
if (stat(_fileName, &fileInfo) != 0) {
//File does not exist. Create it.
- logInfo("Config file %s does not exist, creating new config file.\n", _fileName);
+ logInfo("EEPROM file %s does not exist, creating new file.\n", _fileName);
std::ofstream myFile(_fileName, std::ios::out | std::ios::binary);
if (!myFile) {
logError("Unable to create config file %s.\n", _fileName);
- exit(1);
+ return -1;
+ }
+ // Fill the eeprom with 1s
+ for (size_t i = 0; i < _length; ++i) {
+ _values[i] = 0xFF;
}
myFile.write((const char*)_values, _length);
myFile.close();
} else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) {
- logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n",
+ logError("EEPROM file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n",
_fileName, _length);
- exit(1);
+ destroy();
+ return -1;
} else {
//Read config into local memory.
std::ifstream myFile(_fileName, std::ios::in | std::ios::binary);
if (!myFile) {
- logError("Unable to open config to file %s for reading.\n", _fileName);
- exit(1);
+ logError("Unable to open EEPROM file %s for reading.\n", _fileName);
+ return -1;
}
myFile.read((char*)_values, _length);
myFile.close();
}
-}
-SoftEeprom::SoftEeprom(const SoftEeprom& other)
-{
- _fileName = strdup(other._fileName);
-
- _length = other._length;
- _values = new uint8_t[_length];
- for (size_t i = 0; i < _length; ++i) {
- _values[i] = other._values[i];
- }
+ return 0;
}
-SoftEeprom::~SoftEeprom()
+void SoftEeprom::destroy()
{
- delete[] _values;
- free(_fileName);
+ if (_values) {
+ delete[] _values;
+ }
+ if (_fileName) {
+ free(_fileName);
+ }
+ _length = 0;
}
void SoftEeprom::readBlock(void* buf, void* addr, size_t length)
{
- static bool config_to_mem = false;
unsigned long int offs = reinterpret_cast(addr);
- if (!config_to_mem) {
- //Read config into local memory.
- std::ifstream myFile(_fileName, std::ios::in | std::ios::binary);
- if (!myFile) {
- logError("Unable to open config to file %s for reading.\n", _fileName);
- exit(1);
- }
- myFile.read((char*)_values, _length);
- myFile.close();
-
- config_to_mem = true;
+ if (!length) {
+ logError("EEPROM being read without being initialized!\n");
+ return;
}
- if (length && offs + length <= _length) {
+ if (offs + length <= _length) {
memcpy(buf, _values+offs, length);
}
}
@@ -112,7 +123,16 @@ void SoftEeprom::writeBlock(void* buf, void* addr, size_t length)
{
unsigned long int offs = reinterpret_cast(addr);
- if (length && offs + length <= _length) {
+ if (!length) {
+ logError("EEPROM being written without being initialized!\n");
+ return;
+ }
+
+ if (offs + length <= _length) {
+ if (memcmp(_values+offs, buf, length) == 0) {
+ return;
+ }
+
memcpy(_values+offs, buf, length);
std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary);
@@ -144,6 +164,9 @@ void SoftEeprom::writeByte(int addr, uint8_t value)
SoftEeprom& SoftEeprom::operator=(const SoftEeprom& other)
{
if (this != &other) {
+ delete[] _values;
+ free(_fileName);
+
_fileName = strdup(other._fileName);
_length = other._length;
diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h
index 6b2431830..806bb0a74 100644
--- a/drivers/Linux/SoftEeprom.h
+++ b/drivers/Linux/SoftEeprom.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -37,7 +37,7 @@ class SoftEeprom
/**
* @brief SoftEeprom constructor.
*/
- SoftEeprom(const char *fileName, size_t length);
+ SoftEeprom();
/**
* @brief SoftEeprom copy constructor.
*/
@@ -46,6 +46,19 @@ class SoftEeprom
* @brief SoftEeprom destructor.
*/
~SoftEeprom();
+ /**
+ * @brief Initializes the eeprom class.
+ *
+ * @param fileName filepath where the data is saved.
+ * @param length eeprom size in bytes.
+ * @return 0 if SUCCESS or -1 if FAILURE.
+ */
+ int init(const char *fileName, size_t length);
+ /**
+ * @brief Clear all allocated memory variables.
+ *
+ */
+ void destroy();
/**
* @brief Read a block of bytes from eeprom.
*
diff --git a/drivers/Linux/SerialSimulator.cpp b/drivers/Linux/StdInOutStream.cpp
similarity index 80%
rename from drivers/Linux/SerialSimulator.cpp
rename to drivers/Linux/StdInOutStream.cpp
index b14cb6576..d9867d15a 100644
--- a/drivers/Linux/SerialSimulator.cpp
+++ b/drivers/Linux/StdInOutStream.cpp
@@ -18,39 +18,39 @@
*/
#include
-#include "SerialSimulator.h"
+#include "StdInOutStream.h"
-void SerialSimulator::begin(int baud)
+void StdInOutStream::begin(int baud)
{
(void)baud;
}
-int SerialSimulator::available()
+int StdInOutStream::available()
{
return 1;
}
-int SerialSimulator::read()
+int StdInOutStream::read()
{
return getchar();
}
-size_t SerialSimulator::write(uint8_t b)
+size_t StdInOutStream::write(uint8_t b)
{
return (size_t)::printf("%c", b);
}
-int SerialSimulator::peek()
+int StdInOutStream::peek()
{
return -1;
}
-void SerialSimulator::flush()
+void StdInOutStream::flush()
{
fflush(stdout);
}
-void SerialSimulator::end()
+void StdInOutStream::end()
{
flush();
}
diff --git a/drivers/Linux/SerialSimulator.h b/drivers/Linux/StdInOutStream.h
similarity index 91%
rename from drivers/Linux/SerialSimulator.h
rename to drivers/Linux/StdInOutStream.h
index 2007d2185..2f0356ee8 100644
--- a/drivers/Linux/SerialSimulator.h
+++ b/drivers/Linux/StdInOutStream.h
@@ -17,8 +17,8 @@
* version 2 as published by the Free Software Foundation.
*/
-#ifndef SerialSimulator_h
-#define SerialSimulator_h
+#ifndef StdInOutStream_h
+#define StdInOutStream_h
#include
#include
@@ -26,9 +26,9 @@
#include "Stream.h"
/**
- * @brief A class equivalent to Serial in Arduino but outputs to stdout
+ * @brief A class that prints to stdout and reads from stdin
*/
-class SerialSimulator : public Stream
+class StdInOutStream : public Stream
{
public:
diff --git a/drivers/Linux/config.c b/drivers/Linux/config.c
new file mode 100644
index 000000000..79252edfc
--- /dev/null
+++ b/drivers/Linux/config.c
@@ -0,0 +1,304 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Based on mosquitto project, Copyright (c) 2012 Roger Light
+ */
+
+#include "config.h"
+#include
+#include
+#include
+#include
+#include
+#include "log.h"
+
+static int _config_create(const char *config_file);
+static int _config_parse_int(char *token, const char *name, int *value);
+static int _config_parse_string(char *token, const char *name, char **value);
+
+int config_parse(const char *config_file)
+{
+ FILE *fptr;
+ char buf[1024];
+ struct stat fileInfo;
+
+ if (stat(config_file, &fileInfo) != 0) {
+ //File does not exist. Create it.
+ logInfo("Config file %s does not exist, creating new file.\n", config_file);
+ _config_create(config_file);
+ }
+
+ fptr = fopen(config_file, "rt");
+ if (!fptr) {
+ logError("Error opening config file \"%s\".\n", config_file);
+ return -1;
+ }
+
+ conf.verbose = 7;
+ conf.log_pipe = 0;
+ conf.log_pipe_file = NULL;
+ conf.syslog = 0;
+ conf.eeprom_file = NULL;
+ conf.eeprom_size = 0;
+ conf.soft_hmac_key = NULL;
+ conf.soft_serial_key = NULL;
+ conf.aes_key = NULL;
+
+ while (fgets(buf, 1024, fptr)) {
+ if (buf[0] != '#' && buf[0] != 10 && buf[0] != 13) {
+ while (buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13) {
+ buf[strlen(buf)-1] = 0;
+ }
+
+ if (!strncmp(buf, "verbose=", 8)) {
+ char *verbose = NULL;
+ if (_config_parse_string(&(buf[8]), "verbose", &verbose)) {
+ fclose(fptr);
+ return -1;
+ } else {
+ if (!strncmp(verbose, "err", 3)) {
+ conf.verbose = 3;
+ } else if (!strncmp(verbose, "warn", 4)) {
+ conf.verbose = 4;
+ } else if (!strncmp(verbose, "notice", 6)) {
+ conf.verbose = 5;
+ } else if (!strncmp(verbose, "info", 4)) {
+ conf.verbose = 6;
+ } else if (!strncmp(verbose, "debug", 5)) {
+ conf.verbose = 7;
+ } else {
+ logError("Invalid value for verbose in configuration.\n");
+ fclose(fptr);
+ free(verbose);
+ return -1;
+ }
+ free(verbose);
+ }
+ } else if (!strncmp(buf, "log_file=", 9)) {
+ if (_config_parse_int(&(buf[9]), "log_file", &conf.log_file)) {
+ fclose(fptr);
+ return -1;
+ } else {
+ if (conf.log_file != 0 && conf.log_file != 1) {
+ logError("log_file must be 1 or 0 in configuration.\n");
+ fclose(fptr);
+ return -1;
+ }
+ }
+ } else if (!strncmp(buf, "log_filepath=", 13)) {
+ if (_config_parse_string(&(buf[13]), "log_filepath", &conf.log_filepath)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else if (!strncmp(buf, "log_pipe=", 9)) {
+ if (_config_parse_int(&(buf[9]), "log_pipe", &conf.log_pipe)) {
+ fclose(fptr);
+ return -1;
+ } else {
+ if (conf.log_pipe != 0 && conf.log_pipe != 1) {
+ logError("log_pipe must be 1 or 0 in configuration.\n");
+ fclose(fptr);
+ return -1;
+ }
+ }
+ } else if (!strncmp(buf, "log_pipe_file=", 14)) {
+ if (_config_parse_string(&(buf[14]), "log_pipe_file", &conf.log_pipe_file)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else if (!strncmp(buf, "syslog=", 7)) {
+ if (_config_parse_int(&(buf[7]), "syslog", &conf.syslog)) {
+ fclose(fptr);
+ return -1;
+ } else {
+ if (conf.syslog != 0 && conf.syslog != 1) {
+ logError("syslog must be 1 or 0 in configuration.\n");
+ fclose(fptr);
+ return -1;
+ }
+ }
+ } else if (!strncmp(buf, "eeprom_file=", 12)) {
+ if (_config_parse_string(&(buf[12]), "eeprom_file", &conf.eeprom_file)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else if (!strncmp(buf, "eeprom_size=", 12)) {
+ if (_config_parse_int(&(buf[12]), "eeprom_size", &conf.eeprom_size)) {
+ fclose(fptr);
+ return -1;
+ } else {
+ if (conf.eeprom_size <= 0) {
+ logError("eeprom_size value must be greater than 0 in configuration.\n");
+ fclose(fptr);
+ return -1;
+ }
+ }
+ } else if (!strncmp(buf, "soft_hmac_key=", 14)) {
+ if (_config_parse_string(&(buf[14]), "soft_hmac_key", &conf.soft_hmac_key)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else if (!strncmp(buf, "soft_serial_key=", 16)) {
+ if (_config_parse_string(&(buf[16]), "soft_serial_key", &conf.soft_serial_key)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else if (!strncmp(buf, "aes_key=", 8)) {
+ if (_config_parse_string(&(buf[8]), "aes_key", &conf.aes_key)) {
+ fclose(fptr);
+ return -1;
+ }
+ } else {
+ logWarning("Unknown config option \"%s\".\n", buf);
+ }
+ }
+ }
+ fclose(fptr);
+
+ if (!conf.eeprom_file) {
+ logError("No eeprom_file found in configuration.\n");
+ return -1;
+ }
+
+ if (conf.log_file && !conf.log_filepath) {
+ logError("log_filepath must be set if you enable log_file in configuration.\n");
+ return -1;
+ }
+
+ if (conf.log_pipe && !conf.log_pipe_file) {
+ logError("log_pipe_file must be set if you enable log_pipe in configuration.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void config_cleanup(void)
+{
+ if (conf.log_filepath) {
+ free(conf.log_filepath);
+ }
+ if (conf.log_pipe_file) {
+ free(conf.log_pipe_file);
+ }
+ if (conf.eeprom_file) {
+ free(conf.eeprom_file);
+ }
+ if (conf.soft_hmac_key) {
+ free(conf.soft_hmac_key);
+ }
+ if (conf.soft_serial_key) {
+ free(conf.soft_serial_key);
+ }
+ if (conf.aes_key) {
+ free(conf.aes_key);
+ }
+}
+
+int _config_create(const char *config_file)
+{
+ FILE *myFile;
+ int ret;
+
+ const char default_conf[] = "# Logging\n" \
+ "# Verbosity: debug,info,notice,warn,err\n" \
+ "verbose=debug\n" \
+ "\n" \
+ "# Enable logging to a file.\n" \
+ "log_file=0\n" \
+ "# Log file path.\n" \
+ "log_filepath=/tmp/mysgw.log\n" \
+ "\n" \
+ "# Enable logging to a named pipe.\n" \
+ "# Use this option to view your gateway's log messages\n" \
+ "# from the log_pipe_file defined bellow.\n" \
+ "# To do so, run the following command on another terminal:\n" \
+ "# cat \"log_pipe_file\"\n" \
+ "log_pipe=0\n" \
+ "log_pipe_file=/tmp/mysgw.pipe\n" \
+ "\n" \
+ "# Enable logging to syslog.\n" \
+ "syslog=0\n" \
+ "\n" \
+ "# EEPROM settings\n" \
+ "eeprom_file=/etc/mysensors.eeprom\n" \
+ "eeprom_size=1024\n" \
+ "\n" \
+ "# Software signing settings\n" \
+ "# Note: The gateway must have been built with signing\n" \
+ "# support to use the options below.\n" \
+ "#\n" \
+ "# To generate a HMAC key run mysgw with: --gen-soft-hmac-key\n" \
+ "# copy the new key in the line below and uncomment it.\n" \
+ "#soft_hmac_key=\n" \
+ "# To generate a serial key run mysgw with: --gen-soft-serial-key\n" \
+ "# copy the new key in the line below and uncomment it.\n" \
+ "#soft_serial_key=\n" \
+ "\n" \
+ "# Encryption settings\n" \
+ "# Note: The gateway must have been built with encryption\n" \
+ "# support to use the options below.\n" \
+ "#\n" \
+ "# To generate a AES key run mysgw with: --gen-aes-key\n" \
+ "# copy the new key in the line below and uncomment it.\n" \
+ "#aes_key=\n";
+
+ myFile = fopen(config_file, "w");
+ if (!myFile) {
+ logError("Unable to create config file %s.\n", config_file);
+ return -1;
+ }
+ ret = fputs(default_conf, myFile);
+ fclose(myFile);
+
+ return (ret > 0);
+}
+
+int _config_parse_int(char *token, const char *name, int *value)
+{
+ if (token) {
+ *value = atoi(token);
+ } else {
+ logError("Empty %s value in configuration.\n", name);
+ return 1;
+ }
+
+ return 0;
+}
+
+int _config_parse_string(char *token, const char *name, char **value)
+{
+ if (token) {
+ if (*value) {
+ logError("Duplicate %s value in configuration.\n", name);
+ return 1;
+ }
+ while (token[0] == ' ' || token[0] == '\t') {
+ token++;
+ }
+ *value = strdup(token);
+ if (!*value) {
+ logError("Out of memory.\n");
+ return 1;
+ }
+ } else {
+ logError("Empty %s value in configuration.\n", name);
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/Linux/config.h b/drivers/Linux/config.h
new file mode 100644
index 000000000..988cfbae4
--- /dev/null
+++ b/drivers/Linux/config.h
@@ -0,0 +1,48 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct config {
+ int verbose;
+ int log_file;
+ char *log_filepath;
+ int log_pipe;
+ char *log_pipe_file;
+ int syslog;
+ char *eeprom_file;
+ int eeprom_size;
+ char *soft_hmac_key;
+ char *soft_serial_key;
+ char *aes_key;
+} conf;
+
+int config_parse(const char *config_file);
+void config_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/drivers/Linux/log.c b/drivers/Linux/log.c
index 8d33c6fe5..a88bb2df0 100644
--- a/drivers/Linux/log.c
+++ b/drivers/Linux/log.c
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -19,123 +19,259 @@
#include "log.h"
#include
-#include
-#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
-// Default values
-static const int log_opts = LOG_CONS | LOG_PERROR; // print syslog to stderror
-static const int log_facility = LOG_USER;
+static const char *_log_level_colors[] = {
+ "\x1b[1;5;91m", "\x1b[1;91m", "\x1b[91m", "\x1b[31m", "\x1b[33m", "\x1b[34m", "\x1b[32m", "\x1b[36m"
+};
+static const char *_log_level_names[] = {
+ "EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"
+};
+static uint8_t _log_quiet = 0;
+static uint8_t _log_level = LOG_DEBUG;
+static uint8_t _log_syslog = 0;
-static uint8_t log_open = 0;
+static uint8_t _log_pipe = 0;
+static char *_log_pipe_file = NULL;
+static int _log_pipe_fd = -1;
-void logOpen(int options, int facility)
+static FILE *_log_file_fp = NULL;
+
+void logSetQuiet(uint8_t enable)
+{
+ _log_quiet = enable ? 1 : 0;
+}
+
+void logSetLevel(int level)
+{
+ if (level < LOG_EMERG || level > LOG_DEBUG) {
+ return;
+ }
+
+ _log_level = level;
+}
+
+void logSetSyslog(int options, int facility)
{
openlog(NULL, options, facility);
- log_open = 1;
+ _log_syslog = 1;
+}
+
+int logSetPipe(char *pipe_file)
+{
+ if (pipe_file == NULL) {
+ return -1;
+ }
+
+ _log_pipe_file = strdup(pipe_file);
+ if (_log_pipe_file == NULL) {
+ return -1;
+ }
+
+ int ret = mkfifo(_log_pipe_file, 0666);
+ if (ret == 0) {
+ _log_pipe = 1;
+ }
+
+ return ret;
}
-void vlogInfo(const char *fmt, va_list args)
+int logSetFile(char *file)
{
- if (!log_open) {
- logOpen(log_opts, log_facility);
+ if (file == NULL) {
+ return -1;
+ }
+
+ _log_file_fp = fopen(file, "a");
+ if (_log_file_fp == NULL) {
+ return errno;
+ }
+
+ return 0;
+}
+
+void logClose(void)
+{
+ if (_log_syslog) {
+ closelog();
+ _log_syslog = 0;
+ }
+
+ if (_log_pipe) {
+ if (_log_pipe_fd > 0) {
+ close(_log_pipe_fd);
+ }
+ /* remove the FIFO */
+ unlink(_log_pipe_file);
+ _log_pipe = 0;
+ }
+ if (_log_pipe_file != NULL) {
+ free(_log_pipe_file);
+ _log_pipe_file = NULL;
+ }
+
+ if (_log_file_fp != NULL) {
+ fclose(_log_file_fp);
+ _log_file_fp = NULL;
+ }
+}
+
+void vlog(int level, const char *fmt, va_list args)
+{
+ if (_log_level < level) {
+ return;
+ }
+
+ if (!_log_quiet || _log_file_fp != NULL) {
+ /* Get current time */
+ time_t t = time(NULL);
+ struct tm *lt = localtime(&t);
+
+ char date[16];
+ date[strftime(date, sizeof(date), "%b %d %H:%M:%S", lt)] = '\0';
+
+ if (_log_file_fp != NULL) {
+ fprintf(_log_file_fp, "%s %-5s ", date, _log_level_names[level]);
+ vfprintf(_log_file_fp, fmt, args);
+ }
+
+ if (!_log_quiet) {
+#ifdef LOG_DISABLE_COLOR
+ (void)_log_level_colors;
+ fprintf(stderr, "%s %-5s ", date, _log_level_names[level]);
+ vfprintf(stderr, fmt, args);
+#else
+ fprintf(stderr, "%s %s%-5s\x1b[0m ", date, _log_level_colors[level], _log_level_names[level]);
+ vfprintf(stderr, fmt, args);
+#endif
+ }
+ }
+
+ if (_log_syslog) {
+ vsyslog(level, fmt, args);
+ }
+
+ if (_log_pipe) {
+ if (_log_pipe_fd < 0) {
+ _log_pipe_fd = open(_log_pipe_file, O_WRONLY | O_NONBLOCK);
+ }
+ if (_log_pipe_fd > 0) {
+ if (vdprintf(_log_pipe_fd, fmt, args) < 0) {
+ close(_log_pipe_fd);
+ _log_pipe_fd = -1;
+ }
+ }
+
}
- vsyslog(LOG_INFO, fmt, args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
-logInfo(const char *fmt, ...)
+logEmergency(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vlogInfo(fmt, args);
+ vlog(LOG_EMERG, fmt, args);
va_end(args);
}
-void vlogError(const char *fmt, va_list args)
-{
- if (!log_open) {
- logOpen(log_opts, log_facility);
- }
- vsyslog(LOG_ERR, fmt, args);
-}
-
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
-logError(const char *fmt, ...)
+logAlert(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vlogError(fmt, args);
+ vlog(LOG_ALERT, fmt, args);
va_end(args);
}
-void vlogNotice(const char *fmt, va_list args)
+void
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+logCritical(const char *fmt, ...)
{
- if (!log_open) {
- logOpen(log_opts, log_facility);
- }
- vsyslog(LOG_NOTICE, fmt, args);
+ va_list args;
+
+ va_start(args, fmt);
+ vlog(LOG_CRIT, fmt, args);
+ va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
-logNotice(const char *fmt, ...)
+logError(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vlogNotice(fmt, args);
+ vlog(LOG_ERR, fmt, args);
va_end(args);
}
-void vlogDebug(const char *fmt, va_list args)
+void
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+logWarning(const char *fmt, ...)
{
- if (!log_open) {
- logOpen(log_opts, log_facility);
- }
- vsyslog(LOG_DEBUG, fmt, args);
+ va_list args;
+
+ va_start(args, fmt);
+ vlog(LOG_WARNING, fmt, args);
+ va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
-logDebug(const char *fmt, ...)
+logNotice(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vlogDebug(fmt, args);
+ vlog(LOG_NOTICE, fmt, args);
va_end(args);
}
-void vlogWarning(const char *fmt, va_list args)
+void
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+logInfo(const char *fmt, ...)
{
- if (!log_open) {
- logOpen(log_opts, log_facility);
- }
- vsyslog(LOG_WARNING, fmt, args);
+ va_list args;
+
+ va_start(args, fmt);
+ vlog(LOG_INFO, fmt, args);
+ va_end(args);
}
void
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
-logWarning(const char *fmt, ...)
+logDebug(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vlogWarning(fmt, args);
+ vlog(LOG_DEBUG, fmt, args);
va_end(args);
}
diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h
index b49758086..0cecfc42c 100644
--- a/drivers/Linux/log.h
+++ b/drivers/Linux/log.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -21,27 +21,36 @@
#define LOG_H
#include
+#include
+#include
+#include
#ifdef __cplusplus
extern "C" {
#endif
-extern void logOpen(int options, int facility);
-
-extern void vlogInfo(const char *fmt, va_list args);
-extern void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2)));
-
-extern void vlogError(const char *fmt, va_list args);
-extern void logError(const char *fmt, ...) __attribute__((format(printf,1,2)));
-
-extern void vlogNotice(const char *fmt, va_list args);
-extern void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2)));
-
-extern void vlogDebug(const char *fmt, va_list args);
-extern void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
-
-extern void vlogWarning(const char *fmt, va_list args);
-extern void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2)));
+#define vlogError(...) vlog(LOG_ERR, __VA_ARGS__)
+#define vlogWarning(...) vlog(LOG_WARNING, __VA_ARGS__)
+#define vlogNotice(...) vlog(LOG_NOTICE, __VA_ARGS__)
+#define vlogInfo(...) vlog(LOG_INFO, __VA_ARGS__)
+#define vlogDebug(...) vlog(LOG_DEBUG, __VA_ARGS__)
+
+void logSetQuiet(uint8_t enable);
+void logSetLevel(int level);
+void logSetSyslog(int options, int facility);
+int logSetPipe(char *pipe_file);
+int logSetFile(char *file);
+void logClose(void);
+
+void vlog(int level, const char *fmt, va_list args);
+void logEmergency(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logAlert(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logCritical(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logError(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
#ifdef __cplusplus
}
diff --git a/drivers/NRF5/Flash.cpp b/drivers/NRF5/Flash.cpp
index 298f0f180..bc7720edd 100644
--- a/drivers/NRF5/Flash.cpp
+++ b/drivers/NRF5/Flash.cpp
@@ -52,12 +52,14 @@ uint32_t *FlashClass::page_address(size_t page)
uint32_t *FlashClass::top_app_page_address()
{
+#if !defined(MCUBOOT_PRESENT)
// Bootcode at the top of the flash memory?
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Flib_bootloader.html
if (NRF_UICR->NRFFW[0]<0xFFFFFFFF) {
// Return pointer calculated by SoftDevice/bootloader
return (uint32_t *)NRF_UICR->NRFFW[0];
}
+#endif
// Return flash length
return (uint32_t *)(Flash.page_count() << Flash.page_size_bits());
diff --git a/drivers/NRF5/Radio_ESB.cpp b/drivers/NRF5/Radio_ESB.cpp
index 03472cfb8..3b0a929eb 100644
--- a/drivers/NRF5/Radio_ESB.cpp
+++ b/drivers/NRF5/Radio_ESB.cpp
@@ -637,7 +637,7 @@ extern "C" {
(NRF_RADIO->STATE == RADIO_STATE_STATE_RxDisable) or
(NRF_RADIO->STATE == RADIO_STATE_STATE_TxRu)) {
if (NRF_RADIO->CRCSTATUS) {
- // Ensure no ACK package is recieved
+ // Ensure no ACK package is received
if (NRF_RADIO->RXMATCH != NRF5_ESB_TX_ADDR) {
// calculate a package id
uint32_t pkgid = rx_buffer.pid << 16 | NRF_RADIO->RXCRC;
diff --git a/drivers/NVM/VirtualPage.cpp b/drivers/NVM/VirtualPage.cpp
index 760120c7d..6eaeb7e33 100644
--- a/drivers/NVM/VirtualPage.cpp
+++ b/drivers/NVM/VirtualPage.cpp
@@ -21,37 +21,45 @@
VirtualPageClass VirtualPage;
-#ifndef VNM_VIRTUAL_PAGE_SIZE_BITS
-#define VNM_VIRTUAL_PAGE_SIZE_BITS 12
-#elif VNM_VIRTUAL_PAGE_SIZE_BITS < 12
-#error "VNM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
+#ifndef NVM_VIRTUAL_PAGE_SIZE_BITS
+#define NVM_VIRTUAL_PAGE_SIZE_BITS 12
+#elif NVM_VIRTUAL_PAGE_SIZE_BITS < 12
+#error "NVM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
+#endif
+
+// Calculate virtual page count, when mcuboot is present
+#if defined(MCUBOOT_PRESENT) && !defined(NVM_VIRTUAL_PAGE_COUNT)
+// mcuboot zephyr build via generated_dts_board.h
+#include "generated_dts_board.h"
+// Calculate number of free pages after scratch area
+#define NVM_VIRTUAL_PAGE_COUNT (((CONFIG_FLASH_SIZE_0<<10)-(FLASH_AREA_IMAGE_SCRATCH_OFFSET_0+FLASH_AREA_IMAGE_SCRATCH_SIZE_0)) >> NVM_VIRTUAL_PAGE_SIZE_BITS)
#endif
// check page size
-#ifndef VNM_VIRTUAL_PAGE_COUNT
+#ifndef NVM_VIRTUAL_PAGE_COUNT
#if FLASH_ERASE_CYCLES >= 20000
// use 16k of flash memory
-#define VNM_VIRTUAL_PAGE_COUNT 4
+#define NVM_VIRTUAL_PAGE_COUNT 4
#else
// use 32k of flash memory
-#define VNM_VIRTUAL_PAGE_COUNT 8
+#define NVM_VIRTUAL_PAGE_COUNT 8
#endif
#endif
/*
* How many virtual pages are skipped from top of flash
*/
-#ifndef VNM_VIRTUAL_PAGE_SKIP_FROM_TOP
-#define VNM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
+#ifndef NVM_VIRTUAL_PAGE_SKIP_FROM_TOP
+#define NVM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
#endif
/*
- * Calculate things around VNM_VIRTUAL_PAGE_SIZE
+ * Calculate things around NVM_VIRTUAL_PAGE_SIZE
*/
-#define VNM_VIRTUAL_PAGE_SIZE (1 << (VNM_VIRTUAL_PAGE_SIZE_BITS))
-#define VNM_VIRTUAL_PAGE_ADDRESS_MASK (~(VNM_VIRTUAL_PAGE_SIZE - 1))
-#define VNM_VIRTUAL_PAGE_ALIGN(address) \
- { address = (uint32_t *)((uint32_t)address & VNM_VIRTUAL_PAGE_ADDRESS_MASK); }
+#define NVM_VIRTUAL_PAGE_SIZE (1 << (NVM_VIRTUAL_PAGE_SIZE_BITS))
+#define NVM_VIRTUAL_PAGE_ADDRESS_MASK (~(NVM_VIRTUAL_PAGE_SIZE - 1))
+#define NVM_VIRTUAL_PAGE_ALIGN(address) \
+ { address = (uint32_t *)((uint32_t)address & NVM_VIRTUAL_PAGE_ADDRESS_MASK); }
/*
* Defines the position of status words in a page.
@@ -79,8 +87,8 @@ VirtualPageClass VirtualPage;
#define OFFSET_MAGIC 1
#define OFFSET_COUNTER 0
#define MASK_ERASE_COUNTER 0x00FFFFFF
-#define OFFSET_STATUS_RELEASE_PREPARE VNM_VIRTUAL_PAGE_SIZE - 8
-#define OFFSET_STATUS_RELEASE_END VNM_VIRTUAL_PAGE_SIZE - 4
+#define OFFSET_STATUS_RELEASE_PREPARE NVM_VIRTUAL_PAGE_SIZE - 8
+#define OFFSET_STATUS_RELEASE_END NVM_VIRTUAL_PAGE_SIZE - 4
#define METADATA_SIZE 16
#define OFFSET_DATA 4
#endif
@@ -88,45 +96,45 @@ VirtualPageClass VirtualPage;
#define BIT_STATUS_RELEASE_PREPARE (1 << 30)
#define BIT_STATUS_RELEASE_END (1 << 31)
-#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
+#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
#else
// use first 8 byte for magic and erase counter and last 8 byte for page release
#define OFFSET_MAGIC 1
#define OFFSET_ERASE_COUNTER 0
#define OFFSET_DATA 2
#define OFFSET_STATUS_RELEASE_PREPARE \
- ((VNM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
+ ((NVM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
#define OFFSET_STATUS_RELEASE_END \
- ((VNM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
+ ((NVM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
#define MASK_ERASE_COUNTER 0xFFFFFFFF
#define BIT_STATUS_RELEASE_PREPARE 1
#define BIT_STATUS_RELEASE_END 1
-#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - 16)
+#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - 16)
#endif
uint16_t VirtualPageClass::size() const
{
- return (VNM_VIRTUAL_PAGE_DATA_SIZE);
+ return (NVM_VIRTUAL_PAGE_DATA_SIZE);
}
uint16_t VirtualPageClass::length() const
{
- return (VNM_VIRTUAL_PAGE_DATA_SIZE / 4);
+ return (NVM_VIRTUAL_PAGE_DATA_SIZE / 4);
}
uint16_t VirtualPageClass::page_count() const
{
- return (VNM_VIRTUAL_PAGE_COUNT - 1);
+ return (NVM_VIRTUAL_PAGE_COUNT - 1);
}
uint32_t VirtualPageClass::wear_level()
{
uint32_t max_erase_cycles = 0;
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t erase_cycles = get_page_erase_cycles(get_page_address(i));
if (erase_cycles > max_erase_cycles) {
max_erase_cycles = erase_cycles;
@@ -140,7 +148,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
{
// Give back a page prepared for release and not closed
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -156,7 +164,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
}
// check if a unreleased page is available
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -177,7 +185,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic)
uint32_t max_erase_cycles = (uint32_t)~0;
// Avoid duplicate allocation of pages, look for the less used page
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
// Delete duplicated pages
@@ -225,7 +233,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic, uint32_t max_writes)
void VirtualPageClass::release_prepare(uint32_t *address)
{
// move pointer to beginning of the page
- VNM_VIRTUAL_PAGE_ALIGN(address);
+ NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -244,7 +252,7 @@ void VirtualPageClass::release_prepare(uint32_t *address)
void VirtualPageClass::release(uint32_t *address)
{
// move pointer to beginning of the page
- VNM_VIRTUAL_PAGE_ALIGN(address);
+ NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -263,7 +271,7 @@ void VirtualPageClass::release(uint32_t *address)
bool VirtualPageClass::release_started(uint32_t *address)
{
// move pointer to beginning of the page
- VNM_VIRTUAL_PAGE_ALIGN(address);
+ NVM_VIRTUAL_PAGE_ALIGN(address);
return (address[OFFSET_STATUS_RELEASE_PREPARE] &
BIT_STATUS_RELEASE_PREPARE) == 0;
@@ -272,7 +280,7 @@ bool VirtualPageClass::release_started(uint32_t *address)
void VirtualPageClass::fail(uint32_t *address)
{
// move pointer to beginning of the page
- VNM_VIRTUAL_PAGE_ALIGN(address);
+ NVM_VIRTUAL_PAGE_ALIGN(address);
build_page(address, 0x00000000);
return;
@@ -281,7 +289,7 @@ void VirtualPageClass::fail(uint32_t *address)
void VirtualPageClass::clean_up()
{
// No page found -> try to give back a page prepared for release
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if ((page[OFFSET_STATUS_RELEASE_END] & BIT_STATUS_RELEASE_END) == 0) {
build_page(get_page_address(i), ~0);
@@ -292,7 +300,7 @@ void VirtualPageClass::clean_up()
void VirtualPageClass::format()
{
- for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
+ for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *address = get_page_address(i);
build_page(address, (uint32_t)~0);
}
@@ -301,25 +309,25 @@ void VirtualPageClass::format()
uint32_t *VirtualPageClass::get_page_address(uint16_t page)
{
return (uint32_t *)(Flash.top_app_page_address() -
- ((page + VNM_VIRTUAL_PAGE_SKIP_FROM_TOP)
- << VNM_VIRTUAL_PAGE_SIZE_BITS));
+ ((page + NVM_VIRTUAL_PAGE_SKIP_FROM_TOP)
+ << NVM_VIRTUAL_PAGE_SIZE_BITS));
}
void VirtualPageClass::build_page(uint32_t *address, uint32_t magic)
{
// move pointer to beginning of the page
- VNM_VIRTUAL_PAGE_ALIGN(address);
+ NVM_VIRTUAL_PAGE_ALIGN(address);
// get erase counter
uint32_t erase_counter = get_page_erase_cycles(address);
// Check if a magic is set
if (address[OFFSET_MAGIC] != (uint32_t)~0) {
- Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
+ Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
} else {
// check if page is empty
- for (int i = OFFSET_DATA; i < (VNM_VIRTUAL_PAGE_SIZE / 4); i++) {
+ for (int i = OFFSET_DATA; i < (NVM_VIRTUAL_PAGE_SIZE / 4); i++) {
if (address[i] != (uint32_t)~0) {
- Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
+ Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
break;
}
}
diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp
index 025ad607c..58d8c3738 100644
--- a/drivers/RF24/RF24.cpp
+++ b/drivers/RF24/RF24.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
-* Copyright (C) 2013-2017 Sensnology AB
+* Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -36,9 +36,10 @@ LOCAL uint8_t RF24_NODE_ADDRESS = RF24_BROADCAST_ADDRESS;
LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL;
#endif
-#ifdef LINUX_SPI_BCM
-uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes)
-uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command)
+#if defined(LINUX_SPI_BCM)
+uint8_t RF24_spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes)
+uint8_t RF24_spi_txbuff[32+1]
+; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command)
#endif
LOCAL void RF24_csn(const bool level)
@@ -51,21 +52,22 @@ LOCAL void RF24_ce(const bool level)
hwDigitalWrite(MY_RF24_CE_PIN, level);
}
-LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len,
+LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t *buf, uint8_t len,
const bool readMode)
{
uint8_t status;
- uint8_t* current = buf;
+ uint8_t *current = buf;
#if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION)
RF24_SPI.beginTransaction(SPISettings(MY_RF24_SPI_SPEED, RF24_SPI_DATA_ORDER,
RF24_SPI_DATA_MODE));
#endif
+
RF24_csn(LOW);
// timing
delayMicroseconds(10);
#ifdef LINUX_SPI_BCM
- uint8_t * prx = spi_rxbuff;
- uint8_t * ptx = spi_txbuff;
+ uint8_t *prx = RF24_spi_rxbuff;
+ uint8_t *ptx = RF24_spi_txbuff;
uint8_t size = len + 1; // Add register value to transmit buffer
*ptx++ = cmd;
@@ -76,7 +78,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t
*ptx++ = *current++;
}
}
- RF24_SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size);
+ RF24_SPI.transfernb( (char *) RF24_spi_txbuff, (char *) RF24_spi_rxbuff, size);
if (readMode) {
if (size == 2) {
status = *++prx; // result is 2nd byte of receive buffer
@@ -103,6 +105,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t
}
}
#endif
+
RF24_csn(HIGH);
#if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION)
RF24_SPI.endTransaction();
@@ -198,7 +201,7 @@ LOCAL void RF24_setRFConfiguration(const uint8_t configuration)
RF24_writeByteRegister(RF24_REG_NRF_CONFIG, configuration);
}
-LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t addressWidth)
+LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t *address, const uint8_t addressWidth)
{
RF24_writeMultiByteRegister(pipe, address, addressWidth);
}
@@ -283,7 +286,7 @@ LOCAL void RF24_standBy(void)
}
-LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len,
+LOCAL bool RF24_sendMessage(const uint8_t recipient, const void *buf, const uint8_t len,
const bool noACK)
{
uint8_t RF24_status;
@@ -296,16 +299,17 @@ LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint
// AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending
RF24_spiMultiByteTransfer((recipient == RF24_BROADCAST_ADDRESS ||
noACK) ? RF24_CMD_WRITE_TX_PAYLOAD_NO_ACK :
- RF24_CMD_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false );
+ RF24_CMD_WRITE_TX_PAYLOAD, (uint8_t *)buf, len, false );
// go, TX starts after ~10us, CE high also enables PA+LNA on supported HW
RF24_ce(HIGH);
+ delayMicroseconds(10); // datasheet: Pulse CE at least 10us
+ RF24_ce(LOW);
// timeout counter to detect HW issues
uint16_t timeout = 0xFFFF;
do {
RF24_status = RF24_getStatus();
} while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--);
// timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles
- RF24_ce(LOW);
// reset interrupts
RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) );
// Max retries exceeded
@@ -337,11 +341,11 @@ LOCAL bool RF24_isDataAvailable(void)
}
-LOCAL uint8_t RF24_readMessage(void* buf)
+LOCAL uint8_t RF24_readMessage(void *buf)
{
const uint8_t len = RF24_getDynamicPayloadSize();
RF24_DEBUG(PSTR("RF24:RXM:LEN=%" PRIu8 "\n"), len); // read message
- RF24_spiMultiByteTransfer(RF24_CMD_READ_RX_PAYLOAD,(uint8_t*)buf,len,true);
+ RF24_spiMultiByteTransfer(RF24_CMD_READ_RX_PAYLOAD,(uint8_t *)buf,len,true);
// clear RX interrupt
RF24_setStatus(_BV(RF24_RX_DR));
return len;
@@ -407,11 +411,11 @@ LOCAL int16_t RF24_getSendingRSSI(void)
LOCAL void RF24_irqHandler(void)
{
if (RF24_receiveCallback) {
+#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
// Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial
// rx coming in during our stay will not be handled and will cause characters to be lost.
// As a workaround we re-enable interrupts to allow nested processing of other interrupts.
// Our own handler is disconnected to prevent recursive calling of this handler.
-#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
interrupts();
#endif
@@ -420,13 +424,28 @@ LOCAL void RF24_irqHandler(void)
// 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available.
// Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS.
+#if defined(__linux__)
+ // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt
+ // for a message we've already read.
+ if (RF24_isDataAvailable()) {
+ do {
+ RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
+ } while (RF24_isDataAvailable());
+ } else {
+ // Occasionally interrupt is triggered but no data is available - clear RX interrupt only
+ RF24_setStatus(_BV(RF24_RX_DR));
+ logNotice("RF24: Recovered from a bad interrupt trigger.\n");
+ }
+#else
// Start checking if RX-FIFO is not empty, as we might end up here from an interrupt
// for a message we've already read.
while (RF24_isDataAvailable()) {
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
}
- // Restore our interrupt handler.
+#endif
+
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
+ // Restore our interrupt handler.
noInterrupts();
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
#endif
@@ -500,11 +519,11 @@ LOCAL bool RF24_initialize(void)
RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0));
// listen to broadcast pipe
RF24_BASE_ID[0] = RF24_BROADCAST_ADDRESS;
- RF24_setPipeAddress(RF24_REG_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&RF24_BASE_ID,
+ RF24_setPipeAddress(RF24_REG_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t *)&RF24_BASE_ID,
RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH);
// pipe 0, set full address, later only LSB is updated
- RF24_setPipeAddress(RF24_REG_RX_ADDR_P0, (uint8_t*)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH);
- RF24_setPipeAddress(RF24_REG_TX_ADDR, (uint8_t*)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH);
+ RF24_setPipeAddress(RF24_REG_RX_ADDR_P0, (uint8_t *)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH);
+ RF24_setPipeAddress(RF24_REG_TX_ADDR, (uint8_t *)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH);
// reset FIFO
RF24_flushRX();
RF24_flushTX();
diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h
index d44e9f392..4b182b7b5 100644
--- a/drivers/RF24/RF24.h
+++ b/drivers/RF24/RF24.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
-* Copyright (C) 2013-2017 Sensnology AB
+* Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -34,26 +34,26 @@
* RF24 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
* - [!] Exclamation mark is prepended in case of error
*
-* |E| SYS | SUB | Message | Comment
-* |-|------|------|--------------------|---------------------------------------------------------------------
-* | | RF24 | INIT | | Initialise RF24 radio
-* | | RF24 | INIT | PIN,CE=%d,CS=%d | Pin configuration: chip enable (CE), chip select (CS)
-* |!| RF24 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
-* | | RF24 | SPP | PCT=%d,TX LEVEL=%d | Set TX level, input TX percent (PCT)
-* | | RF24 | RBR | REG=%d,VAL=%d | Read register (REG), value=(VAL)
-* | | RF24 | WBR | REG=%d,VAL=%d | Write register (REG), value=(VAL)
-* | | RF24 | FRX | | Flush RX buffer
-* | | RF24 | FTX | | Flush TX buffer
-* | | RF24 | OWP | RCPT=%d | Open writing pipe, recipient=(RCPT)
-* | | RF24 | STL | | Start listening
-* | | RF24 | SPL | | Stop listening
-* | | RF24 | SLP | | Set radio to sleep
-* | | RF24 | SBY | | Set radio to standby
-* | | RF24 | TXM | TO=%d,LEN=%d | Transmit message to=(TO), length=(LEN)
-* |!| RF24 | TXM | MAX_RT | Max TX retries, no ACK received
-* |!| RF24 | GDP | PYL INV | Invalid payload size
-* | | RF24 | RXM | LEN=%d | Read message, length=(LEN)
-* | | RF24 | STX | LEVEL=%d | Set TX level, level=(LEVEL)
+* |E| SYS | SUB | Message | Comment
+* |-|------|------|----------------------|---------------------------------------------------------------------
+* | | RF24 | INIT | | Initialise RF24 radio
+* | | RF24 | INIT | PIN,CE=%%d,CS=%%d | Pin configuration: chip enable (CE), chip select (CS)
+* |!| RF24 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
+* | | RF24 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level, input TX percent (PCT)
+* | | RF24 | RBR | REG=%%d,VAL=%%d | Read register (REG), value=(VAL)
+* | | RF24 | WBR | REG=%%d,VAL=%%d | Write register (REG), value=(VAL)
+* | | RF24 | FRX | | Flush RX buffer
+* | | RF24 | FTX | | Flush TX buffer
+* | | RF24 | OWP | RCPT=%%d | Open writing pipe, recipient=(RCPT)
+* | | RF24 | STL | | Start listening
+* | | RF24 | SPL | | Stop listening
+* | | RF24 | SLP | | Set radio to sleep
+* | | RF24 | SBY | | Set radio to standby
+* | | RF24 | TXM | TO=%%d,LEN=%%d | Transmit message to=(TO), length=(LEN)
+* |!| RF24 | TXM | MAX_RT | Max TX retries, no ACK received
+* |!| RF24 | GDP | PYL INV | Invalid payload size
+* | | RF24 | RXM | LEN=%%d | Read message, length=(LEN)
+* | | RF24 | STX | LEVEL=%%d | Set TX level, level=(LEVEL)
*
*/
@@ -67,7 +67,7 @@
#elif defined(ARDUINO_ARCH_ESP8266)
#define DEFAULT_RF24_CE_PIN (4) //!< DEFAULT_RF24_CE_PIN
#elif defined(ARDUINO_ARCH_ESP32)
-#warning not implemented yet
+#define DEFAULT_RF24_CE_PIN (17) //!< DEFAULT_RF24_CE_PIN
#elif defined(ARDUINO_ARCH_SAMD)
#define DEFAULT_RF24_CE_PIN (27) //!< DEFAULT_RF24_CE_PIN
#elif defined(LINUX_ARCH_RASPBERRYPI)
@@ -174,7 +174,7 @@ LOCAL void RF24_ce(const bool level);
* @param readMode
* @return
*/
-LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len,
+LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t *buf, const uint8_t len,
const bool readMode);
/**
* @brief RF24_spiByteTransfer
@@ -199,7 +199,7 @@ LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, const uint8_t value)
// helper macros
#define RF24_readByteRegister(__reg) RF24_RAW_readByteRegister(RF24_CMD_READ_REGISTER | (RF24_REGISTER_MASK & (__reg))) //!< RF24_readByteRegister
#define RF24_writeByteRegister(__reg,__value) RF24_RAW_writeByteRegister(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)), __value) //!< RF24_writeByteRegister
-#define RF24_writeMultiByteRegister(__reg,__buf,__len) RF24_spiMultiByteTransfer(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)),(uint8_t*)__buf, __len,false) //!< RF24_writeMultiByteRegister
+#define RF24_writeMultiByteRegister(__reg,__buf,__len) RF24_spiMultiByteTransfer(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)),(uint8_t *)__buf, __len,false) //!< RF24_writeMultiByteRegister
/**
* @brief RF24_flushRX
@@ -256,7 +256,7 @@ LOCAL void RF24_powerUp(void);
* @param noACK set True if no ACK is required
* @return
*/
-LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len,
+LOCAL bool RF24_sendMessage(const uint8_t recipient, const void *buf, const uint8_t len,
const bool noACK = false);
/**
* @brief RF24_getDynamicPayloadSize
@@ -272,7 +272,7 @@ LOCAL bool RF24_isDataAvailable(void);
* @brief RF24_readMessage
* @return
*/
-LOCAL uint8_t RF24_readMessage(void* buf);
+LOCAL uint8_t RF24_readMessage(void *buf);
/**
* @brief RF24_setNodeAddress
* @param address
@@ -345,7 +345,7 @@ LOCAL void RF24_setRFConfiguration(const uint8_t configuration);
* @param address
* @param addressWidth
*/
-LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t addressWidth);
+LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t *address, const uint8_t addressWidth);
/**
* @brief RF24_setPipeLSB
* @param pipe
diff --git a/drivers/RF24/RF24registers.h b/drivers/RF24/RF24registers.h
index 195056ef4..83b2298c6 100644
--- a/drivers/RF24/RF24registers.h
+++ b/drivers/RF24/RF24registers.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
-* Copyright (C) 2013-2017 Sensnology AB
+* Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
diff --git a/drivers/RFM69/new/RFM69_new.cpp b/drivers/RFM69/new/RFM69_new.cpp
index 7cfb8b87d..c1a065a1b 100644
--- a/drivers/RFM69/new/RFM69_new.cpp
+++ b/drivers/RFM69/new/RFM69_new.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -16,20 +16,20 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
- * RFM69 driver refactored for Mysensors
+ * RFM69 driver refactored for MySensors
*
* Based on :
* - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com
* - Automatic Transmit Power Control class derived from RFM69 library.
* Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html
* Copyright Thomas Studwell (2014,2015)
- * - Mysensors generic radio driver implementation Copyright (C) 2017 Olivier Mauti
+ * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti
*
* Changes by : @tekka, @scalz, @marceloagno
*
* Definitions for Semtech SX1231/H radios:
- * http://www.semtech.com/images/datasheet/sx1231.pdf
- * http://www.semtech.com/images/datasheet/sx1231h.pdf
+ * https://www.semtech.com/uploads/documents/sx1231.pdf
+ * https://www.semtech.com/uploads/documents/sx1231h.pdf
*/
#include "RFM69_new.h"
@@ -41,21 +41,13 @@
#define RFM69_DEBUG(x,...) //!< DEBUG null
#endif
-volatile rfm69_internal_t RFM69; //!< internal variables
+rfm69_internal_t RFM69; //!< internal variables
+volatile uint8_t RFM69_irq; //!< rfm69 irq flag
-#if defined (SREG) && !defined(SPI_HAS_TRANSACTION)
-uint8_t _SREG; // Used to save and restore the SREG values in SPI transactions
-#endif
-
-#if defined (SPCR) && defined (SPSR) && !defined(SPI_HAS_TRANSACTION)
-uint8_t _SPCR; //!< _SPCR
-uint8_t _SPSR; //!< _SPSR
-#endif
-
-#ifdef LINUX_SPI_BCM
+#if defined(LINUX_SPI_BCM)
// SPI RX and TX buffers (max packet len + 1 byte for the command)
-uint8_t spi_rxbuff[RFM69_MAX_PACKET_LEN + 1];
-uint8_t spi_txbuff[RFM69_MAX_PACKET_LEN + 1];
+uint8_t RFM69_spi_rxbuff[RFM69_MAX_PACKET_LEN + 1];
+uint8_t RFM69_spi_txbuff[RFM69_MAX_PACKET_LEN + 1];
#endif
LOCAL void RFM69_csn(const bool level)
@@ -68,24 +60,6 @@ LOCAL void RFM69_prepareSPITransaction(void)
#if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION)
RFM69_SPI.beginTransaction(SPISettings(MY_RFM69_SPI_SPEED, RFM69_SPI_DATA_ORDER,
RFM69_SPI_DATA_MODE));
-#else
-#if defined(SREG)
- _SREG = SREG;
-#endif
- noInterrupts();
-#if defined(SPCR) && defined(SPSR)
- // save current SPI settings
- _SPCR = SPCR;
- _SPSR = SPSR;
-#endif
-
- // set RFM69 SPI settings
-#if !defined(MY_SOFTSPI)
- RFM69_SPI.setDataMode(RFM69_SPI_DATA_MODE);
- RFM69_SPI.setBitOrder(RFM69_SPI_DATA_ORDER);
- RFM69_SPI.setClockDivider(RFM69_CLOCK_DIV);
-#endif
-
#endif
}
@@ -93,17 +67,6 @@ LOCAL void RFM69_concludeSPITransaction(void)
{
#if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION)
RFM69_SPI.endTransaction();
-#else
- // restore SPI settings to what they were before talking to RFM69
-#if defined(SPCR) && defined(SPSR)
- SPCR = _SPCR;
- SPSR = _SPSR;
-#endif
- // restore the prior interrupt state
-#if defined(SREG)
- SREG = _SREG;
-#endif
- interrupts();
#endif
}
@@ -111,14 +74,14 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
const bool aReadMode)
{
uint8_t status;
- uint8_t* current = buf;
+ uint8_t *current = buf;
RFM69_prepareSPITransaction();
RFM69_csn(LOW);
-#ifdef LINUX_SPI_BCM
- uint8_t * prx = spi_rxbuff;
- uint8_t * ptx = spi_txbuff;
+#if defined(LINUX_SPI_BCM)
+ uint8_t *prx = RFM69_spi_rxbuff;
+ uint8_t *ptx = RFM69_spi_txbuff;
uint8_t size = len + 1; // Add register value to transmit buffer
*ptx++ = cmd;
@@ -129,7 +92,7 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
*ptx++ = *current++;
}
}
- RFM69_SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size);
+ RFM69_SPI.transfernb((char *)RFM69_spi_txbuff, (char *)RFM69_spi_rxbuff, size);
if (aReadMode) {
if (size == 2) {
status = *++prx; // result is 2nd byte of receive buffer
@@ -156,33 +119,52 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
}
}
#endif
-
RFM69_csn(HIGH);
RFM69_concludeSPITransaction();
-
return status;
}
// low level register access
-LOCAL uint8_t RFM69_RAW_readByteRegister(const uint8_t address)
+LOCAL inline uint8_t RFM69_RAW_readByteRegister(const uint8_t address)
{
- const uint8_t value = RFM69_spiMultiByteTransfer(address, NULL, 1, true);
- //RFM69_DEBUG(PSTR("RFM69:read register, reg=0x%02" PRIx8 ", value=%" PRIu8 "\n"), address, value);
- return value;
+ return RFM69_spiMultiByteTransfer(address, NULL, 1, true);
}
-// low level register access
-LOCAL uint8_t RFM69_RAW_writeByteRegister(const uint8_t address, uint8_t value)
+LOCAL inline uint8_t RFM69_RAW_writeByteRegister(const uint8_t address, uint8_t value)
{
- //RFM69_DEBUG(PSTR("RFM69:write register, reg=0x%02" PRIx8 ", value=%" PRIu8 "\n"), address & 0x7F, value);
return RFM69_spiMultiByteTransfer(address, &value, 1, false);
}
-// macros, saves space
-#define RFM69_readReg(__reg) RFM69_RAW_readByteRegister(__reg & RFM69_READ_REGISTER)
-#define RFM69_writeReg(__reg, __value) RFM69_RAW_writeByteRegister((__reg | RFM69_WRITE_REGISTER), __value )
-#define RFM69_burstReadReg(__reg, __buf, __len) RFM69_spiMultiByteTransfer( __reg & RFM69_READ_REGISTER, (uint8_t*)__buf, __len, true )
-#define RFM69_burstWriteReg(__reg, __buf, __len) RFM69_spiMultiByteTransfer( __reg | RFM69_WRITE_REGISTER, (uint8_t*)__buf, __len, false )
+// helper functions
+LOCAL inline uint8_t RFM69_readReg(const uint8_t reg)
+{
+ return RFM69_RAW_readByteRegister(reg & RFM69_READ_REGISTER);
+}
+
+LOCAL inline uint8_t RFM69_writeReg(const uint8_t reg, const uint8_t value)
+{
+ return RFM69_RAW_writeByteRegister(reg | RFM69_WRITE_REGISTER, value);
+}
+
+LOCAL inline uint8_t RFM69_burstReadReg(const uint8_t reg, void *buf, uint8_t len)
+{
+ return RFM69_spiMultiByteTransfer(reg & RFM69_READ_REGISTER, (uint8_t *)buf, len, true);
+}
+
+LOCAL inline uint8_t RFM69_burstWriteReg(const uint8_t reg, const void *buf, uint8_t len)
+{
+ return RFM69_spiMultiByteTransfer(reg | RFM69_WRITE_REGISTER, (uint8_t *)buf, len, false);
+}
+
+LOCAL inline rfm69_RSSI_t RFM69_RSSItoInternal(const int16_t externalRSSI)
+{
+ return (rfm69_RSSI_t)-(externalRSSI * 2);
+}
+
+LOCAL inline int16_t RFM69_internalToRSSI(const rfm69_RSSI_t internalRSSI)
+{
+ return (int16_t)-(internalRSSI / 2);
+}
LOCAL bool RFM69_initialise(const uint32_t frequencyHz)
{
@@ -218,65 +200,58 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz)
RFM69.powerLevel = MY_RFM69_TX_POWER_DBM + 1; // will be overwritten when set
RFM69.radioMode = RFM69_RADIO_MODE_SLEEP;
RFM69.ATCenabled = false;
- RFM69.listenModeEnabled = false;
- RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(RFM69_TARGET_RSSI_DBM);
+ RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(MY_RFM69_ATC_TARGET_RSSI_DBM);
// SPI init
hwDigitalWrite(MY_RFM69_CS_PIN, HIGH);
hwPinMode(MY_RFM69_CS_PIN, OUTPUT);
RFM69_SPI.begin();
-
+ (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
+ // set configuration, encryption is disabled
RFM69_setConfiguration();
RFM69_setFrequency(frequencyHz);
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
-
- // Encryption is persistent between resets and can trip you up during debugging.
- // Disable it during initialization so we always start from a known state.
- RFM69_encrypt(0);
(void)RFM69_setTxPowerLevel(MY_RFM69_TX_POWER_DBM);
- // IRQ
- hwPinMode(MY_RFM69_IRQ_PIN, INPUT);
-#if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) && !defined (MY_SOFTSPI)
- RFM69_SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN));
-#endif
-#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS
+#if defined(MY_DEBUG_VERBOSE_RFM69_REGISTERS)
RFM69_readAllRegs();
+#else
+ (void)RFM69_readAllRegs;
#endif
+ //RFM69_DEBUG(PSTR("RFM69:INIT:HWV=%" PRIu8 "\n"),RFM69_readReg(RFM69_REG_VERSION));
if (!RFM69_sanityCheck()) {
- RFM69_DEBUG(
- PSTR("!RFM69:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module
+ // sanity check failed, check wiring or replace module
+ RFM69_DEBUG(PSTR("!RFM69:INIT:SANCHK FAIL\n"));
return false;
}
- attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING);
+ // IRQ
+ RFM69_irq = false;
+ hwPinMode(MY_RFM69_IRQ_PIN, INPUT);
+ attachInterrupt(MY_RFM69_IRQ_NUM, RFM69_interruptHandler, RISING);
return true;
}
+LOCAL void RFM69_clearFIFO(void)
+{
+ (void)RFM69_writeReg(RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN);
+}
// IRQ handler: PayloadReady (RX) & PacketSent (TX) mapped to DI0
LOCAL void RFM69_interruptHandler(void)
{
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
- if (RFM69.listenModeEnabled) {
- RFM69_listenModeReset();
- //noInterrupts();
- union { // union to simplify addressing of long and short parts of time offset
- uint32_t l;
- uint8_t b[4];
- } burstRemaining;
-
- burstRemaining.l = 0;
- }
-#endif
+ // set flag
+ RFM69_irq = true;
+}
+
+LOCAL void RFM69_interruptHandling(void)
+{
const uint8_t regIrqFlags2 = RFM69_readReg(RFM69_REG_IRQFLAGS2);
- if ( RFM69.radioMode == RFM69_RADIO_MODE_RX && (regIrqFlags2 & RFM69_IRQFLAGS2_PAYLOADREADY) ) {
- RFM69.currentPacket.RSSI = RFM69_readRSSI();
+ if (RFM69.radioMode == RFM69_RADIO_MODE_RX && (regIrqFlags2 & RFM69_IRQFLAGS2_PAYLOADREADY)) {
(void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
// use the fifo level irq as indicator if header bytes received
if (regIrqFlags2 & RFM69_IRQFLAGS2_FIFOLEVEL) {
RFM69_prepareSPITransaction();
RFM69_csn(LOW);
-#ifdef LINUX_SPI_BCM
+#if defined(LINUX_SPI_BCM)
char data[RFM69_MAX_PACKET_LEN + 1]; // max packet len + 1 byte for the command
data[0] = RFM69_REG_FIFO & RFM69_READ_REGISTER;
RFM69_SPI.transfern(data, 3);
@@ -292,8 +267,8 @@ LOCAL void RFM69_interruptHandler(void)
//SPI.transfern(data, RFM69.currentPacket.header.packetLen - 1); //TODO: Wrong packetLen?
RFM69_SPI.transfern(data, RFM69.currentPacket.header.packetLen);
- //(void)memcpy((void*)&RFM69.currentPacket.data[2], (void*)&data[1], RFM69.currentPacket.header.packetLen - 2); //TODO: Wrong packetLen?
- (void)memcpy((void*)&RFM69.currentPacket.data[2], (void*)&data[1],
+ //(void)memcpy((void *)&RFM69.currentPacket.data[2], (void *)&data[1], RFM69.currentPacket.header.packetLen - 2); //TODO: Wrong packetLen?
+ (void)memcpy((void *)&RFM69.currentPacket.data[2], (void *)&data[1],
RFM69.currentPacket.header.packetLen - 1);
if (RFM69.currentPacket.header.version >= RFM69_MIN_PACKET_HEADER_VERSION) {
@@ -303,23 +278,22 @@ LOCAL void RFM69_interruptHandler(void)
RFM69.dataReceived = !RFM69.ackReceived;
}
#else
- RFM69_SPI.transfer(RFM69_REG_FIFO & RFM69_READ_REGISTER);
+ (void)RFM69_SPI.transfer(RFM69_REG_FIFO & RFM69_READ_REGISTER);
// set reading pointer
- uint8_t* current = (uint8_t*)&RFM69.currentPacket;
+ uint8_t *current = (uint8_t *)&RFM69.currentPacket;
bool headerRead = false;
// first read header
uint8_t readingLength = RFM69_HEADER_LEN;
while (readingLength--) {
- *current++ = RFM69_SPI.transfer((uint8_t)0x00);
+ *current++ = RFM69_SPI.transfer((uint8_t)RFM69_NOP);
if (!readingLength && !headerRead) {
// header read
headerRead = true;
if (RFM69.currentPacket.header.version >= RFM69_MIN_PACKET_HEADER_VERSION) {
// read payload
- readingLength = RFM69.currentPacket.header.packetLen - (RFM69_HEADER_LEN - 1);
- if (readingLength > RFM69_MAX_PACKET_LEN) {
- readingLength = RFM69_MAX_PACKET_LEN;
- }
+ readingLength = min(RFM69.currentPacket.header.packetLen - (RFM69_HEADER_LEN - 1),
+ RFM69_MAX_PACKET_LEN);
+ // save payload length
RFM69.currentPacket.payloadLen = readingLength;
RFM69.ackReceived = RFM69_getACKReceived(RFM69.currentPacket.header.controlFlags);
RFM69.dataReceived = !RFM69.ackReceived;
@@ -330,94 +304,106 @@ LOCAL void RFM69_interruptHandler(void)
RFM69_csn(HIGH);
RFM69_concludeSPITransaction();
}
- // radio remains in stdby until paket read
- } else if (RFM69.radioMode == RFM69_RADIO_MODE_TX && (regIrqFlags2 & RFM69_IRQFLAGS2_PACKETSENT) ) {
- RFM69.dataSent = true;
+ RFM69.currentPacket.RSSI = RFM69_readRSSI();
+ // radio remains in stdby until packet read
+ } else {
// back to RX
(void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX);
}
}
+LOCAL void RFM69_handler(void)
+{
+ if (RFM69_irq) {
+ // radio is in STDBY
+ // clear flag, 8bit - no need for critical section
+ RFM69_irq = false;
+ RFM69_interruptHandling();
+ }
+}
+
LOCAL bool RFM69_available(void)
{
if (RFM69.dataReceived) {
- // data received - we are still in STDBY from IRQ handler
- //(void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
+ // data received - we are still in STDBY
return true;
} else if (RFM69.radioMode == RFM69_RADIO_MODE_TX) {
+ // still in TX
return false;
- } else if (RFM69.radioMode != RFM69_RADIO_MODE_RX) {
- // we are not in RX, and no data received
- RFM69_setRadioMode(RFM69_RADIO_MODE_RX);
+ } else if (RFM69.radioMode != RFM69_RADIO_MODE_RX) { // adding this check speeds up loop() :)
+ // no data received and not in RX
+ (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX);
}
return false;
}
-
-
-LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize)
+LOCAL uint8_t RFM69_receive(uint8_t *buf, const uint8_t maxBufSize)
{
- // atomic
- noInterrupts();
-
- const uint8_t payloadLen = RFM69.currentPacket.payloadLen < maxBufSize?
- RFM69.currentPacket.payloadLen : maxBufSize;
+ const uint8_t payloadLen = min(RFM69.currentPacket.payloadLen, maxBufSize);
const uint8_t sender = RFM69.currentPacket.header.sender;
const rfm69_sequenceNumber_t sequenceNumber = RFM69.currentPacket.header.sequenceNumber;
const uint8_t controlFlags = RFM69.currentPacket.header.controlFlags;
- const rfm69_RSSI_t RSSI = RFM69.currentPacket.RSSI; // of incoming packet
+ const rfm69_RSSI_t RSSI = RFM69.currentPacket.RSSI;
if (buf != NULL) {
- (void)memcpy((void*)buf, (void*)RFM69.currentPacket.payload, payloadLen);
- // packet read
- RFM69.dataReceived = false;
+ (void)memcpy((void *)buf, (void *)&RFM69.currentPacket.payload, payloadLen);
}
-
- interrupts(); // explicitly re-enable interrupts
-
+ // clear data flag
+ RFM69.dataReceived = false;
if (RFM69_getACKRequested(controlFlags) && !RFM69_getACKReceived(controlFlags)) {
- RFM69_sendACK(sender, sequenceNumber,RSSI);
+#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16*1000000ul)
+ // delay for fast GW and slow nodes
+ delay(50);
+#endif
+ RFM69_sendACK(sender, sequenceNumber, RSSI);
}
-
return payloadLen;
}
-LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCounter)
+LOCAL bool RFM69_channelFree(void)
{
- /*
- if(!RFM69_waitCAD()) {
- // channel not free
- return false;
- }
- */
-
+ // returns true if channel activity under RFM69_CSMA_LIMIT_DBM
+ const rfm69_RSSI_t RSSI = RFM69_readRSSI(false);
+ RFM69_DEBUG(PSTR("RFM69:CSMA:RSSI=%" PRIi16 "\n"), RFM69_internalToRSSI(RSSI));
+ return (RSSI > RFM69_RSSItoInternal(MY_RFM69_CSMA_LIMIT_DBM));
+}
+LOCAL bool RFM69_sendFrame(rfm69_packet_t *packet, const bool increaseSequenceCounter)
+{
+ // ensure we are in RX for correct RSSI sampling, dirty hack to enforce rx restart :)
+ RFM69.radioMode = RFM69_RADIO_MODE_STDBY;
+ (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX);
+ delay(1); // timing for correct RSSI sampling
+ const uint32_t CSMA_START_MS = hwMillis();
+ while (!RFM69_channelFree() &&
+ ((hwMillis() - CSMA_START_MS) < MY_RFM69_CSMA_TIMEOUT_MS)) {
+ doYield();
+ }
// set radio to standby to load fifo
(void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
if (increaseSequenceCounter) {
// increase sequence counter, overflow is ok
RFM69.txSequenceNumber++;
}
- packet.header.sequenceNumber = RFM69.txSequenceNumber;
-
- RFM69_writeReg(RFM69_REG_PACKETCONFIG2,
- (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFB) | RFM69_PACKET2_RXRESTART); // avoid RX deadlocks
+ // clear FIFO and flags
+ RFM69_clearFIFO();
+ // assign sequence number
+ packet->header.sequenceNumber = RFM69.txSequenceNumber;
// write packet
- const uint8_t finalLen = packet.payloadLen + RFM69_HEADER_LEN; // including length byte
- RFM69_burstWriteReg(RFM69_REG_FIFO, packet.data, finalLen);
+ const uint8_t finalLen = packet->payloadLen + RFM69_HEADER_LEN; // including length byte
+ (void)RFM69_burstWriteReg(RFM69_REG_FIFO, packet->data, finalLen);
// send message
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX);
- const uint32_t txStart = hwMillis();
- // irq handler set radiomode to rx once packet sent
- while (!RFM69.dataSent && hwMillis() - txStart < RFM69_TX_LIMIT_MS) { // wait until packet sent
+ (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); // irq upon txsent
+ const uint32_t txStartMS = hwMillis();
+ while (!RFM69_irq && (hwMillis() - txStartMS < MY_RFM69_TX_TIMEOUT_MS)) {
doYield();
- }
- return RFM69.dataSent;
+ };
+ return RFM69_irq;
}
-LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
+LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len,
const rfm69_controlFlags_t flags, const bool increaseSequenceCounter)
{
// assemble packet
@@ -425,20 +411,20 @@ LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
packet.header.version = RFM69_PACKET_HEADER_VERSION;
packet.header.sender = RFM69.address;
packet.header.recipient = recipient;
- packet.header.controlFlags = 0x00; // reset
+ packet.header.controlFlags = 0u; // reset
packet.payloadLen = min(len, (uint8_t)RFM69_MAX_PAYLOAD_LEN);
packet.header.controlFlags = flags;
- (void)memcpy(&packet.payload, data, packet.payloadLen); // copy payload
+ (void)memcpy((void *)&packet.payload, (void *)data, packet.payloadLen); // copy payload
packet.header.packetLen = packet.payloadLen + (RFM69_HEADER_LEN - 1); // -1 length byte
- return RFM69_sendFrame(packet, increaseSequenceCounter);
+ return RFM69_sendFrame(&packet, increaseSequenceCounter);
}
LOCAL void RFM69_setFrequency(const uint32_t frequencyHz)
{
const uint32_t freqHz = (uint32_t)(frequencyHz / RFM69_FSTEP);
- RFM69_writeReg(RFM69_REG_FRFMSB, freqHz >> 16);
- RFM69_writeReg(RFM69_REG_FRFMID, freqHz >> 8);
- RFM69_writeReg(RFM69_REG_FRFLSB, freqHz);
+ RFM69_writeReg(RFM69_REG_FRFMSB, (uint8_t)((freqHz >> 16) & 0xFF));
+ RFM69_writeReg(RFM69_REG_FRFMID, (uint8_t)((freqHz >> 8) & 0xFF));
+ RFM69_writeReg(RFM69_REG_FRFLSB, (uint8_t)(freqHz & 0xFF));
}
LOCAL void RFM69_setHighPowerRegs(const bool onOff)
@@ -521,62 +507,12 @@ LOCAL bool RFM69_setRadioMode(const rfm69_radio_mode_t newRadioMode)
RFM69_writeReg(RFM69_REG_PACKETCONFIG2,
(RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFB) | RFM69_PACKET2_RXRESTART); // avoid RX deadlocks
} else if (newRadioMode == RFM69_RADIO_MODE_TX) {
- RFM69.dataSent = false;
regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_TRANSMITTER;
RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_00); // Interrupt on PacketSent, DIO0
RFM69_setHighPowerRegs(RFM69.powerLevel >= (rfm69_powerlevel_t)RFM69_HIGH_POWER_DBM);
} else if (newRadioMode == RFM69_RADIO_MODE_SYNTH) {
regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_SYNTHESIZER;
- }
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
- else if (newRadioMode == RFM69_RADIO_MODE_LISTEN) {
- // Start LISTENMODE
- regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON;
-
- RFM69.listenModeEnabled = true;
-
- RFM69_DEBUG(PSTR("RFM69:LSM:Start..\n"));
- while (RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_PACKETSENT ==
- 0x00); // wait for ModeReady
-
- RFM69_listenModeReset();
- detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN));
- attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING);
-
- RFM69_writeReg(RFM69_REG_OPMODE,
- RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY); //standby mode
-
- //TODO _isHighSpeed = true;
- //TODO _haveEncryptKey = false;
- uint32_t rxDuration = RFM69_LISTEN_RX_US;
- uint32_t idleDuration = RFM69_LISTEN_IDLE_US;
- RFM69_listenModeSetDurations(rxDuration, idleDuration);
-
- RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01);
- RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1);
- RFM69_writeReg(RFM69_REG_FRFLSB,
- RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change!
- RFM69_listenModeApplyHighSpeedSettings();
- RFM69_writeReg(RFM69_REG_PACKETCONFIG1,
- RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON |
- RFM69_PACKET1_CRCAUTOCLEAR_ON);
- RFM69_writeReg(RFM69_REG_PACKETCONFIG2,
- RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF);
- RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A);
- RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A);
- RFM69_setListenConfig(idleListenResolution, rxListenResolution, RFM69_LISTEN1_CRITERIA_RSSI,
- RFM69_LISTEN1_END_10);
- RFM69_setListenCoefIdle(idleListenCoef);
- RFM69_setListenCoefRx(rxListenCoef);
- RFM69_writeReg(RFM69_REG_RSSITHRESH, 180);
- RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 75);
- RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY);
- RFM69_writeReg(RFM69_REG_OPMODE,
- RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON | RFM69_OPMODE_STANDBY);
- //WIP
- }
-#endif
- else {
+ } else {
regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY;
}
@@ -597,6 +533,7 @@ LOCAL bool RFM69_setRadioMode(const rfm69_radio_mode_t newRadioMode)
LOCAL void RFM69_powerUp(void)
{
#if defined(MY_RFM69_POWER_PIN)
+ RFM69_DEBUG(PSTR("RFM69:PWU\n")); // power up radio
hwDigitalWrite(MY_RFM69_POWER_PIN, HIGH);
delay(RFM69_POWERUP_DELAY_MS);
#endif
@@ -604,6 +541,7 @@ LOCAL void RFM69_powerUp(void)
LOCAL void RFM69_powerDown(void)
{
#if defined(MY_RFM69_POWER_PIN)
+ RFM69_DEBUG(PSTR("RFM69:PWD\n")); // power down radio
hwDigitalWrite(MY_RFM69_POWER_PIN, LOW);
#endif
}
@@ -630,33 +568,31 @@ LOCAL void RFM69_sendACK(const uint8_t recipient, const rfm69_sequenceNumber_t s
rfm69_ack_t ACK;
ACK.sequenceNumber = sequenceNumber;
ACK.RSSI = RSSI;
- rfm69_controlFlags_t flags = 0x00; // reset flags
+ rfm69_controlFlags_t flags = 0u; // reset flags
RFM69_setACKReceived(flags, true);
RFM69_setACKRSSIReport(flags, true);
- (void)RFM69_send(recipient, (uint8_t*)&ACK, sizeof(rfm69_ack_t), flags);
+ (void)RFM69_send(recipient, (uint8_t *)&ACK, sizeof(rfm69_ack_t), flags);
}
LOCAL bool RFM69_executeATC(const rfm69_RSSI_t currentRSSI, const rfm69_RSSI_t targetRSSI)
{
+ // RSSI range -80..-70 = internal representation 160(l)..140(u)
rfm69_powerlevel_t newPowerLevel = RFM69.powerLevel;
- if (RFM69_internalToRSSI(currentRSSI) < RFM69_internalToRSSI(targetRSSI *
- (1 + RFM69_ATC_TARGET_RANGE_PERCENT/100)) &&
- newPowerLevel < RFM69_MAX_POWER_LEVEL_DBM) {
+ const rfm69_RSSI_t uRange = targetRSSI - RFM69_RSSItoInternal(RFM69_ATC_TARGET_RANGE_DBM);
+ const rfm69_RSSI_t lRange = targetRSSI + RFM69_RSSItoInternal(RFM69_ATC_TARGET_RANGE_DBM);
+ if (currentRSSI > lRange && newPowerLevel < RFM69_MAX_POWER_LEVEL_DBM) {
// increase transmitter power
newPowerLevel++;
- } else if (RFM69_internalToRSSI(currentRSSI) > RFM69_internalToRSSI(targetRSSI *
- (1 - RFM69_ATC_TARGET_RANGE_PERCENT/100)) &&
- newPowerLevel > RFM69_MIN_POWER_LEVEL_DBM) {
+ } else if (currentRSSI < uRange && newPowerLevel > RFM69_MIN_POWER_LEVEL_DBM) {
// decrease transmitter power
newPowerLevel--;
} else {
// nothing to adjust
return false;
}
- RFM69_DEBUG(PSTR("RFM69:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 ",TXL=%" PRIi16 "\n"),
- RFM69_internalToRSSI(currentRSSI),
- RFM69_internalToRSSI(targetRSSI), newPowerLevel);
-
+ RFM69_DEBUG(PSTR("RFM69:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 "..%" PRIi16 ",TXL=%" PRIi8 "\n"),
+ RFM69_internalToRSSI(currentRSSI), RFM69_internalToRSSI(lRange), RFM69_internalToRSSI(uRange),
+ RFM69.powerLevel);
return RFM69_setTxPowerLevel(newPowerLevel);
}
@@ -667,22 +603,24 @@ LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI)
}
-LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer,
+LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void *buffer,
const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTimeMS)
{
for (uint8_t retry = 0; retry <= retries; retry++) {
- RFM69_DEBUG(PSTR("RFM69:SWR:SEND,TO=%" PRIu8 ",RETRY=%" PRIu8 "\n"), recipient, retry);
- rfm69_controlFlags_t flags = 0x00; // reset all flags
+ RFM69_DEBUG(PSTR("RFM69:SWR:SEND,TO=%" PRIu8 ",SEQ=%" PRIu16 ",RETRY=%" PRIu8 "\n"), recipient,
+ RFM69.txSequenceNumber,retry);
+ rfm69_controlFlags_t flags = 0u; // reset all flags
RFM69_setACKRequested(flags, (recipient != RFM69_BROADCAST_ADDRESS));
RFM69_setACKRSSIReport(flags, RFM69.ATCenabled);
- (void)RFM69_send(recipient, (uint8_t*)buffer, bufferSize, flags, !retry);
+ (void)RFM69_send(recipient, (uint8_t *)buffer, bufferSize, flags, !retry);
if (recipient == RFM69_BROADCAST_ADDRESS) {
// no ACK requested
return true;
}
// radio is in RX
const uint32_t enterMS = hwMillis();
- while (hwMillis() - enterMS < retryWaitTimeMS) {
+ while (hwMillis() - enterMS < retryWaitTimeMS && !RFM69.dataReceived) {
+ RFM69_handler();
if (RFM69.ackReceived) {
// radio is in stdby
const uint8_t sender = RFM69.currentPacket.header.sender;
@@ -700,24 +638,12 @@ LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer,
// ATC
if (RFM69.ATCenabled && RFM69_getACKRSSIReport(flags)) {
(void)RFM69_executeATC(RSSI,RFM69.ATCtargetRSSI);
- } // ATC
- // return to RX
+ }
return true;
} // seq check
}
- doYield();
}
RFM69_DEBUG(PSTR("!RFM69:SWR:NACK\n"));
- if (RFM69.ATCenabled) {
- // No ACK received, maybe out of reach: increase power level
- RFM69_setTxPowerLevel(RFM69.powerLevel + 1);
- }
- // random 100ms
- const uint32_t enterCSMAMS = hwMillis();
- const uint16_t randDelayCSMA = enterMS & 40; // 61 bytes + ACK take ~40ms
- while (hwMillis() - enterCSMAMS < randDelayCSMA) {
- doYield();
- }
}
return false;
}
@@ -770,447 +696,81 @@ LOCAL uint8_t RFM69_getTxPowerPercent(void)
LOCAL bool RFM69_sanityCheck(void)
{
bool result = true; // default
- result &= RFM69_readReg(RFM69_REG_DATAMODUL) == (RFM69_DATAMODUL_DATAMODE_PACKET |
- RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00);
- // check Bitrate
- result &= RFM69_readReg(RFM69_REG_BITRATEMSB) == MY_RFM69_BITRATE_MSB;
- result &= RFM69_readReg(RFM69_REG_BITRATELSB) == MY_RFM69_BITRATE_LSB;
- // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz)
- result &= RFM69_readReg(RFM69_REG_FDEVMSB) == RFM69_FDEVMSB_50000;
- result &= RFM69_readReg(RFM69_REG_FDEVLSB) == RFM69_FDEVLSB_50000;
- // check network
+ result &= RFM69_readReg(RFM69_REG_RSSITHRESH) == RFM69_RSSITHRESH_VALUE;
+ result &= RFM69_readReg(RFM69_REG_SYNCVALUE1) == RFM69_SYNCVALUE1;
result &= RFM69_readReg(RFM69_REG_SYNCVALUE2) == MY_RFM69_NETWORKID;
return result;
}
LOCAL void RFM69_setConfiguration(void)
{
+ const uint8_t rfm69_modem_config[] = { MY_RFM69_MODEM_CONFIGURATION };
const uint8_t CONFIG[][2] = {
{ RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY },
- { RFM69_REG_DATAMODUL, RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00 },
- { RFM69_REG_BITRATEMSB, MY_RFM69_BITRATE_MSB },
- { RFM69_REG_BITRATELSB, MY_RFM69_BITRATE_LSB },
- { RFM69_REG_FDEVMSB, RFM69_FDEVMSB_50000 },
- { RFM69_REG_FDEVLSB, RFM69_FDEVLSB_50000 },
- //{ RFM69_REG_FRFMSB, RFM69_FREQ_MSB },
- //{ RFM69_REG_FRFMID, RFM69_FREQ_MID },
- //{ RFM69_REG_FRFLSB, RFM69_FREQ_LSB },
+ { RFM69_REG_DATAMODUL, rfm69_modem_config[0] },
+ { RFM69_REG_BITRATEMSB, rfm69_modem_config[1] },
+ { RFM69_REG_BITRATELSB, rfm69_modem_config[2] },
+ { RFM69_REG_FDEVMSB, rfm69_modem_config[3] },
+ { RFM69_REG_FDEVLSB, rfm69_modem_config[4] },
{ RFM69_REG_LNA, RFM69_LNA_ZIN_200 | RFM69_LNA_CURRENTGAIN },
- { RFM69_REG_RXBW, RFM69_RXBW_DCCFREQ_010 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2 },
+ { RFM69_REG_RXBW, rfm69_modem_config[5] },
+ { RFM69_REG_AFCBW, rfm69_modem_config[5] }, // same as rxbw, experimental, based on datasheet
//{ RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01 },
{ RFM69_REG_DIOMAPPING2, RFM69_DIOMAPPING2_CLKOUT_OFF },
- { RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN },
- { RFM69_REG_RSSITHRESH, 220 /*RFM69_RSSITHRESH_VALUE*/ },
- { RFM69_REG_PREAMBLEMSB, 0 }, // default
- { RFM69_REG_PREAMBLELSB, 3 }, // default
+ { RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN }, // clear FIFO and flags
+ { RFM69_REG_RSSITHRESH, RFM69_RSSITHRESH_VALUE },
+ { RFM69_REG_PREAMBLEMSB, RFM69_PREAMBLESIZE_MSB_VALUE },
+ { RFM69_REG_PREAMBLELSB, RFM69_PREAMBLESIZE_LSB_VALUE },
{ RFM69_REG_SYNCCONFIG, RFM69_SYNC_ON | RFM69_SYNC_FIFOFILL_AUTO | RFM69_SYNC_SIZE_2 | RFM69_SYNC_TOL_0 },
{ RFM69_REG_SYNCVALUE1, RFM69_SYNCVALUE1 },
{ RFM69_REG_SYNCVALUE2, MY_RFM69_NETWORKID },
- // changed from dcfree_none to dcfree_whitening
- { RFM69_REG_PACKETCONFIG1, RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST },
- { RFM69_REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX
+ { RFM69_REG_PACKETCONFIG1, rfm69_modem_config[6] },
+ { RFM69_REG_PAYLOADLENGTH, RFM69_MAX_PACKET_LEN }, // in variable length mode: the max frame size, not used in TX
{ RFM69_REG_NODEADRS, RFM69_BROADCAST_ADDRESS }, // init
{ RFM69_REG_BROADCASTADRS, RFM69_BROADCAST_ADDRESS },
{ RFM69_REG_FIFOTHRESH, RFM69_FIFOTHRESH_TXSTART_FIFOTHRESH | (RFM69_HEADER_LEN - 1) }, // start transmitting when rfm69 header loaded, fifo level irq when header bytes received (irq asserted when n bytes exceeded)
{ RFM69_REG_PACKETCONFIG2, RFM69_PACKET2_RXRESTARTDELAY_2BITS | RFM69_PACKET2_AUTORXRESTART_OFF | RFM69_PACKET2_AES_OFF },
- { RFM69_REG_TESTDAGC, RFM69_DAGC_IMPROVED_LOWBETA0 },
+ { RFM69_REG_TESTDAGC, RFM69_DAGC_IMPROVED_LOWBETA0 }, // continuous DAGC mode, use 0x30 if afc offset == 0
{ 255, 0}
};
-
for (uint8_t i = 0; CONFIG[i][0] != 255; i++) {
RFM69_writeReg(CONFIG[i][0], CONFIG[i][1]);
}
-
}
LOCAL bool RFM69_isModeReady(void)
{
- const uint32_t enterMS = hwMillis();
- while (hwMillis() - enterMS < RFM69_MODE_READY_TIMEOUT_MS) {
- if (RFM69_readReg(RFM69_REG_IRQFLAGS1) & RFM69_IRQFLAGS1_MODEREADY) {
- return true;
- }
- }
- return false;
+ uint16_t timeout = 0xFFFF;
+ while (!(RFM69_readReg(RFM69_REG_IRQFLAGS1) & RFM69_IRQFLAGS1_MODEREADY) && timeout--) {
+ };
+ return timeout;
}
-LOCAL void RFM69_encrypt(const char* key)
+LOCAL void RFM69_encrypt(const char *key)
{
(void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
if (key != NULL) {
RFM69_burstWriteReg(RFM69_REG_AESKEY1, key, 16);
}
RFM69_writeReg(RFM69_REG_PACKETCONFIG2,
- (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0));
+ (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFE) | (key ? RFM69_PACKET2_AES_ON :
+ RFM69_PACKET2_AES_OFF));
}
-LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger)
+LOCAL rfm69_RSSI_t RFM69_readRSSI(const bool forceTrigger)
{
- // RSSI trigger not needed if DAGC is in continuous mode (we are)
- if (forceTrigger) {
+ // RssiStart command and RssiDone flags are not usable when DAGC is turned on
+ /*if (forceTrigger) {
RFM69_writeReg(RFM69_REG_RSSICONFIG, RFM69_RSSI_START);
uint16_t timeout = 0xFFFF;
while (!(RFM69_readReg(RFM69_REG_RSSICONFIG) & RFM69_RSSI_DONE) && timeout--) {
};
}
- return RFM69_readReg(RFM69_REG_RSSIVALUE);
-}
-
-/* UNUSED
-
-LOCAL uint8_t RFM69_getVersion(void)
-{
- return RFM69_readReg(RFM69_REG_VERSION);
-}
-
-LOCAL uint8_t RFM69_readTemperature(const uint8_t calFactor)
-{
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
- RFM69_writeReg(RFM69_REG_TEMP1, RFM69_TEMP1_MEAS_START);
- const uint32_t enterMS = hwMillis();
- while ((RFM69_readReg(RFM69_REG_TEMP1) & RFM69_TEMP1_MEAS_RUNNING) && hwMillis() - enterMS < 500);
- return ~RFM69_readReg(RFM69_REG_TEMP2) + RFM69_COURSE_TEMP_COEF +
- calFactor; // 'complement' corrects the slope, rising temp = rising val
-}
-
-LOCAL void RFM69_rcCalibration(void)
-{
- RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START);
- const uint32_t enterMS = hwMillis();
- while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE) && hwMillis() - enterMS < 500) {
- };
-}
-
-LOCAL uint8_t RFM69_setLNA(const uint8_t newReg)
-{
- const uint8_t oldReg = RFM69_readReg(RFM69_REG_LNA);
- RFM69_writeReg(RFM69_REG_LNA, ((newReg & 7) | (oldReg &
- ~7))); // just control the LNA Gain bits for now
- return oldReg; // return the original value in case we need to restore it
-}
-
-LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI)
-{
- RFM69.ATCenabled = onOff;
- RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(targetRSSI);
-}
-
-LOCAL bool RFM69_waitCAD(void)
-{
- const uint32_t enterMS = hwMillis();
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX);
- while (RFM69.radioMode == RFM69_RADIO_MODE_RX && !RFM69.dataReceived &&
- RFM69_RSSItoInternal(RFM69_readRSSI()) > RFM69_RSSItoInternal(RFM69_CSMA_LIMIT_DBM)) {
- if (hwMillis() - enterMS > RFM69_CSMA_TIMEOUT_MS) {
- return false;
- }
- }
- return true;
-}
-
-*/
-
-
-// ************************ LISTENMODE SECTION ************************
-
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
-LOCAL void RFM69_setListenConfig(const uint8_t listenResolIdle, const uint8_t listenResolRx,
- const uint8_t listenCriteria, const uint8_t listenEnd)
-{
- /*
- ListenResolIdle one of:
- RFM69_LISTEN_RESOL_IDLE_64US
- RFM69_LISTEN_RESOL_IDLE_4_1MS
- RFM69_LISTEN_RESOL_IDLE_262MS
- Sets the listen mode idle time to 64 usec, 4.1ms or 262 ms
- ListenResolRx one of:
- RFM69_LISTEN_RESOL_RX_64US
- RFM69_LISTEN_RESOL_RX_4_1MS
- RFM69_LISTEN_RESOL_RX_262MS
- Sets the listen mode Rx time to 64 usec, 4.1ms or 262 ms
- ListenCriteria
- Criteria for packet acceptance in listen mode, either:
- RFM69_LISTEN_CRITERIA_RSSI
- signal strength above RssiThreshold
- RFM69_LISTEN_CRITERIA_RSSI_SYNC
- Signal strength above RssiThresshold and SyncAddress matched.
- ListenEnd:
- Action taken after acceptance of a packet in Listen mode:
- RFM69_LISTEN_END_STAY_RX_LISTEN_STOP
- Chip stays in Rx mode, listen mode stops and must be disabled.
- RFM69_LISTEN_END_RX_UNTIL_LISTEN_STOP
- Chip stays in Rx mode until PayloadReady or Timeout interrupt
- occurs. Listen mode stops and must be disabled.
- RFM69_LISTEN_END_RX_UNTIL_LISTEN_RESUME
- Chip stays in Rx mode until PayloadReady or Timeout interrupt
- occurs. Listen mode then resumes in Idle State.
- FIFO lost at next RX wakeup.
- Default: (RFM69_LISTEN_RESOL_IDLE_4_1MS, RFM69_LISTEN_RESOL_RX_64US,
- RFM69_LISTEN_CRITERIA_RSSI, RFM69_LISTEN_END_RX_UNTIL_LISTEN_STOP)
- */
-
- RFM69_writeReg(RFM69_REG_LISTEN1, listenResolIdle | listenResolRx | listenCriteria | listenEnd);
-}
-
-LOCAL void RFM69_setListenCoefIdle(const uint8_t coeffIdle)
-{
- /*
- Duration of the Idle phase in Listen mode.
- t ListenIdle = ListenCoefIdle * ListenResolIdle
- Default 0xf5; 245
- */
-
- RFM69_writeReg(RFM69_REG_LISTEN2, coeffIdle);
-}
-
-LOCAL void RFM69_setListenCoefRx(const uint8_t coeffRX)
-{
- /*
- Duration of the Rx phase in Listen mode.
- t ListenRx = ListenCoefRx * ListenResolRx
- Default 0x20; 32
- */
-
- RFM69_writeReg(RFM69_REG_LISTEN3, coeffRX);
-}
-
-LOCAL void RFM69_listenModeApplyHighSpeedSettings(void)
-{
- if (!_isHighSpeed) {
- return;
- }
- RFM69_writeReg(RFM69_REG_BITRATEMSB, RFM69_BITRATEMSB_200000);
- RFM69_writeReg(RFM69_REG_BITRATELSB, RFM69_BITRATELSB_200000);
- RFM69_writeReg(RFM69_REG_FDEVMSB, RFM69_FDEVMSB_100000);
- RFM69_writeReg(RFM69_REG_FDEVLSB, RFM69_FDEVLSB_100000);
- RFM69_writeReg(RFM69_REG_RXBW, RFM69_RXBW_DCCFREQ_000 | RFM69_RXBW_MANT_20 | RFM69_RXBW_EXP_0);
-
- // Force LNA to the highest gain
- //RFM69_writeReg(RFM69_REG_LNA, (RFM69_readReg(REG_LNA) << 2) | RF_LNA_GAINSELECT_MAX);
-}
-
-LOCAL void RFM69_listenModeReset(void)
-{
- // reset vars
-
- //DATALEN = 0;
- //SENDERID = 0;
- //TARGETID = 0;
- //PAYLOADLEN = 0;
- //ACK_REQUESTED = 0;
- //ACK_RECEIVED = 0;
- //LISTEN_BURST_REMAINING_MS = 0;
-}
-
-LOCAL void RFM69_ListenModeStart(void)
-{
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_LISTEN);
- /*
- RFM69_DEBUG(PSTR("RFM69:LSM:Start..\n"));
- while (RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady
- RFM69_listenModeReset();
-
- detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN));
- attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING);
-
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
-
- RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01);
- RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1);
- RFM69_writeReg(RFM69_REG_FRFLSB, RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change!
-
- RFM69_listenModeApplyHighSpeedSettings();
-
- RFM69_writeReg(RFM69_REG_PACKETCONFIG1, RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON);
- RFM69_writeReg(RFM69_REG_PACKETCONFIG2, RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF);
- RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A);
- RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A);
-
- RFM69_setListenConfig(idleListenResolution, rxListenResolution, RFM69_LISTEN1_CRITERIA_RSSI, RFM69_LISTEN1_END_10);
- RFM69_setListenCoefIdle(idleListenCoef);
- RFM69_setListenCoefRx(rxListenCoef);
-
- RFM69_writeReg(RFM69_REG_RSSITHRESH, 180);
- RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 75);
- RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY);
- RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON | RFM69_OPMODE_STANDBY);
*/
+ (void)forceTrigger;
+ return (rfm69_RSSI_t)RFM69_readReg(RFM69_REG_RSSIVALUE);
}
-LOCAL bool RFM69_listenModeEnd(void)
-{
- RFM69_DEBUG(PSTR("RFM69:LSM:End..\n"));
- detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN));
-
- RFM69_writeReg(RFM69_REG_OPMODE,
- RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTENABORT | RFM69_OPMODE_STANDBY);
- RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY);
- RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 0);
-
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
-
- // wait for ModeReady
- //if (!rfm69_ismodeready()) {
- // return false;
- //}
- RFM69_isModeReady();
- RFM69_listenModeReset();
- RFM69_reinitRadio();
-}
-
-LOCAL bool RFM69_reinitRadio(void)
-{
- if (!RFM69_initialise(MY_RFM69_FREQUENCY)) {
- return false;
- }
- //TODO
- //if (_haveEncryptKey) RFM69_encrypt(_encryptKey); // Restore the encryption key if necessary
- //if (_isHighSpeed) RFM69_writeReg(RFM69_REG_LNA, (RFM69_readReg(RFM69_REG_LNA) & ~0x3) | RFM69_LNA_GAINSELECT_AUTO);
- return true;
-}
-
-LOCAL void RFM69_listenModeSendBurst(const uint8_t recipient, uint8_t* data, const uint8_t len)
-{
-
- detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN));
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY);
- RFM69_writeReg(RFM69_REG_PACKETCONFIG1,
- RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON |
- RFM69_PACKET1_CRCAUTOCLEAR_ON);
- RFM69_writeReg(RFM69_REG_PACKETCONFIG2,
- RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF);
- RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A);
- RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A);
- RFM69_listenModeApplyHighSpeedSettings();
- RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1);
- RFM69_writeReg(RFM69_REG_FRFLSB,
- RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change!
-
- // TODO set high power level
-
- union { // union to simplify addressing of long and short parts of time offset
- int32_t l;
- uint8_t b[4];
- } timeRemaining;
-
- uint16_t cycleDurationMs = listenCycleDurationUs / 1000;
-
- timeRemaining.l = cycleDurationMs;
-
- RFM69_DEBUG(PSTR("RFM69:LSM:Send burst for %d ms\n"), cycleDurationMs);
-
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX);
- uint32_t startTime = hwMillis();
-
- while (timeRemaining.l > 0) {
- // send burst
- // write to FIFO TODO refactorize with func, check if send/sendframe could be used, and prepare packet struct
- RFM69_prepareSPITransaction();
- RFM69_csn(LOW);
- RFM69_SPI.transfer(RFM69_REG_FIFO | 0x80);
- RFM69_SPI(len +
- 4); // two bytes for target and sender node, two bytes for the burst time remaining
- RFM69_SPI.transfer(recipient);
- RFM69_SPI.transfer(_address);
-
- // We send the burst time remaining with the packet so the receiver knows how long to wait before trying to reply
- RFM69_SPI.transfer(timeRemaining.b[0]);
- RFM69_SPI.transfer(timeRemaining.b[1]);
-
- for (uint8_t i = 0; i < len; i++) {
- RFM69_SPI.transfer(((uint8_t*)data)[i]);
- }
-
- RFM69_csn(HIGH);
- RFM69_concludeSPITransaction();
-
- while ((RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_FIFONOTEMPTY) !=
- 0x00); // make sure packet is sent before putting more into the FIFO
- timeRemaining.l = cycleDurationMs - (hwMillis() - startTime);
- }
-
- (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX);
- RFM69_reinitRadio();
-}
-
-LOCAL uint32_t RFM69_getUsForResolution(uint8_t resolution)
-{
- switch (resolution) {
- case RFM69_LISTEN1_RESOL_RX_64:
- case RFM69_LISTEN1_RESOL_IDLE_64:
- return 64;
- case RFM69_LISTEN1_RESOL_RX_4100:
- case RFM69_LISTEN1_RESOL_IDLE_4100:
- return 4100;
- case RFM69_LISTEN1_RESOL_RX_262000:
- case RFM69_LISTEN1_RESOL_IDLE_262000:
- return 262000;
- default:
- // Whoops
- return 0;
- }
-}
-
-LOCAL uint32_t RFM69_getCoefForResolution(uint8_t resolution, uint32_t duration)
-{
- uint32_t resolDuration = RFM69_getUsForResolution(resolution);
- uint32_t result = duration / resolDuration;
-
- // If the next-higher coefficient is closer, use that
- if (abs(duration - ((result + 1) * resolDuration)) < abs(duration - (result * resolDuration))) {
- return result + 1;
- }
-
- return result;
-}
-
-LOCAL bool RFM69_chooseResolutionAndCoef(uint8_t *resolutions, uint32_t duration, uint8_t& resolOut,
- uint8_t& coefOut)
-{
- for (int i = 0; resolutions[i]; i++) {
- uint32_t coef = RFM69_getCoefForResolution(resolutions[i], duration);
- if (coef <= 255) {
- coefOut = coef;
- resolOut = resolutions[i];
- return true;
- }
- }
-
- // out of range
- return false;
-}
-
-LOCAL bool RFM69_listenModeSetDurations(uint32_t& rxDuration, uint32_t& idleDuration)
-{
- uint8_t rxResolutions[] = { RFM69_LISTEN1_RESOL_RX_64, RFM69_LISTEN1_RESOL_RX_4100, RFM69_LISTEN1_RESOL_RX_262000, 0 };
- uint8_t idleResolutions[] = { RFM69_LISTEN1_RESOL_IDLE_64, RFM69_LISTEN1_RESOL_IDLE_4100, RFM69_LISTEN1_RESOL_IDLE_262000, 0 };
-
- if (!RFM69_chooseResolutionAndCoef(rxResolutions, rxDuration, rxListenResolution, rxListenCoef)) {
- return false;
- }
-
- if (!RFM69_chooseResolutionAndCoef(idleResolutions, idleDuration, idleListenResolution,
- idleListenCoef)) {
- return false;
- }
-
- rxDuration = RFM69_getUsForResolution(rxListenResolution) * rxListenCoef;
- idleDuration = RFM69_getUsForResolution(idleListenResolution) * idleListenCoef;
- listenCycleDurationUs = rxDuration + idleDuration;
-
- return true;
-}
-
-LOCAL void RFM69_listenModeGetDurations(uint32_t &rxDuration, uint32_t &idleDuration)
-{
- rxDuration = RFM69_getUsForResolution(rxListenResolution) * rxListenCoef;
- idleDuration = RFM69_getUsForResolution(idleListenResolution) * idleListenCoef;
-}
-
-#endif
-
-#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS
-
LOCAL void RFM69_readAllRegs(void)
{
#ifdef RFM69_REGISTER_DETAIL
@@ -1470,5 +1030,3 @@ LOCAL void RFM69_readAllRegs(void)
(void)regVal;
}
}
-
-#endif
diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h
index bc5df4ad3..1f08b084f 100644
--- a/drivers/RFM69/new/RFM69_new.h
+++ b/drivers/RFM69/new/RFM69_new.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -16,22 +16,23 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
- * RFM69 driver refactored for Mysensors
+ * RFM69 driver refactored for MySensors
*
* Based on :
* - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com
* - Automatic Transmit Power Control class derived from RFM69 library.
* Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html
* Copyright Thomas Studwell (2014,2015)
- * - Mysensors generic radio driver implementation, Copyright (C) 2017 Olivier Mauti
+ * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti
*
* Changes by : @tekka, @scalz, @marceloagno
*
* Definitions for Semtech SX1231/H radios:
- * http://www.semtech.com/images/datasheet/sx1231.pdf
- * http://www.semtech.com/images/datasheet/sx1231h.pdf
+ * https://www.semtech.com/uploads/documents/sx1231.pdf
+ * https://www.semtech.com/uploads/documents/sx1231h.pdf
*/
+
/**
* @file RFM69_new.h
*
@@ -42,20 +43,24 @@
* RFM69 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
* - [!] Exclamation mark is prepended in case of error
*
-* |E| SYS | SUB | Message | Comment
-* |-|-------|-------|----------------------------------|-----------------------------------------------------------------------------------
-* | | RFM69 | INIT | | Initialise RFM69 radio
-* | | RFM69 | INIT | PIN,CS=%d,IQP=%d,IQN=%d[,RST=%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST)
-* |!| RFM69 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
-* | | RFM69 | PTX | NO ADJ | TX power level, no adjustment
-* | | RFM69 | PTX | LEVEL=%d dbM | TX power level, set to (LEVEL) dBm
-* | | RFM69 | SLEEP | | Radio in sleep mode
-* | | RFM69 | SAC | SEND ACK,TO=%d,RSSI=%d | ACK sent to (TO), RSSI of incoming message (RSSI)
-* | | RFM69 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX power level (TXL) to match set RSSI (sR), current RSSI (cR)
-* | | RFM69 | SWR | SEND,TO=%d,RETRY=%d | Send to (TO), retry if no ACK received (RETRY)
-* | | RFM69 | SWR | ACK,FROM=%d,SEQ=%d,RSSI=%d | ACK received from (FROM), sequence nr (SEQ), ACK RSSI (RSSI)
-* |!| RFM69 | SWR | NACK | Message sent, no ACK received
-* | | RFM69 | SPP | PCT=%d,TX LEVEL=%d | Set TX level, input TX percent (PCT)
+* |E| SYS | SUB | Message | Comment
+* |-|-------|------|--------------------------------------|-----------------------------------------------------------------------------------
+* | | RFM69 | INIT | | Initialise RFM69 radio
+* | | RFM69 | INIT | PIN,CS=%%d,IQP=%%d,IQN=%%d[,RST=%%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST)
+* | | RFM69 | INIT | HWV=%%d | HW version, see datasheet chapter 9
+* |!| RFM69 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
+* | | RFM69 | PTX | NO ADJ | TX power level, no adjustment
+* | | RFM69 | PTX | LEVEL=%%d dbM | TX power level, set to (LEVEL) dBm
+* | | RFM69 | SAC | SEND ACK,TO=%%d,RSSI=%%d | ACK sent to (TO), RSSI of incoming message (RSSI)
+* | | RFM69 | ATC | ADJ TXL,cR=%%d,tR=%%d..%%d,TXL=%%d | Adjust TX level, current RSSI (cR), target RSSI range (tR), TX level (TXL)
+* | | RFM69 | SWR | SEND,TO=%%d,SEQ=%%d,RETRY=%%d | Send to (TO), sequence number (SWQ), retry if no ACK received (RETRY)
+* | | RFM69 | SWR | ACK,FROM=%%d,SEQ=%%d,RSSI=%%d | ACK received from (FROM), sequence nr (SEQ), ACK RSSI (RSSI)
+* |!| RFM69 | SWR | NACK | Message sent, no ACK received
+* | | RFM69 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level, input TX percent (PCT)
+* | | RFM69 | RSL | | Radio in sleep mode
+* | | RFM69 | RSB | | Radio in standby mode
+* | | RFM69 | PWD | | Power down radio
+* | | RFM69 | PWU | | Power up radio
*
* @brief API declaration for RFM69
*
@@ -72,27 +77,21 @@
#else
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
#endif
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_ESP8266)
-#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
+#define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN
#elif defined(ARDUINO_ARCH_ESP32)
-#warning not implemented yet
+#define DEFAULT_RFM69_IRQ_PIN (16) //!< DEFAULT_RFM69_IRQ_PIN
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_SAMD)
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(LINUX_ARCH_RASPBERRYPI)
#define DEFAULT_RFM69_IRQ_PIN (22) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_STM32F1)
#define DEFAULT_RFM69_IRQ_PIN (PA3) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(TEENSYDUINO)
#define DEFAULT_RFM69_IRQ_PIN (8) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#else
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM (2) //!< DEFAULT_RFM69_IRQ_NUM
#endif
#define DEFAULT_RFM69_CS_PIN (SS) //!< DEFAULT_RFM69_CS_PIN
@@ -101,30 +100,10 @@
#define RFM69_SPI_DATA_ORDER MSBFIRST //!< SPI data order
#define RFM69_SPI_DATA_MODE SPI_MODE0 //!< SPI mode
-// SPI clock divier for non-transaction implementations
-#if (MY_RFM69_SPI_SPEED >= F_CPU / 2)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV2 //!< SPI clock divider 2
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 4)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV4 //!< SPI clock divider 4
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 8)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV8 //!< SPI clock divider 8
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 16)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV16 //!< SPI clock divider 16
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 32)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV32 //!< SPI clock divider 32
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 64)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV64 //!< SPI clock divider 64
-#elif (MY_RFM69_SPI_SPEED >= F_CPU / 128)
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV128 //!< SPI clock divider 128
-#else
-#define RFM69_CLOCK_DIV SPI_CLOCK_DIV256 //!< SPI clock divider 256
-#endif
-
-#if defined (ARDUINO) && !defined (__arm__) && !defined (RFM69_SPI)
+#if defined(ARDUINO) && !defined(__arm__) && !defined(RFM69_SPI)
#include
#if defined(MY_SOFTSPI)
-SoftSPI
-RFM69_SPI;
+SoftSPIRFM69_SPI;
#else
#define RFM69_SPI SPI
#endif
@@ -147,7 +126,7 @@ extern HardwareSPI SPI; //!< SPI
#if (MY_RFM69HW==true)
// RFM69H(C)W
#define RFM69_VERSION_HW //!< HW version
-#define RFM69_MIN_POWER_LEVEL_DBM ((rfm69_powerlevel_t)-2) //!< min. power level, -18dBm
+#define RFM69_MIN_POWER_LEVEL_DBM ((rfm69_powerlevel_t)-2) //!< min. power level, -2dBm
#if defined(MY_RFM69_MAX_POWER_LEVEL_DBM)
#define RFM69_MAX_POWER_LEVEL_DBM MY_RFM69_MAX_POWER_LEVEL_DBM //!< MY_RFM69_MAX_POWER_LEVEL_DBM
#else
@@ -163,71 +142,121 @@ extern HardwareSPI SPI; //!< SPI
#endif
#endif
-#define RFM69_FIFO_SIZE (0xFFu) //!< Max number of bytes the Rx/Tx FIFO can hold
-#define RFM69_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried
-#define RFM69_ATC_TARGET_RANGE_PERCENT (5u) //!< ATC target range +/-%
-#define RFM69_PACKET_HEADER_VERSION (1u) //!< RFM69 packet header version
-#define RFM69_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM69 packet header version
-#define RFM69_RETRIES (5u) //!< Retries in case of failed transmission
-#define RFM69_RETRY_TIMEOUT_MS (200ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different)
-#define RFM69_MODE_READY_TIMEOUT_MS (50ul) //!< Timeout for mode ready
-#define RFM69_TX_LIMIT_MS (1*1000ul) //!< Timeout for packet sent
+#define RFM69_FIFO_SIZE (0xFFu) //!< Max number of bytes the Rx/Tx FIFO can hold
+#define RFM69_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried
+#define RFM69_ATC_TARGET_RANGE_DBM (2u) //!< ATC target range +/- dBm
+#define RFM69_PACKET_HEADER_VERSION (1u) //!< RFM69 packet header version
+#define RFM69_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM69 packet header version
+
+#define RFM69_RETRIES (5u) //!< Retries in case of failed transmission
+#define RFM69_RETRY_TIMEOUT_MS (200ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different)
+#define RFM69_MODE_READY_TIMEOUT_MS (50ul) //!< Timeout for mode ready
-#define RFM69_ACK_REQUESTED (7u) //!< RFM69 header, controlFlag, bit 7
-#define RFM69_ACK_RECEIVED (6u) //!< RFM69 header, controlFlag, bit 6
-#define RFM69_ACK_RSSI_REPORT (5u) //!< RFM69 header, controlFlag, bit 5
+#define RFM69_ACK_REQUESTED (7u) //!< RFM69 header, controlFlag, bit 7
+#define RFM69_ACK_RECEIVED (6u) //!< RFM69 header, controlFlag, bit 6
+#define RFM69_ACK_RSSI_REPORT (5u) //!< RFM69 header, controlFlag, bit 5
-#define RFM69_BROADCAST_ADDRESS (255u) //!< Broadcasting address
-#define RFM69_TARGET_RSSI_DBM (-60) //!< RSSI target
-#define RFM69_HIGH_POWER_DBM (18u) //!< High power threshold, dBm
-#define RFM69_PROMISCUOUS (false) //!< RFM69 promiscuous mode
+#define RFM69_BROADCAST_ADDRESS (255u) //!< Broadcasting address
+#define RFM69_TARGET_RSSI_DBM (-75) //!< RSSI target
+#define RFM69_HIGH_POWER_DBM (18u) //!< High power threshold, dBm
-#define RFM69_RSSItoInternal(__value) ((uint8_t)-(__value*2)) //!< RSSI converting macro
-#define RFM69_internalToRSSI(__value) ((int16_t)-(__value/2)) //!< RSSI converting macro
+#if !defined(MY_RFM69_TX_TIMEOUT_MS)
+#define MY_RFM69_TX_TIMEOUT_MS (2*1000ul) //!< Timeout for packet sent
+#endif
+
+// CSMA settings
+#if !defined(MY_RFM69_CSMA_LIMIT_DBM)
+#define MY_RFM69_CSMA_LIMIT_DBM (-95) //!< upper RX signal sensitivity threshold in dBm for carrier sense access
+#endif
+#if !defined(MY_RFM69_CSMA_TIMEOUT_MS)
+#define MY_RFM69_CSMA_TIMEOUT_MS (500ul) //!< CSMA timeout
+#endif
+// powerup delay
+#define RFM69_POWERUP_DELAY_MS (100ul) //!< Power up delay, allow VCC to settle, transport to become fully operational
+
+// available frequency bands, non trivial values to avoid misconfiguration
+#define RFM69_315MHZ (315000000ul) //!< RFM69_315MHZ
+#define RFM69_433MHZ (433920000ul) //!< RFM69_433MHZ, center frequencz 433.92 MHz
+#define RFM69_868MHZ (868000000ul) //!< RFM69_868MHZ
+#define RFM69_915MHZ (915000000ul) //!< RFM69_915MHZ
+
+#define RFM69_COURSE_TEMP_COEF (-90) //!< puts the temperature reading in the ballpark, user can fine tune the returned value
+#define RFM69_FXOSC (32*1000000ul) //!< OSC freq, 32MHz
+#define RFM69_FSTEP (RFM69_FXOSC / 524288.0f) //!< FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet)
// helper macros
#define RFM69_getACKRequested(__value) ((bool)bitRead(__value,RFM69_ACK_REQUESTED)) //!< getACKRequested
-#define RFM69_setACKRequested(__value, __flag) bitWrite(__value,RFM69_ACK_REQUESTED,__flag) //!< setACKRequested
-#define RFM69_getACKReceived(__value) ((bool)bitRead(__value,RFM69_ACK_RECEIVED)) //!< getACKReceived
-#define RFM69_setACKReceived(__value, __flag) bitWrite(__value,RFM69_ACK_RECEIVED,__flag) //!< setACKReceived
-#define RFM69_setACKRSSIReport(__value, __flag) bitWrite(__value,RFM69_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport
-#define RFM69_getACKRSSIReport(__value) ((bool)bitRead(__value,RFM69_ACK_RSSI_REPORT)) //!< getACKRSSIReport
-
+#define RFM69_setACKRequested(__value, __flag) bitWrite(__value,RFM69_ACK_REQUESTED,__flag) //!< setACKRequested
+#define RFM69_getACKReceived(__value) ((bool)bitRead(__value,RFM69_ACK_RECEIVED)) //!< getACKReceived
+#define RFM69_setACKReceived(__value, __flag) bitWrite(__value,RFM69_ACK_RECEIVED,__flag) //!< setACKReceived
+#define RFM69_setACKRSSIReport(__value, __flag) bitWrite(__value,RFM69_ACK_RSSI_REPORT,__flag)//!< setACKRSSIReport
+#define RFM69_getACKRSSIReport(__value) ((bool)bitRead(__value,RFM69_ACK_RSSI_REPORT)) //!< getACKRSSIReport
// Register access
#define RFM69_READ_REGISTER (0x7Fu) //!< reading register
#define RFM69_WRITE_REGISTER (0x80u) //!< writing register
-// CAD & CSMA
-#define RFM69_CAD_TIMEOUT_MS (2*1000ul) //!< Channel activity detection timeout
-#define RFM69_CSMA_LIMIT_DBM (-90) //!< upper RX signal sensitivity threshold in dBm for carrier sense access
-#define RFM69_CSMA_TIMEOUT_MS (1000ul) //!< CSMA timeout
-
-// powerup delay
-#define RFM69_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational
-
-// available frequency bands, non trivial values to avoid misconfiguration
-#define RFM69_315MHZ (315000000ul) //!< RFM69_315MHZ
-#define RFM69_433MHZ (433920000ul) //!< RFM69_433MHZ, center frequencz 433.92 MHz
-#define RFM69_868MHZ (868000000ul) //!< RFM69_868MHZ
-#define RFM69_915MHZ (915000000ul) //!< RFM69_915MHZ
-
-#define RFM69_COURSE_TEMP_COEF (-90) //!< puts the temperature reading in the ballpark, user can fine tune the returned value
-#define RFM69_FXOSC (32*1000000ul) //!< OSC freq, 32MHz
-#define RFM69_FSTEP (RFM69_FXOSC / 524288.0f) //!< FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet)
-
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
-#define RFM69_LISTEN_RX_US MY_RFM69_DEFAULT_LISTEN_RX_US //!< RFM69_LISTEN_RX_US
-#define RFM69_LISTEN_IDLE_US MY_RFM69_DEFAULT_LISTEN_IDLE_US //!< RFM69_LISTEN_IDLE_US
+// Modem configuration section
+#define RFM69_CONFIG_FSK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00) //!< RFM69_CONFIG_FSK
+#define RFM69_CONFIG_GFSK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_10) //!< RFM69_CONFIG_GFSK
+#define RFM69_CONFIG_OOK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_OOK | RFM69_DATAMODUL_MODULATIONSHAPING_00) //!< RFM69_CONFIG_OOK
+
+#define RFM69_CONFIG_NOWHITE (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_OFF | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_NOWHITE
+#define RFM69_CONFIG_WHITE (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_WHITE
+#define RFM69_CONFIG_MANCHESTER (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_MANCHESTER | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_MANCHESTER
+
+#define RFM69_RXBW_111_24_4 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_4) //!< RFM69_RXBW_111_24_4
+#define RFM69_RXBW_111_24_3 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_3) //!< RFM69_RXBW_111_24_3
+#define RFM69_RXBW_111_24_2 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_111_24_2
+#define RFM69_RXBW_111_16_2 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_111_16_2
+#define RFM69_RXBW_111_16_1 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_1) //!< RFM69_RXBW_111_16_1
+#define RFM69_RXBW_111_16_0 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_0) //!< RFM69_RXBW_111_16_0
+#define RFM69_RXBW_010_16_2 (RFM69_RXBW_DCCFREQ_010 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_010_16_2
+
+#define RFM69_FSK_BR2_FD5 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR2_FD5
+#define RFM69_FSK_BR2_4_FD4_8 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR2_4_FD4_8
+#define RFM69_FSK_BR4_8_FD9_6 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR4_8_FD9_6
+#define RFM69_FSK_BR9_6_FD19_2 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR9_6_FD19_2
+#define RFM69_FSK_BR19_2_FD38_4 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR19_2_FD38_4
+#define RFM69_FSK_BR38_4_FD76_8 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR38_4_FD76_8
+#define RFM69_FSK_BR55_5_FD50 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR55_5_FD50
+#define RFM69_FSK_BR57_6_FD120 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR57_6_FD120
+#define RFM69_FSK_BR125_FD125 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR125_FD125
+#define RFM69_FSK_BR250_FD250 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR250_FD250
+
+#define RFM69_GFSK_BR2_FD5 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR2_FD5
+#define RFM69_GFSK_BR2_4_FD4_8 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR2_4_FD4_8
+#define RFM69_GFSK_BR4_8_FD9_6 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR4_8_FD9_6
+#define RFM69_GFSK_BR9_6_FD19_2 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR9_6_FD19_2
+#define RFM69_GFSK_BR19_2_FD38_4 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR19_2_FD38_4
+#define RFM69_GFSK_BR38_4_FD76_8 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR38_4_FD76_8
+#define RFM69_GFSK_BR55_5_FD50 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR55_5_FD50
+#define RFM69_GFSK_BR57_6_FD120 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR57_6_FD120
+#define RFM69_GFSK_BR125_FD125 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR125_FD125
+#define RFM69_GFSK_BR250_FD250 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR250_FD250
+
+#define RFM69_OOK_BR2_FD5 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR2_FD5
+#define RFM69_OOK_BR2_4_FD4_8 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR2_4_FD4_8
+#define RFM69_OOK_BR4_8_FD9_6 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR4_8_FD9_6
+#define RFM69_OOK_BR9_6_FD19_2 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR9_6_FD19_2
+#define RFM69_OOK_BR19_2_FD38_4 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR19_2_FD38_4
+#define RFM69_OOK_BR38_4_FD76_8 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR38_4_FD76_8
+#define RFM69_OOK_BR55_5_FD50 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR55_5_FD50
+#define RFM69_OOK_BR57_6_FD120 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR57_6_FD120
+#define RFM69_OOK_BR125_FD125 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR125_FD125
+#define RFM69_OOK_BR250_FD250 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR250_FD250
+
+#if !defined(MY_RFM69_MODEM_CONFIGURATION)
+#define MY_RFM69_MODEM_CONFIGURATION RFM69_FSK_BR55_5_FD50 //!< default setting, RFM69_FSK_BR55_5_FD50
#endif
/**
* @brief Radio modes
*/
typedef enum {
- RFM69_RADIO_MODE_RX = 0, //!< RX mode
- RFM69_RADIO_MODE_TX = 1, //!< TX mode
- RFM69_RADIO_MODE_CAD = 2, //!< CAD mode
+ RFM69_RADIO_MODE_RX = 0, //!< RX mode
+ RFM69_RADIO_MODE_TX = 1, //!< TX mode
+ RFM69_RADIO_MODE_CAD = 2, //!< CAD mode
RFM69_RADIO_MODE_SLEEP = 3, //!< SLEEP mode
RFM69_RADIO_MODE_STDBY = 4, //!< STDBY mode
RFM69_RADIO_MODE_SYNTH = 5, //!< SYNTH mode
@@ -260,19 +289,20 @@ typedef int8_t rfm69_powerlevel_t;
* IMPORTANT: Do not change order (see datasheet for packet structure)
*/
typedef struct {
- uint8_t packetLen; //!< Packet length
- uint8_t recipient; //!< Payload recipient
- uint8_t version; //!< Header version
- uint8_t sender; //!< Payload sender
- rfm69_controlFlags_t controlFlags; //!< Control flags, used for ACK
- rfm69_sequenceNumber_t sequenceNumber; //!< Packet sequence number, used for ACK
+ uint8_t packetLen; //!< packet length
+ uint8_t recipient; //!< payload recipient
+ uint8_t version; //!< header version (20180128tk: >=3.0.0 fused with controlFlags)
+ uint8_t sender; //!< payload sender
+ rfm69_controlFlags_t controlFlags; //!< control flags, used for ACK
+ rfm69_sequenceNumber_t sequenceNumber; //!< packet sequence number, used for ACK
} __attribute__((packed)) rfm69_header_t;
+
/**
* @brief RFM69 ACK packet structure
*/
typedef struct {
- rfm69_sequenceNumber_t sequenceNumber; //!< sequence number
- rfm69_RSSI_t RSSI; //!< RSSI
+ rfm69_sequenceNumber_t sequenceNumber; //!< sequence number
+ rfm69_RSSI_t RSSI; //!< RSSI
} __attribute__((packed)) rfm69_ack_t;
#define RFM69_HEADER_LEN sizeof(rfm69_header_t) //!< Size header inside payload
@@ -280,6 +310,7 @@ typedef struct {
/**
* @brief Packet structure
+* IMPORTANT: Do not change order
*/
typedef struct {
union {
@@ -296,35 +327,46 @@ typedef struct {
rfm69_RSSI_t RSSI; //!< RSSI of current packet, RSSI = value - 137
} __attribute__((packed)) rfm69_packet_t;
-
/**
* @brief RFM69 internal variables
*/
typedef struct {
- uint8_t address; //!< Node address
- rfm69_packet_t currentPacket; //!< Buffer for current packet
- rfm69_sequenceNumber_t txSequenceNumber; //!< RFM69_txSequenceNumber
- rfm69_powerlevel_t powerLevel; //!< TX power level dBm
- uint8_t ATCtargetRSSI; //!< ATC: target RSSI
+ uint8_t address; //!< Node address
+ rfm69_packet_t currentPacket; //!< Buffer for current packet
+ rfm69_sequenceNumber_t txSequenceNumber; //!< RFM69_txSequenceNumber
+ rfm69_powerlevel_t powerLevel; //!< TX power level dBm
+ uint8_t ATCtargetRSSI; //!< ATC: target RSSI
// 8 bit
- rfm69_radio_mode_t radioMode : 3; //!< current transceiver state
- bool dataSent : 1; //!< Data sent
- bool dataReceived : 1; //!< data received
- bool ackReceived : 1; //!< ack received
- bool ATCenabled : 1; //!< ATC enabled
- bool listenModeEnabled : 1; //!< Listen Mode enabled
+ rfm69_radio_mode_t radioMode : 3; //!< current transceiver state
+ bool dataReceived : 1; //!< data received
+ bool ackReceived : 1; //!< ACK received
+ bool ATCenabled : 1; //!< ATC enabled
+ uint8_t reserved : 2; //!< Reserved
} rfm69_internal_t;
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
-uint8_t rxListenCoef;
-uint8_t rxListenResolution;
-uint8_t idleListenCoef;
-uint8_t idleListenResolution;
-uint32_t listenCycleDurationUs;
-#endif
-
#define LOCAL static //!< static
+/**
+* @brief RFM69_handler
+*/
+LOCAL void RFM69_handler(void);
+
+/**
+* @brief Clear flags and FIFO
+*/
+LOCAL void RFM69_clearFIFO(void);
+
+/**
+* @brief Check for channel activity
+* @return True if channel activity under RFM69_CSMA_LIMIT_DBM
+*/
+LOCAL bool RFM69_channelFree(void);
+
+/**
+* @brief RFM69_interruptHandling
+*/
+LOCAL void RFM69_interruptHandling(void);
+
/**
* @brief Initialise the driver transport hardware and software
* @param frequencyHz Frequency in Hz
@@ -346,7 +388,7 @@ LOCAL uint8_t RFM69_getAddress(void);
/**
* @brief Tests whether a new message is available
-* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM69_recv()
+* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM69_receive()
*/
LOCAL bool RFM69_available(void);
@@ -356,7 +398,7 @@ LOCAL bool RFM69_available(void);
* @param maxBufSize Max buffer size
* @return Number of bytes
*/
-LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize);
+LOCAL uint8_t RFM69_receive(uint8_t *buf, const uint8_t maxBufSize);
/**
* @brief RFM69_sendFrame
@@ -364,7 +406,7 @@ LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize);
* @param increaseSequenceCounter
* @return True if packet sent
*/
-LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCounter = true);
+LOCAL bool RFM69_sendFrame(rfm69_packet_t *packet, const bool increaseSequenceCounter = true);
/**
* @brief RFM69_send
@@ -375,7 +417,7 @@ LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCo
* @param increaseSequenceCounter
* @return True if frame sent
*/
-LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
+LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len,
const rfm69_controlFlags_t flags, const bool increaseSequenceCounter = true);
/**
@@ -396,25 +438,30 @@ LOCAL bool RFM69_setTxPowerLevel(rfm69_powerlevel_t newPowerLevel);
* @return power level
*/
LOCAL rfm69_powerlevel_t RFM69_getTxPowerLevel(void);
+
/**
* @brief Reports the transmitter power output level in percents
* @return power level
*/
LOCAL uint8_t RFM69_getTxPowerPercent(void);
+
/**
* @brief Sets the radio into low-power sleep mode
* @return true if sleep mode was successfully entered
*/
LOCAL bool RFM69_sleep(void);
+
/**
* @brief Sets the radio to standby mode
* @return true if standby mode was successfully entered
*/
LOCAL bool RFM69_standBy(void);
+
/**
* @brief Power down radio (HW)
*/
LOCAL void RFM69_powerDown(void);
+
/**
* @brief Power up radio (HW)
*/
@@ -438,7 +485,7 @@ LOCAL void RFM69_sendACK(const uint8_t recipient, const rfm69_sequenceNumber_t s
* @param retryWaitTimeMS
* @return True if packet successfully sent
*/
-LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer,
+LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void *buffer,
const uint8_t bufferSize,
const uint8_t retries = RFM69_RETRIES, const uint32_t retryWaitTimeMS = RFM69_RETRY_TIMEOUT_MS);
@@ -465,6 +512,7 @@ LOCAL int16_t RFM69_getSendingRSSI(void);
* @return RSSI Signal strength of last received packet
*/
LOCAL int16_t RFM69_getReceivingRSSI(void);
+
/**
* @brief RFM69_executeATC
* @param currentRSSI
@@ -491,12 +539,11 @@ LOCAL bool RFM69_isModeReady(void);
*/
LOCAL bool RFM69_sanityCheck(void);
-
/**
* @brief RFM69_encrypt Set encryption mode
* @param key if key is null, encryption is disabled. Key has to be 16 bytes!
*/
-LOCAL void RFM69_encrypt(const char* key);
+LOCAL void RFM69_encrypt(const char *key);
/**
* @brief RFM69_setHighPowerRegs
@@ -509,7 +556,7 @@ LOCAL void RFM69_setHighPowerRegs(const bool onOff);
* @param forceTrigger
* @return RSSI (internal format)
*/
-LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger = false);
+LOCAL rfm69_RSSI_t RFM69_readRSSI(const bool forceTrigger = false);
/**
* @brief RFM69_ATCmode
@@ -518,96 +565,12 @@ LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger = false);
*/
LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI = RFM69_TARGET_RSSI_DBM);
-#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS
/**
-* @brief RFM69_readAllRegs Read and display RFM69 register contents
+* @brief RFM69_readAllRegs
+* Read and display all RFM69 register contents.
+* @note define RFM69_REGISTER_DETAIL for register content decoding.
*/
LOCAL void RFM69_readAllRegs(void);
-#endif
-// ************************ LISTENMODE SECTION ************************
-
-#if defined(MY_RFM69_ENABLE_LISTENMODE)
-
-/**
-* @brief RFM69_listenModeApplyHighSpeedSettings Set high speed settings
-*/
-LOCAL void RFM69_listenModeApplyHighSpeedSettings(void);
-
-/**
-* @brief RFM69_ListenModeStart Switch radio to listen Mode in prep for sleep until burst
-*/
-LOCAL void RFM69_ListenModeStart(void);
-
-/**
-* @brief RFM69_listenModeEnd Exit listen mode and reinit the radio
-* @return
-*/
-LOCAL bool RFM69_listenModeEnd(void);
-
-/**
-* @brief RFM69_listenModeReset Reset listen mode
-*/
-LOCAL void RFM69_listenModeReset(void);
-
-/**
-* @brief RFM69_reinitRadio Restore previous radio settigns for normal mode
-* @return
-*/
-LOCAL bool RFM69_reinitRadio(void);
-
-/**
-* @brief RFM69_listenModeSendBurst This repeatedly sends the message to the target node for
- * the duration of an entire listen cycle. The amount of time remaining in the burst is
- * transmitted to the receiver, and it is expected that the receiver
- * wait for the burst to end before attempting a reply.
-* @param recipient
-* @param data
-* @param len
-*/
-LOCAL void RFM69_listenModeSendBurst(const uint8_t recipient, uint8_t* data, const uint8_t len);
-
-/**
-* @brief getUsForResolution
-* @param resolution
-* @return
-*/
-LOCAL uint32_t RFM69_getUsForResolution(uint8_t resolution);
-
-/**
-* @brief getCoefForResolution
-* @param resolution
-* @param duration
-* @return
-*/
-LOCAL uint32_t RFM69_getCoefForResolution(uint8_t resolution, uint32_t duration);
-
-/**
-* @brief RFM69_chooseResolutionAndCoef
-* @param resolutions
-* @param duration
-* @param resolOut
-* @param coefOut
-* @return
-*/
-LOCAL bool RFM69_chooseResolutionAndCoef(uint8_t *resolutions, uint32_t duration, uint8_t& resolOut,
- uint8_t& coefOut);
-
-/**
-* @brief RFM69_listenModeSetDurations
-* @param rxDuration
-* @param idleDuration
-* @return
-*/
-LOCAL bool RFM69_listenModeSetDurations(uint32_t& rxDuration, uint32_t& idleDuration);
-
-/**
-* @brief RFM69_listenModeGetDurations
-* @param rxDuration
-* @param idleDuration
-*/
-LOCAL void RFM69_listenModeGetDurations(uint32_t &rxDuration, uint32_t &idleDuration);
-
-#endif
#endif
diff --git a/drivers/RFM69/new/RFM69registers_new.h b/drivers/RFM69/new/RFM69registers_new.h
index 19af8ea5a..2c2dade75 100644
--- a/drivers/RFM69/new/RFM69registers_new.h
+++ b/drivers/RFM69/new/RFM69registers_new.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2016 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -16,20 +16,20 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
- * RFM69 driver refactored for Mysensors
+ * RFM69 driver refactored for MySensors
*
* Based on :
* - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com
* - Automatic Transmit Power Control class derived from RFM69 library.
* Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html
* Copyright Thomas Studwell (2014,2015)
- * - Mysensors generic radio driver implementation, Copyright (C) 2017 Olivier Mauti
+ * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti
*
* Changes by : @tekka, @scalz, @marceloagno
*
* Definitions for Semtech SX1231/H radios:
- * http://www.semtech.com/images/datasheet/sx1231.pdf
- * http://www.semtech.com/images/datasheet/sx1231h.pdf
+ * https://www.semtech.com/uploads/documents/sx1231.pdf
+ * https://www.semtech.com/uploads/documents/sx1231h.pdf
*/
#define RFM69_REG_FIFO 0x00
@@ -150,71 +150,69 @@
#define RFM69_DATAMODUL_MODULATIONSHAPING_10 0x02
#define RFM69_DATAMODUL_MODULATIONSHAPING_11 0x03
-
// RegBitRate (bits/sec) example bit rates
#define RFM69_BITRATEMSB_1200 0x68
#define RFM69_BITRATELSB_1200 0x2B
+#define RFM69_BITRATEMSB_2000 0x3e
+#define RFM69_BITRATELSB_2000 0x80
#define RFM69_BITRATEMSB_2400 0x34
#define RFM69_BITRATELSB_2400 0x15
#define RFM69_BITRATEMSB_4800 0x1A // Default
#define RFM69_BITRATELSB_4800 0x0B // Default
#define RFM69_BITRATEMSB_9600 0x0D
#define RFM69_BITRATELSB_9600 0x05
-#define RFM69_BITRATEMSB_19200 0x06
-#define RFM69_BITRATELSB_19200 0x83
-#define RFM69_BITRATEMSB_38400 0x03
-#define RFM69_BITRATELSB_38400 0x41
-
-#define RFM69_BITRATEMSB_38323 0x03
-#define RFM69_BITRATELSB_38323 0x43
-
-#define RFM69_BITRATEMSB_34482 0x03
-#define RFM69_BITRATELSB_34482 0xA0
-
-#define RFM69_BITRATEMSB_76800 0x01
-#define RFM69_BITRATELSB_76800 0xA1
-#define RFM69_BITRATEMSB_153600 0x00
-#define RFM69_BITRATELSB_153600 0xD0
-#define RFM69_BITRATEMSB_57600 0x02
-#define RFM69_BITRATELSB_57600 0x2C
-#define RFM69_BITRATEMSB_115200 0x01
-#define RFM69_BITRATELSB_115200 0x16
#define RFM69_BITRATEMSB_12500 0x0A
#define RFM69_BITRATELSB_12500 0x00
+#define RFM69_BITRATEMSB_19200 0x06
+#define RFM69_BITRATELSB_19200 0x83
#define RFM69_BITRATEMSB_25000 0x05
#define RFM69_BITRATELSB_25000 0x00
+#define RFM69_BITRATEMSB_32768 0x03
+#define RFM69_BITRATELSB_32768 0xD1
+#define RFM69_BITRATEMSB_38400 0x03
+#define RFM69_BITRATELSB_38400 0x41
#define RFM69_BITRATEMSB_50000 0x02
#define RFM69_BITRATELSB_50000 0x80
+#define RFM69_BITRATEMSB_55555 0x02
+#define RFM69_BITRATELSB_55555 0x40
+#define RFM69_BITRATEMSB_57600 0x02
+#define RFM69_BITRATELSB_57600 0x2C
+#define RFM69_BITRATEMSB_76800 0x01
+#define RFM69_BITRATELSB_76800 0xA1
#define RFM69_BITRATEMSB_100000 0x01
#define RFM69_BITRATELSB_100000 0x40
+#define RFM69_BITRATEMSB_115200 0x01
+#define RFM69_BITRATELSB_115200 0x16
+#define RFM69_BITRATEMSB_125000 0x01
+#define RFM69_BITRATELSB_125000 0x00
#define RFM69_BITRATEMSB_150000 0x00
#define RFM69_BITRATELSB_150000 0xD5
+#define RFM69_BITRATEMSB_153600 0x00
+#define RFM69_BITRATELSB_153600 0xD0
#define RFM69_BITRATEMSB_200000 0x00
#define RFM69_BITRATELSB_200000 0xA0
#define RFM69_BITRATEMSB_250000 0x00
#define RFM69_BITRATELSB_250000 0x80
#define RFM69_BITRATEMSB_300000 0x00
#define RFM69_BITRATELSB_300000 0x6B
-#define RFM69_BITRATEMSB_32768 0x03
-#define RFM69_BITRATELSB_32768 0xD1
-// custom bit rates
-#define RFM69_BITRATEMSB_55555 0x02
-#define RFM69_BITRATELSB_55555 0x40
-#define RFM69_BITRATEMSB_200KBPS 0x00
-#define RFM69_BITRATELSB_200KBPS 0xa0
-
// RegFdev - frequency deviation (Hz)
#define RFM69_FDEVMSB_2000 0x00
#define RFM69_FDEVLSB_2000 0x21
+#define RFM69_FDEVMSB_4800 0x00
+#define RFM69_FDEVLSB_4800 0x4f
#define RFM69_FDEVMSB_5000 0x00 // Default
#define RFM69_FDEVLSB_5000 0x52 // Default
#define RFM69_FDEVMSB_7500 0x00
#define RFM69_FDEVLSB_7500 0x7B
+#define RFM69_FDEVMSB_9600 0x00
+#define RFM69_FDEVLSB_9600 0x9d
#define RFM69_FDEVMSB_10000 0x00
#define RFM69_FDEVLSB_10000 0xA4
#define RFM69_FDEVMSB_15000 0x00
#define RFM69_FDEVLSB_15000 0xF6
+#define RFM69_FDEVMSB_19200 0x01
+#define RFM69_FDEVLSB_19200 0x3b
#define RFM69_FDEVMSB_20000 0x01
#define RFM69_FDEVLSB_20000 0x48
#define RFM69_FDEVMSB_25000 0x01
@@ -223,6 +221,8 @@
#define RFM69_FDEVLSB_30000 0xEC
#define RFM69_FDEVMSB_35000 0x02
#define RFM69_FDEVLSB_35000 0x3D
+#define RFM69_FDEVMSB_38400 0x02
+#define RFM69_FDEVLSB_38400 0x75
#define RFM69_FDEVMSB_40000 0x02
#define RFM69_FDEVLSB_40000 0x8F
#define RFM69_FDEVMSB_45000 0x02
@@ -239,6 +239,8 @@
#define RFM69_FDEVLSB_70000 0x7B
#define RFM69_FDEVMSB_75000 0x04
#define RFM69_FDEVLSB_75000 0xCD
+#define RFM69_FDEVMSB_76800 0x04
+#define RFM69_FDEVLSB_76800 0xea
#define RFM69_FDEVMSB_80000 0x05
#define RFM69_FDEVLSB_80000 0x1F
#define RFM69_FDEVMSB_85000 0x05
@@ -253,6 +255,8 @@
#define RFM69_FDEVLSB_110000 0x0A
#define RFM69_FDEVMSB_120000 0x07
#define RFM69_FDEVLSB_120000 0xAE
+#define RFM69_FDEVMSB_125000 0x08
+#define RFM69_FDEVLSB_125000 0x00
#define RFM69_FDEVMSB_130000 0x08
#define RFM69_FDEVLSB_130000 0x52
#define RFM69_FDEVMSB_140000 0x08
@@ -290,7 +294,7 @@
#define RFM69_FDEVMSB_300000 0x13
#define RFM69_FDEVLSB_300000 0x33
-#define RFM69_NOP 0x00
+#define RFM69_NOP 0x00
// RegOsc1
#define RFM69_OSC1_RCCAL_START 0x80
diff --git a/drivers/RFM69/old/RFM69_old.h b/drivers/RFM69/old/RFM69_old.h
index 3129b6529..9e56b6a00 100644
--- a/drivers/RFM69/old/RFM69_old.h
+++ b/drivers/RFM69/old/RFM69_old.h
@@ -41,15 +41,16 @@
#else
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
#endif
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_ESP8266)
-#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
+#define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_ESP32)
-#warning not implemented yet
+#define DEFAULT_RFM69_IRQ_PIN (16) //!< DEFAULT_RFM69_IRQ_PIN
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(ARDUINO_ARCH_SAMD)
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(LINUX_ARCH_RASPBERRYPI)
#define DEFAULT_RFM69_IRQ_PIN (22) //!< DEFAULT_RFM69_IRQ_PIN
#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
@@ -58,7 +59,7 @@
#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
#elif defined(TEENSYDUINO)
#define DEFAULT_RFM69_IRQ_PIN (8) //!< DEFAULT_RFM69_IRQ_PIN
-#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
+#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
#else
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
#define DEFAULT_RFM69_IRQ_NUM (2) //!< DEFAULT_RFM69_IRQ_NUM
diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp
index cc55a41f1..a8e7deee6 100644
--- a/drivers/RFM95/RFM95.cpp
+++ b/drivers/RFM95/RFM95.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -18,7 +18,11 @@
*
* Based on Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley
* Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html
- * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017 Olivier Mauti
+ *
+ * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017-2018 Olivier Mauti
+ *
+ * Definitions for HopeRF LoRa radios:
+ * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
*
*/
@@ -31,41 +35,34 @@
#define RFM95_DEBUG(x,...) //!< DEBUG null
#endif
-#if defined (SREG) // To identify AVR vs EP8266
-uint8_t _SREG; // Used to save and restore the SREG values in SPI transactions
-#endif
-
-#if defined (SPCR) && defined (SPSR)
-uint8_t _SPCR; //!< _SPCR
-uint8_t _SPSR; //!< _SPSR
-#endif
+rfm95_internal_t RFM95; //!< internal variables
+volatile uint8_t RFM95_irq; //(externalRSSI + RFM95_RSSI_OFFSET);
+}
+
+LOCAL inline int16_t RFM95_internalToRSSI(const rfm95_RSSI_t internalRSSI)
+{
+ return static_cast(internalRSSI - RFM95_RSSI_OFFSET);
+}
LOCAL bool RFM95_initialise(const uint32_t frequencyHz)
{
RFM95_DEBUG(PSTR("RFM95:INIT\n"));
- // reset radio module if rst pin defined
+ // power pin, if defined
#if defined(MY_RFM95_POWER_PIN)
hwPinMode(MY_RFM95_POWER_PIN, OUTPUT);
#endif
RFM95_powerUp();
+ // reset radio module if rst pin defined
#if defined(MY_RFM95_RST_PIN)
hwPinMode(MY_RFM95_RST_PIN, OUTPUT);
hwDigitalWrite(MY_RFM95_RST_PIN, LOW);
// 100uS
- delayMicroseconds(100);
+ delayMicroseconds(RFM95_POWERUP_DELAY_MS);
hwDigitalWrite(MY_RFM95_RST_PIN, HIGH);
// wait until chip ready
delay(5);
@@ -168,16 +192,20 @@ LOCAL bool RFM95_initialise(const uint32_t frequencyHz)
RFM95_SPI.begin();
// Set LoRa mode (during sleep mode)
- RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE);
+ (void)RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE);
delay(10); // Wait for sleep mode to take over
- if (RFM95_readReg(RFM95_REG_01_OP_MODE) != (RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE)) {
- return false; // No device present?
- }
+
+ // TCXO init, if present
+#if defined(MY_RFM95_TCXO)
+ RFM95_enableTCXO();
+#else
+ (void)RFM95_enableTCXO;
+#endif
// Set up FIFO, 256 bytes: LoRa max message 64 bytes, set half RX half TX (default)
- RFM95_writeReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR, RFM95_RX_FIFO_ADDR);
- RFM95_writeReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR, RFM95_TX_FIFO_ADDR);
- RFM95_writeReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH, RFM95_MAX_PACKET_LEN);
+ (void)RFM95_writeReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR, RFM95_RX_FIFO_ADDR);
+ (void)RFM95_writeReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR, RFM95_TX_FIFO_ADDR);
+ (void)RFM95_writeReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH, RFM95_MAX_PACKET_LEN);
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
const rfm95_modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION };
@@ -185,64 +213,76 @@ LOCAL bool RFM95_initialise(const uint32_t frequencyHz)
RFM95_setPreambleLength(RFM95_PREAMBLE_LENGTH);
RFM95_setFrequency(frequencyHz);
(void)RFM95_setTxPowerLevel(MY_RFM95_TX_POWER_DBM);
- // IRQ
- hwPinMode(MY_RFM95_IRQ_PIN, INPUT);
-#if defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(MY_SOFTSPI)
- RFM95_SPI.usingInterrupt(MY_RFM95_IRQ_NUM);
-#endif
if (!RFM95_sanityCheck()) {
- RFM95_DEBUG(
- PSTR("!RFM95:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module
+ // sanity check failed, check wiring or replace module
+ RFM95_DEBUG(PSTR("!RFM95:INIT:SANCHK FAIL\n"));
return false;
}
- attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING);
+ // IRQ
+ RFM95_irq = false;
+ hwPinMode(MY_RFM95_IRQ_PIN, INPUT);
+ attachInterrupt(MY_RFM95_IRQ_NUM, RFM95_interruptHandler, RISING);
return true;
}
-// RxDone, TxDone, CADDone is mapped to DI0
LOCAL void RFM95_interruptHandler(void)
{
- // Read the interrupt register
+ // set flag
+ RFM95_irq = true;
+}
+
+// RxDone, TxDone, CADDone is mapped to DI0
+LOCAL void RFM95_interruptHandling(void)
+{
+ // read interrupt register
const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS);
- if (RFM95.radioMode == RFM95_RADIO_MODE_RX &&
- (irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) {
- // CRC error or timeout
- // RXcontinuous mode: radio stays in RX mode, clearing IRQ needed
- } else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) {
- // set radio to STDBY (we are in RXcontinuous mode)
+ if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) {
+ // RXSingle mode: Radio goes automatically to STDBY after packet received
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
- // Have received a packet
- //In order to retrieve received data from FIFO the user must ensure that ValidHeader, PayloadCrcError, RxDone and RxTimeout interrupts in the status register RegIrqFlags are not asserted to ensure that packet reception has terminated successfully(i.e.no flags should be set).
- const uint8_t bufLen = min(RFM95_readReg(RFM95_REG_13_RX_NB_BYTES), (uint8_t)RFM95_MAX_PACKET_LEN);
- if (bufLen >= RFM95_HEADER_LEN) {
- // Reset the fifo read ptr to the beginning of the packet
- RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR));
- RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen);
- RFM95.currentPacket.RSSI = static_cast(RFM95_readReg(
- RFM95_REG_1A_PKT_RSSI_VALUE)); // RSSI of latest packet received
- RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE));
- RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN;
- // Message for us
- if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) &&
- (RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address ||
- RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) {
- RFM95.ackReceived = RFM95_getACKReceived(RFM95.currentPacket.header.controlFlags) &&
- !RFM95_getACKRequested(RFM95.currentPacket.header.controlFlags);
- RFM95.dataReceived = !RFM95.ackReceived;
+ // Check CRC flag
+ if (!(irqFlags & RFM95_PAYLOAD_CRC_ERROR)) {
+ const uint8_t bufLen = min(RFM95_readReg(RFM95_REG_13_RX_NB_BYTES), (uint8_t)RFM95_MAX_PACKET_LEN);
+ if (bufLen >= RFM95_HEADER_LEN) {
+ // Reset the fifo read ptr to the beginning of the packet
+ (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR));
+ (void)RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen);
+ RFM95.currentPacket.RSSI = static_cast(RFM95_readReg(
+ RFM95_REG_1A_PKT_RSSI_VALUE)); // RSSI of latest packet received
+ RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE));
+ RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN;
+ if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) &&
+ (RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address ||
+ RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) {
+ // Message for us
+ RFM95.ackReceived = RFM95_getACKReceived(RFM95.currentPacket.header.controlFlags) &&
+ !RFM95_getACKRequested(RFM95.currentPacket.header.controlFlags);
+ RFM95.dataReceived = !RFM95.ackReceived;
+ }
}
+ } else {
+ // CRC error
+ RFM95_DEBUG(PSTR("!RFM95:IRH:CRC ERROR\n"));
+ // FIFO is cleared when switch from STDBY to RX or TX
+ (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX);
}
-
} else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) {
- (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); // change eventually to RX
+ (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX);
} else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) {
- RFM95.cad = irqFlags & RFM95_CAD_DETECTED;
+ RFM95.channelActive = irqFlags & RFM95_CAD_DETECTED;
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
}
+ // Clear IRQ flags
+ RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, RFM95_CLEAR_IRQ);
+}
- // Clear all IRQ flags
- RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xFF);
+LOCAL void RFM95_handler(void)
+{
+ if (RFM95_irq) {
+ RFM95_irq = false;
+ RFM95_interruptHandling();
+ }
}
LOCAL bool RFM95_available(void)
@@ -253,73 +293,67 @@ LOCAL bool RFM95_available(void)
} else if (RFM95.radioMode == RFM95_RADIO_MODE_TX) {
return false;
} else if (RFM95.radioMode != RFM95_RADIO_MODE_RX) {
- // we are not in RX, and no data received
+ // we are not in RX, not CAD, and no data received
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX);
}
return false;
}
-LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize)
+LOCAL uint8_t RFM95_receive(uint8_t *buf, const uint8_t maxBufSize)
{
-
- // atomic
-#ifdef SREG
- _SREG = SREG;
-#endif
-
- noInterrupts();
-
- const uint8_t payloadLen = RFM95.currentPacket.payloadLen < maxBufSize?
- RFM95.currentPacket.payloadLen : maxBufSize;
+ const uint8_t payloadLen = min(RFM95.currentPacket.payloadLen, maxBufSize);
const uint8_t sender = RFM95.currentPacket.header.sender;
const rfm95_sequenceNumber_t sequenceNumber = RFM95.currentPacket.header.sequenceNumber;
const rfm95_controlFlags_t controlFlags = RFM95.currentPacket.header.controlFlags;
const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI;
const rfm95_SNR_t SNR = RFM95.currentPacket.SNR;
if (buf != NULL) {
- (void)memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen);
- RFM95.dataReceived = false;
+ (void)memcpy((void *)buf, (void *)&RFM95.currentPacket.payload, payloadLen);
}
-#ifdef SREG
- SREG = _SREG; // restore interrupts
-#endif
-
- interrupts(); // explicitly re-enable interrupts
-
+ // clear data flag
+ RFM95.dataReceived = false;
// ACK handling
if (RFM95_getACKRequested(controlFlags) && !RFM95_getACKReceived(controlFlags)) {
+#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16*1000000ul)
+ // delay for fast GW and slow nodes
+ delay(50);
+#endif
RFM95_sendACK(sender, sequenceNumber, RSSI, SNR);
}
-
return payloadLen;
}
-LOCAL bool RFM95_sendFrame(rfm95_packet_t &packet, const bool increaseSequenceCounter)
+LOCAL bool RFM95_sendFrame(rfm95_packet_t *packet, const bool increaseSequenceCounter)
{
- const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN;
- // Make sure we dont interrupt an outgoing message
- (void)RFM95_waitPacketSent();
- (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); //==> not needed
// Check channel activity
if (!RFM95_waitCAD()) {
return false;
}
+ // radio is in STDBY
if (increaseSequenceCounter) {
// increase sequence counter, overflow is ok
RFM95.txSequenceNumber++;
}
- packet.header.sequenceNumber = RFM95.txSequenceNumber;
+ packet->header.sequenceNumber = RFM95.txSequenceNumber;
// Position at the beginning of the TX FIFO
- RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR);
+ (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR);
// write packet
- RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet.data, finalLen);
+ const uint8_t finalLen = packet->payloadLen + RFM95_HEADER_LEN;
+ (void)RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet->data, finalLen);
// total payload length
- RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen);
+ (void)RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen);
// send message, if sent, irq fires and radio returns to standby
- return RFM95_setRadioMode(RFM95_RADIO_MODE_TX);
+ (void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX);
+ // wait until IRQ fires or timeout
+ const uint32_t startTX_MS = hwMillis();
+ // todo: make this payload length + bit rate dependend
+ while (!RFM95_irq && (hwMillis() - startTX_MS < MY_RFM95_TX_TIMEOUT_MS) ) {
+ doYield();
+ }
+ return RFM95_irq;
}
-LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
+LOCAL bool RFM95_send(const uint8_t recipient, uint8_t *data, const uint8_t len,
const rfm95_controlFlags_t flags, const bool increaseSequenceCounter)
{
rfm95_packet_t packet;
@@ -328,16 +362,16 @@ LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
packet.header.recipient = recipient;
packet.payloadLen = min(len, (uint8_t)RFM95_MAX_PAYLOAD_LEN);
packet.header.controlFlags = flags;
- (void)memcpy(&packet.payload, data, packet.payloadLen);
- return RFM95_sendFrame(packet, increaseSequenceCounter);
+ (void)memcpy((void *)&packet.payload, (void *)data, packet.payloadLen);
+ return RFM95_sendFrame(&packet, increaseSequenceCounter);
}
LOCAL void RFM95_setFrequency(const uint32_t frequencyHz)
{
const uint32_t freqReg = (uint32_t)(frequencyHz / RFM95_FSTEP);
- RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freqReg >> 16) & 0xff);
- RFM95_writeReg(RFM95_REG_07_FRF_MID, (freqReg >> 8) & 0xff);
- RFM95_writeReg(RFM95_REG_08_FRF_LSB, freqReg & 0xff);
+ (void)RFM95_writeReg(RFM95_REG_06_FRF_MSB, (uint8_t)((freqReg >> 16) & 0xff));
+ (void)RFM95_writeReg(RFM95_REG_07_FRF_MID, (uint8_t)((freqReg >> 8) & 0xff));
+ (void)RFM95_writeReg(RFM95_REG_08_FRF_LSB, (uint8_t)(freqReg & 0xff));
}
LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel)
@@ -352,13 +386,13 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel)
// enable DAC, adds 3dBm
// The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm,
// but OutputPower claims it would be 17dBm. Measurements show 20dBm is correct
- RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE);
+ (void)RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE);
val = newPowerLevel - 8;
} else {
- RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE);
+ (void)RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE);
val = newPowerLevel - 5;
}
- RFM95_writeReg(RFM95_REG_09_PA_CONFIG, RFM95_PA_SELECT | val);
+ (void)RFM95_writeReg(RFM95_REG_09_PA_CONFIG, RFM95_PA_SELECT | val);
RFM95_DEBUG(PSTR("RFM95:PTX:LEVEL=%" PRIi8 "\n"), newPowerLevel);
return true;
}
@@ -366,28 +400,26 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel)
}
-#if defined(MY_RFM95_TCXO)
LOCAL void RFM95_enableTCXO(void)
{
while ((RFM95_readReg(RFM95_REG_4B_TCXO) & RFM95_TCXO_TCXO_INPUT_ON) != RFM95_TCXO_TCXO_INPUT_ON) {
- RFM95_sleep();
- RFM95_writeReg(RFM95_REG_4B_TCXO, (RFM95_readReg(RFM95_REG_4B_TCXO) | RFM95_TCXO_TCXO_INPUT_ON));
+ (void)RFM95_writeReg(RFM95_REG_4B_TCXO,
+ (RFM95_readReg(RFM95_REG_4B_TCXO) | RFM95_TCXO_TCXO_INPUT_ON));
}
}
-#endif
// Sets registers from a canned modem configuration structure
-LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t* config)
+LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t *config)
{
- RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config->reg_1d);
- RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config->reg_1e);
- RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config->reg_26);
+ (void)RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config->reg_1d);
+ (void)RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config->reg_1e);
+ (void)RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config->reg_26);
}
LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength)
{
- RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, preambleLength >> 8);
- RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff);
+ (void)RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xff));
+ (void)RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xff));
}
LOCAL void RFM95_setAddress(const uint8_t addr)
@@ -413,19 +445,21 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode)
regMode = RFM95_MODE_SLEEP;
} else if (newRadioMode == RFM95_RADIO_MODE_CAD) {
regMode = RFM95_MODE_CAD;
- RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0
+ (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0
} else if (newRadioMode == RFM95_RADIO_MODE_RX) {
RFM95.dataReceived = false;
RFM95.ackReceived = false;
regMode = RFM95_MODE_RXCONTINUOUS;
- RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0
+ (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0
+ (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR,
+ RFM95_RX_FIFO_ADDR); // set FIFO ptr to beginning of RX FIFO address
} else if (newRadioMode == RFM95_RADIO_MODE_TX) {
regMode = RFM95_MODE_TX;
- RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0
+ (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0
} else {
return false;
}
- RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode);
+ (void)RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode);
RFM95.radioMode = newRadioMode;
return true;
@@ -434,6 +468,7 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode)
LOCAL void RFM95_powerUp(void)
{
#if defined(MY_RFM95_POWER_PIN)
+ RFM95_DEBUG(PSTR("RFM95:PWU\n")); // power up radio
hwDigitalWrite(MY_RFM95_POWER_PIN, HIGH);
delay(RFM95_POWERUP_DELAY_MS);
#endif
@@ -441,6 +476,7 @@ LOCAL void RFM95_powerUp(void)
LOCAL void RFM95_powerDown(void)
{
#if defined(MY_RFM95_POWER_PIN)
+ RFM95_DEBUG(PSTR("RFM95:PWD\n")); // power down radio
hwDigitalWrite(MY_RFM95_POWER_PIN, LOW);
#endif
}
@@ -469,52 +505,53 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s
ACK.sequenceNumber = sequenceNumber;
ACK.RSSI = RSSI;
ACK.SNR = SNR;
- rfm95_controlFlags_t flags = 0x00;
+ rfm95_controlFlags_t flags = 0u;
RFM95_setACKReceived(flags, true);
RFM95_setACKRSSIReport(flags, true);
- (void)RFM95_send(recipient, (uint8_t*)&ACK, sizeof(rfm95_ack_t), flags);
+ (void)RFM95_send(recipient, (uint8_t *)&ACK, sizeof(rfm95_ack_t), flags);
}
LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI)
{
rfm95_powerLevel_t newPowerLevel = RFM95.powerLevel;
- if (RFM95_internalToRSSI(currentRSSI) < RFM95_internalToRSSI(targetRSSI *
- (1 + RFM95_ATC_TARGET_RANGE_PERCENT / 100)) &&
- RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) {
+ const int16_t ownRSSI = RFM95_internalToRSSI(currentRSSI);
+ const int16_t uRange = RFM95_internalToRSSI(targetRSSI) + RFM95_ATC_TARGET_RANGE_DBM;
+ const int16_t lRange = RFM95_internalToRSSI(targetRSSI) - RFM95_ATC_TARGET_RANGE_DBM;
+ if (ownRSSI < lRange && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) {
// increase transmitter power
newPowerLevel++;
- } else if (RFM95_internalToRSSI(currentRSSI) > RFM95_internalToRSSI(targetRSSI *
- (1 - RFM95_ATC_TARGET_RANGE_PERCENT / 100)) &&
- RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) {
+ } else if (ownRSSI > uRange && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) {
// decrease transmitter power
newPowerLevel--;
} else {
// nothing to adjust
return false;
}
- RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 ",TXL=%" PRIi8 "\n"),
- RFM95_internalToRSSI(currentRSSI),
- RFM95_internalToRSSI(targetRSSI), RFM95.powerLevel);
+ RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 "..%" PRIi16 ",TXL=%" PRIi8 "\n"),
+ ownRSSI, lRange, uRange, RFM95.powerLevel);
return RFM95_setTxPowerLevel(newPowerLevel);
}
-LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
+LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void *buffer,
const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime)
{
for (uint8_t retry = 0; retry <= retries; retry++) {
RFM95_DEBUG(PSTR("RFM95:SWR:SEND,TO=%" PRIu8 ",SEQ=%" PRIu16 ",RETRY=%" PRIu8 "\n"), recipient,
RFM95.txSequenceNumber,
retry);
- rfm95_controlFlags_t flags = 0x00;
+ rfm95_controlFlags_t flags = 0u;
RFM95_setACKRequested(flags, (recipient != RFM95_BROADCAST_ADDRESS));
- (void)RFM95_send(recipient, (uint8_t*)buffer, bufferSize, flags, !retry);
- (void)RFM95_waitPacketSent();
+ // send packet
+ if (!RFM95_send(recipient, (uint8_t *)buffer, bufferSize, flags, !retry)) {
+ return false;
+ }
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX);
if (recipient == RFM95_BROADCAST_ADDRESS) {
return true;
}
const uint32_t enterMS = hwMillis();
- while (hwMillis() - enterMS < retryWaitTime) {
+ while (hwMillis() - enterMS < retryWaitTime && !RFM95.dataReceived) {
+ RFM95_handler();
if (RFM95.ackReceived) {
const uint8_t sender = RFM95.currentPacket.header.sender;
const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber;
@@ -533,7 +570,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
// ATC
if (RFM95.ATCenabled && RFM95_getACKRSSIReport(flag)) {
(void)RFM95_executeATC(RSSI, RFM95.ATCtargetRSSI);
- } // ATC
+ }
return true;
} // seq check
}
@@ -541,7 +578,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
}
RFM95_DEBUG(PSTR("!RFM95:SWR:NACK\n"));
const uint32_t enterCSMAMS = hwMillis();
- const uint16_t randDelayCSMA = enterMS & 100;
+ const uint16_t randDelayCSMA = enterMS % 100;
while (hwMillis() - enterCSMAMS < randDelayCSMA) {
doYield();
}
@@ -556,24 +593,15 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
// Wait until no channel activity detected or timeout
LOCAL bool RFM95_waitCAD(void)
{
+ // receiver needs to be in STDBY before entering CAD mode
+ (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD);
const uint32_t enterMS = hwMillis();
- while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) {
- if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) {
- return false;
- }
+ while (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (hwMillis() - enterMS < RFM95_CAD_TIMEOUT_MS) ) {
doYield();
+ RFM95_handler();
}
- return !RFM95.cad;
-}
-
-// Wait for any previous transmission to finish
-LOCAL bool RFM95_waitPacketSent(void)
-{
- while (RFM95.radioMode == RFM95_RADIO_MODE_TX) {
- doYield();
- }
- return true;
+ return !RFM95.channelActive;
}
LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI)
@@ -588,7 +616,6 @@ LOCAL bool RFM95_sanityCheck(void)
result &= RFM95_readReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR) == RFM95_RX_FIFO_ADDR;
result &= RFM95_readReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR) == RFM95_TX_FIFO_ADDR;
result &= RFM95_readReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH) == RFM95_MAX_PACKET_LEN;
-
return result;
}
diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h
index f7d5d34cf..4db4a5a57 100644
--- a/drivers/RFM95/RFM95.h
+++ b/drivers/RFM95/RFM95.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -18,7 +18,8 @@
*
* Based on Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley
* Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html
- * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017 Olivier Mauti
+ *
+ * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017-2018 Olivier Mauti
*
* Changelog:
* - ACK with sequenceNumber
@@ -26,7 +27,6 @@
*
* Definitions for HopeRF LoRa radios:
* http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
- * http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
*
*/
@@ -40,19 +40,22 @@
* RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
* - [!] Exclamation mark is prepended in case of error
*
-* |E| SYS | SUB | Message | Comment
-* |-|-------|------|------------------------------------|-----------------------------------------------------------------------------------
-* | | RFM95 | INIT | | Initialise RFM95 radio
-* | | RFM95 | INIT | PIN,CS=%d,IQP=%d,IQN=%d[,RST=%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST)
-* |!| RFM95 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
-* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back
-* | | RFM95 | PTC | LEVEL=%d | Set TX power level
-* | | RFM95 | SAC | SEND ACK,TO=%d,RSSI=%d,SNR=%d | Send ACK to node (TO), RSSI of received message (RSSI), SNR of message (SNR)
-* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL)
-* | | RFM95 | SWR | SEND,TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY)
-* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR)
-* |!| RFM95 | SWR | NACK | No ACK received
-* | | RFM95 | SPP | PCT=%d,TX LEVEL=%d | Set TX level percent (PCT), TX level (LEVEL)
+* |E| SYS | SUB | Message | Comment
+* |-|-------|------|----------------------------------------|-----------------------------------------------------------------------------------
+* | | RFM95 | INIT | | Initialise RFM95 radio
+* | | RFM95 | INIT | PIN,CS=%%d,IQP=%%d,IQN=%%d[,RST=%%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST)
+* |!| RFM95 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module
+* |!| RFM95 | IRH | CRC FAIL | Incoming packet has CRC error, skip
+* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back
+* | | RFM95 | PTC | LEVEL=%%d | Set TX power level
+* | | RFM95 | SAC | SEND ACK,TO=%%d,RSSI=%%d,SNR=%%d | Send ACK to node (TO), RSSI of received message (RSSI), SNR of message (SNR)
+* | | RFM95 | ATC | ADJ TXL,cR=%%d,tR=%%d..%%d,TXL=%%d | Adjust TX level, current RSSI (cR), target RSSI range (tR), TX level (TXL)
+* | | RFM95 | SWR | SEND,TO=%%d,RETRY=%%d | Send message to (TO), NACK retry counter (RETRY)
+* | | RFM95 | SWR | ACK FROM=%%d,SEQ=%%d,RSSI=%%d,SNR=%%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR)
+* |!| RFM95 | SWR | NACK | No ACK received
+* | | RFM95 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level percent (PCT), TX level (LEVEL)
+* | | RFM95 | PWD | | Power down radio
+* | | RFM95 | PWU | | Power up radio
*
* RFM95 modem configuration
*
@@ -60,12 +63,12 @@
* CR = Error correction code
* SF = Spreading factor, chips / symbol
*
-* | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment | air-time (15 bytes)
-* |------------------|--------|--------|--------|-------|-----|------|-----------------------|------------------------
-* | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range | 50ms
-* | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range | 15ms
-* | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range | 900ms
-* | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range | 1500ms
+* | CONFIG | BW | CR | SF | Comment | air-time (15 bytes)
+* |------------------|-------|-----|------|-----------------------|------------------------
+* | BW125CR45SF128 | 125 | 4/5 | 128 | Default, medium range | 50ms
+* | BW500CR45SF128 | 500 | 4/5 | 128 | Fast, short range | 15ms
+* | BW31_25CR48SF512 | 31.25 | 4/8 | 512 | Slow, long range | 900ms
+* | BW125CR48SF4096 | 125 | 4/8 | 4096 | Slow, long range | 1500ms
*
* See here for air-time calculation: https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc
*
@@ -81,44 +84,37 @@
// default PIN assignments, can be overridden
#if defined(ARDUINO_ARCH_AVR)
#if defined(__AVR_ATmega32U4__)
-#define DEFAULT_RFM95_IRQ_PIN (3) //!< DEFAULT_RFM95_IRQ_PIN
+#define DEFAULT_RFM95_IRQ_PIN (3) //!< DEFAULT_RFM95_IRQ_PIN
#else
-#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
+#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
#endif
-#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM
#elif defined(ARDUINO_ARCH_ESP8266)
-#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
-#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM
+#define DEFAULT_RFM95_IRQ_PIN (5) //!< DEFAULT_RFM95_IRQ_PIN
#elif defined(ARDUINO_ARCH_ESP32)
-#warning not implemented yet
-#elif defined(ARDUINO_ARCH_SAMD)
-#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
+#define DEFAULT_RFM95_IRQ_PIN (16) //!< DEFAULT_RFM95_IRQ_PIN
#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM
+#elif defined(ARDUINO_ARCH_SAMD)
+#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
#elif defined(LINUX_ARCH_RASPBERRYPI)
-#define DEFAULT_RFM95_IRQ_PIN (22) //!< DEFAULT_RFM95_IRQ_PIN
-#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM
+#define DEFAULT_RFM95_IRQ_PIN (22) //!< DEFAULT_RFM95_IRQ_PIN
#elif defined(ARDUINO_ARCH_STM32F1)
-#define DEFAULT_RFM95_IRQ_PIN (PA3) //!< DEFAULT_RFM95_IRQ_PIN
-#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM
+#define DEFAULT_RFM95_IRQ_PIN (PA3) //!< DEFAULT_RFM95_IRQ_PIN
#elif defined(TEENSYDUINO)
-#define DEFAULT_RFM95_IRQ_PIN (8) //!< DEFAULT_RFM95_IRQ_PIN
-#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM
+#define DEFAULT_RFM95_IRQ_PIN (8) //!< DEFAULT_RFM95_IRQ_PIN
#else
-#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
-#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM
+#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN
#endif
-#define DEFAULT_RFM95_CS_PIN (SS) //!< DEFAULT_RFM95_CS_PIN
+#define DEFAULT_RFM95_CS_PIN (SS) //!< DEFAULT_RFM95_CS_PIN
// SPI settings
-#define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order
-#define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode
+#define RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order
+#define RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode
#if defined (ARDUINO) && !defined (__arm__) && !defined (RFM95_SPI)
#include
#if defined(MY_SOFTSPI)
-SoftSPI
-RFM95_SPI;
+SoftSPIRFM95_SPI;
#else
#define RFM95_SPI SPI //!< SPI
#endif
@@ -149,36 +145,40 @@ extern HardwareSPI SPI; //!< SPI
#define RFM95_RETRY_TIMEOUT_MS (500ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different)
#endif
+#if !defined(MY_RFM95_TX_TIMEOUT_MS)
+#define MY_RFM95_TX_TIMEOUT_MS (5*1000ul) //!< TX timeout
+#endif
+
// Frequency definitions
-#define RFM95_169MHZ (169000000ul) //!< 169 Mhz
-#define RFM95_315MHZ (315000000ul) //!< 315 Mhz
-#define RFM95_434MHZ (433920000ul) //!< 433.92 Mhz
-#define RFM95_868MHZ (868100000ul) //!< 868.1 Mhz
-#define RFM95_915MHZ (915000000ul) //!< 915 Mhz
-
-#define RFM95_RETRIES (5u) //!< Retries in case of failed transmission
-#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold
-#define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer
-#define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer
-#define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA
-#define RFM95_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8
-#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout
-#define RFM95_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational
-
-#define RFM95_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version
-#define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version
-#define RFM95_BIT_ACK_REQUESTED (7u) //!< RFM95 header, controlFlag, bit 7
-#define RFM95_BIT_ACK_RECEIVED (6u) //!< RFM95 header, controlFlag, bit 6
-#define RFM95_BIT_ACK_RSSI_REPORT (5u) //!< RFM95 header, controlFlag, bit 5
-
-#define RFM95_BROADCAST_ADDRESS (255u) //!< Broadcasting address
-#define RFM95_ATC_TARGET_RANGE_PERCENT (5u) //!< ATC target range +/-%
-#define RFM95_RSSI_OFFSET (137u) //!< RSSI offset
-#define RFM95_TARGET_RSSI (-60) //!< RSSI target
-#define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode
-
-#define RFM95_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module
-#define RFM95_FSTEP (RFM95_FXOSC / 524288.0f) //!< The Frequency Synthesizer step = RFM95_FXOSC /
+#define RFM95_169MHZ (169000000ul) //!< 169 Mhz
+#define RFM95_315MHZ (315000000ul) //!< 315 Mhz
+#define RFM95_434MHZ (433920000ul) //!< 433.92 Mhz
+#define RFM95_868MHZ (868100000ul) //!< 868.1 Mhz
+#define RFM95_915MHZ (915000000ul) //!< 915 Mhz
+
+#define RFM95_RETRIES (5u) //!< Retries in case of failed transmission
+#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold
+#define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer
+#define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer
+#define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA
+#define RFM95_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8
+#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout
+#define RFM95_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational
+
+#define RFM95_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version
+#define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version
+#define RFM95_BIT_ACK_REQUESTED (7u) //!< RFM95 header, controlFlag, bit 7
+#define RFM95_BIT_ACK_RECEIVED (6u) //!< RFM95 header, controlFlag, bit 6
+#define RFM95_BIT_ACK_RSSI_REPORT (5u) //!< RFM95 header, controlFlag, bit 5
+
+#define RFM95_BROADCAST_ADDRESS (255u) //!< Broadcasting address
+#define RFM95_ATC_TARGET_RANGE_DBM (2u) //!< ATC target range +/- dBm
+#define RFM95_RSSI_OFFSET (137u) //!< RSSI offset
+#define RFM95_TARGET_RSSI (-70) //!< RSSI target
+#define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode
+
+#define RFM95_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module
+#define RFM95_FSTEP (RFM95_FXOSC / 524288.0f) //!< The Frequency Synthesizer step
// helper macros
#define RFM95_getACKRequested(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_REQUESTED)) //!< getACKRequested
@@ -187,8 +187,6 @@ extern HardwareSPI SPI; //!< SPI
#define RFM95_setACKReceived(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RECEIVED,__flag) //!< setACKReceived
#define RFM95_setACKRSSIReport(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport
#define RFM95_getACKRSSIReport(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RSSI_REPORT)) //!< getACKRSSIReport
-#define RFM95_internalToRSSI(__value) ((int16_t)(__value - RFM95_RSSI_OFFSET)) //!< Convert internal RSSI to RSSI
-#define RFM95_RSSItoInternal(__value) ((uint8_t)(__value + RFM95_RSSI_OFFSET)) //!< Convert RSSI to internal RSSI
#define RFM95_internalToSNR(__value) ((int8_t)(__value / 4)) //!< Convert internal SNR to SNR
#define RFM95_MIN_POWER_LEVEL_DBM ((rfm95_powerLevel_t)5u) //!< min. power level
@@ -220,7 +218,7 @@ typedef struct {
/**
* @brief Sequence number data type
*/
-typedef uint16_t rfm95_sequenceNumber_t;
+typedef uint16_t rfm95_sequenceNumber_t; // will eventually change to uint8_t in 3.0
/**
* @brief RSSI data type
*/
@@ -285,18 +283,18 @@ typedef struct {
* @brief RFM95 internal variables
*/
typedef struct {
- uint8_t address; //!< Node address
- rfm95_packet_t currentPacket; //!< Buffer for current packet
- rfm95_sequenceNumber_t txSequenceNumber; //!< RFM95_txSequenceNumber
- rfm95_powerLevel_t powerLevel; //!< TX power level dBm
- rfm95_RSSI_t ATCtargetRSSI; //!< ATC: target RSSI
+ uint8_t address; //!< Node address
+ rfm95_packet_t currentPacket; //!< Buffer for current packet
+ rfm95_sequenceNumber_t txSequenceNumber; //!< RFM95_txSequenceNumber
+ rfm95_powerLevel_t powerLevel; //!< TX power level dBm
+ rfm95_RSSI_t ATCtargetRSSI; //!< ATC: target RSSI
// 8 bit
- rfm95_radioMode_t radioMode : 3; //!< current transceiver state
- bool cad : 1; //!< RFM95_cad
- bool ATCenabled : 1; //!< ATC enabled
- bool ackReceived : 1; //!< ACK received
- bool dataReceived : 1; //!< AData received
- uint8_t reserved : 1; //!< reserved
+ rfm95_radioMode_t radioMode : 3; //!< current transceiver state
+ bool channelActive : 1; //!< RFM95_cad
+ bool ATCenabled : 1; //!< ATC enabled
+ bool ackReceived : 1; //!< ACK received
+ bool dataReceived : 1; //!< Data received
+ bool reserved : 1; //!< unused
} rfm95_internal_t;
#define LOCAL static //!< static
@@ -318,14 +316,14 @@ LOCAL void RFM95_setAddress(const uint8_t addr);
*/
LOCAL uint8_t RFM95_getAddress(void);
/**
-* @brief Sets all the registered required to configure the data modem in the RF95/96/97/98, including the
+* @brief Sets all the registers required to configure the data modem in the RF95/96/97/98, including the
* bandwidth, spreading factor etc.
* @param config See modemConfig_t and references therein
*/
-LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t* config);
+LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t *config);
/**
* @brief Tests whether a new message is available
-* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_recv()
+* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_receive()
*/
LOCAL bool RFM95_available(void);
/**
@@ -334,7 +332,7 @@ LOCAL bool RFM95_available(void);
* @param maxBufSize Max buffer size
* @return Number of bytes
*/
-LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize);
+LOCAL uint8_t RFM95_receive(uint8_t *buf, const uint8_t maxBufSize);
/**
* @brief RFM95_send
* @param recipient
@@ -344,7 +342,7 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize);
* @param increaseSequenceCounter
* @return True if packet sent
*/
-LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
+LOCAL bool RFM95_send(const uint8_t recipient, uint8_t *data, const uint8_t len,
const rfm95_controlFlags_t flags, const bool increaseSequenceCounter = true);
/**
* @brief RFM95_sendFrame
@@ -352,7 +350,7 @@ LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len,
* @param increaseSequenceCounter
* @return True if frame sent
*/
-LOCAL bool RFM95_sendFrame(rfm95_packet_t &packet, const bool increaseSequenceCounter = true);
+LOCAL bool RFM95_sendFrame(rfm95_packet_t *packet, const bool increaseSequenceCounter = true);
/**
* @brief RFM95_setPreambleLength
* @param preambleLength
@@ -377,17 +375,15 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel);
*/
LOCAL bool RFM95_setTxPowerPercent(const uint8_t newPowerPercent);
-#if defined(MY_RFM95_TCXO)
/**
* @brief Enable TCXO mode
* Call this immediately after init(), to force your radio to use an external
* frequency source, such as a Temperature Compensated Crystal Oscillator (TCXO).
* See the comments in the main documentation about the sensitivity of this radio to
* clock frequency especially when using narrow bandwidths.
-* Leaves the module in sleep mode.
+* @note Has to be called while radio is in sleep mode.
*/
LOCAL void RFM95_enableTCXO(void);
-#endif
/**
* @brief Sets the radio into low-power sleep mode
@@ -425,7 +421,7 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s
* @param retryWaitTime
* @return True if packet successfully sent
*/
-LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
+LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void *buffer,
const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES,
const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS);
/**
@@ -433,11 +429,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
* @return True if no channel activity detected, False if timeout occured
*/
LOCAL bool RFM95_waitCAD(void);
-/**
-* @brief RFM95_waitPacketSent
-* @return True if packet sent
-*/
-LOCAL bool RFM95_waitPacketSent(void);
+
/**
* @brief RFM95_setRadioMode
* @param newRadioMode
@@ -448,6 +440,16 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode);
* @brief Low level interrupt handler
*/
LOCAL void RFM95_interruptHandler(void);
+
+/**
+* @brief Packet engine
+*/
+LOCAL void RFM95_interruptHandling(void);
+
+/**
+* @brief RFM95_handler
+*/
+LOCAL void RFM95_handler(void);
/**
* @brief RFM95_getSendingRSSI
* @return RSSI Signal strength of last packet received
diff --git a/drivers/RFM95/RFM95registers.h b/drivers/RFM95/RFM95registers.h
index c7dd6301e..33d256285 100644
--- a/drivers/RFM95/RFM95registers.h
+++ b/drivers/RFM95/RFM95registers.h
@@ -1,34 +1,30 @@
/*
-* The MySensors Arduino library handles the wireless radio link and protocol
-* between your home built sensors/actuators and HA controller of choice.
-* The sensors forms a self healing radio network with optional repeaters. Each
-* repeater and gateway builds a routing tables in EEPROM which keeps track of the
-* network topology allowing messages to be routed to nodes.
-*
-* Created by Henrik Ekblad
-* Copyright (C) 2013-2016 Sensnology AB
-* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
-*
-* Documentation: http://www.mysensors.org
-* Support Forum: http://forum.mysensors.org
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* version 2 as published by the Free Software Foundation.
-*
-* Based on Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley
-* Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html
-* RFM95 driver refactored and optimized for MySensors, Copyright (C) 2016 Olivier Mauti
-*
-* Changelog:
-* - ACK with sequenceNumber
-* - ATC control
-*
-* Definitions for HopeRF LoRa radios:
-* http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
-* http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
-*
-*/
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Based on Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley
+ * Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html
+ *
+ * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017-2018 Olivier Mauti
+ *
+ * Definitions for HopeRF LoRa radios:
+ * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
+ *
+ */
// Register access
#define RFM95_READ_REGISTER (0x7Fu) //!< reading register
@@ -152,6 +148,7 @@
#define RFM95_PAYLOAD_CRC_ERROR 0x20 //!< PAYLOAD_CRC_ERROR
#define RFM95_RX_DONE 0x40 //!< RX_DONE
#define RFM95_RX_TIMEOUT 0x80 //!< RX_TIMEOUT
+#define RFM95_CLEAR_IRQ 0xFF //
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/drivers/TinyGSM/TinyGsmClient.h b/drivers/TinyGSM/TinyGsmClient.h
new file mode 100644
index 000000000..8badab174
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClient.h
@@ -0,0 +1,67 @@
+/**
+ * file TinyGsmClient.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClient_h
+#define TinyGsmClient_h
+
+#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_U201) || defined(TINY_GSM_MODEM_ESP8266)
+#define TINY_GSM_MODEM_HAS_SSL
+#endif
+
+#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7)
+#define TINY_GSM_MODEM_HAS_GPS
+#endif
+
+#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM900)
+#define TINY_GSM_MODEM_HAS_GPRS
+#include "TinyGsmClientSIM800.h"
+typedef TinyGsmSim800 TinyGsm;
+typedef TinyGsmSim800::GsmClient TinyGsmClient;
+typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure;
+
+#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
+#define TINY_GSM_MODEM_HAS_GPRS
+#include "TinyGsmClientSIM808.h"
+typedef TinyGsmSim808 TinyGsm;
+typedef TinyGsmSim808::GsmClient TinyGsmClient;
+typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure;
+
+#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
+#define TINY_GSM_MODEM_HAS_GPRS
+#include "TinyGsmClientA6.h"
+typedef TinyGsm::GsmClient TinyGsmClient;
+
+#elif defined(TINY_GSM_MODEM_M590)
+#define TINY_GSM_MODEM_HAS_GPRS
+#include "TinyGsmClientM590.h"
+typedef TinyGsm::GsmClient TinyGsmClient;
+
+#elif defined(TINY_GSM_MODEM_U201)
+#define TINY_GSM_MODEM_HAS_GPRS
+#include "TinyGsmClientU201.h"
+typedef TinyGsmU201 TinyGsm;
+typedef TinyGsmU201::GsmClient TinyGsmClient;
+typedef TinyGsmU201::GsmClientSecure TinyGsmClientSecure;
+
+#elif defined(TINY_GSM_MODEM_ESP8266)
+#define TINY_GSM_MODEM_HAS_WIFI
+#include "TinyGsmClientESP8266.h"
+typedef TinyGsm::GsmClient TinyGsmClient;
+typedef TinyGsm::GsmClientSecure TinyGsmClientSecure;
+
+#elif defined(TINY_GSM_MODEM_XBEE)
+#define TINY_GSM_MODEM_HAS_GPRS
+#define TINY_GSM_MODEM_HAS_WIFI
+#include "TinyGsmClientXBee.h"
+typedef TinyGsm::GsmClient TinyGsmClient;
+
+#else
+#error "Please define GSM modem model"
+#endif
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientA6.h b/drivers/TinyGSM/TinyGsmClientA6.h
new file mode 100644
index 000000000..7630378d9
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientA6.h
@@ -0,0 +1,843 @@
+/**
+ * file TinyGsmClientA6.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientA6_h
+#define TinyGsmClientA6_h
+
+//#define TINY_GSM_DEBUG Serial
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 256
+#endif
+
+#define TINY_GSM_MUX_COUNT 8
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r\n"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+
+enum SimStatus {
+ SIM_ERROR = 0,
+ SIM_READY = 1,
+ SIM_LOCKED = 2,
+};
+
+enum RegStatus {
+ REG_UNREGISTERED = 0,
+ REG_SEARCHING = 2,
+ REG_DENIED = 3,
+ REG_OK_HOME = 1,
+ REG_OK_ROAMING = 5,
+ REG_UNKNOWN = 4,
+};
+
+
+class TinyGsm
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsm;
+ typedef TinyGsmFifo RxFifo;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsm& modem)
+ {
+ init(&modem);
+ }
+
+ bool init(TinyGsm* modem)
+ {
+ this->at = modem;
+ this->mux = -1;
+ sock_connected = false;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ uint8_t newMux = -1;
+ sock_connected = at->modemConnect(host, port, &newMux);
+ if (sock_connected) {
+ mux = newMux;
+ at->sockets[mux] = this;
+ }
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ return connect(host.c_str(), port);
+ }
+
+ virtual void stop()
+ {
+ TINY_GSM_YIELD();
+ at->sendAT(GF("+CIPCLOSE="), mux);
+ sock_connected = false;
+ at->waitResponse();
+ rx.clear();
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ //at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ }
+ return rx.size();
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ size_t cnt = 0;
+ while (cnt < size) {
+ size_t chunk = TinyGsmMin(size-cnt, rx.size());
+ if (chunk > 0) {
+ rx.get(buf, chunk);
+ buf += chunk;
+ cnt += chunk;
+ continue;
+ }
+ // TODO: Read directly into user buffer?
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ //break;
+ }
+ }
+ return cnt;
+ }
+
+ virtual int read()
+ {
+ uint8_t c;
+ if (read(&c, 1) == 1) {
+ return c;
+ }
+ return -1;
+ }
+
+ virtual int peek()
+ {
+ return -1; //TODO
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsm* at;
+ uint8_t mux;
+ bool sock_connected;
+ RxFifo rx;
+ };
+
+public:
+
+ explicit TinyGsm(Stream& stream)
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin()
+ {
+ return init();
+ }
+
+ bool init()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
+ if (waitResponse() != 1) {
+ return false;
+ }
+ sendAT(GF("+CMEE=0"));
+ waitResponse();
+
+ sendAT(GF("+CMER=3,0,0,2"));
+ waitResponse();
+
+ getSimStatus();
+ return true;
+ }
+
+ void setBaud(unsigned long baud)
+ {
+ sendAT(GF("+IPR="), baud);
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF(""));
+ if (waitResponse(200) == 1) {
+ delay(100);
+ return true;
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain()
+ {
+ waitResponse(10, NULL, NULL);
+ }
+
+ bool factoryDefault()
+ {
+ sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
+ waitResponse();
+ sendAT(GF("&W")); // Write configuration
+ return waitResponse() == 1;
+ }
+
+ String getModemInfo()
+ {
+ sendAT(GF("I"));
+ String res;
+ if (waitResponse(1000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, " ");
+ res.trim();
+ return res;
+ }
+
+ bool hasSSL()
+ {
+ return false;
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("+RST=1"));
+ delay(3000);
+ return init();
+ }
+
+ bool poweroff()
+ {
+ sendAT(GF("+CPOF"));
+ return waitResponse() == 1;
+ }
+
+ bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ /*
+ * SIM card functions
+ */
+
+ bool simUnlock(const char *pin)
+ {
+ sendAT(GF("+CPIN=\""), pin, GF("\""));
+ return waitResponse() == 1;
+ }
+
+ String getSimCCID()
+ {
+ sendAT(GF("+CCID"));
+ if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ String getIMEI()
+ {
+ sendAT(GF("+GSN"));
+ if (waitResponse(GF(GSM_NL)) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ SimStatus getSimStatus(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF("+CPIN?"));
+ if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
+ delay(1000);
+ continue;
+ }
+ int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
+ waitResponse();
+ switch (status) {
+ case 2:
+ case 3:
+ return SIM_LOCKED;
+ case 1:
+ return SIM_READY;
+ default:
+ return SIM_ERROR;
+ }
+ }
+ return SIM_ERROR;
+ }
+
+ RegStatus getRegistrationStatus()
+ {
+ sendAT(GF("+CREG?"));
+ if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
+ return REG_UNKNOWN;
+ }
+ streamSkipUntil(','); // Skip format (0)
+ int status = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return (RegStatus)status;
+ }
+
+ String getOperator()
+ {
+ sendAT(GF("+COPS=3,0")); // Set format
+ waitResponse();
+
+ sendAT(GF("+COPS?"));
+ if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
+ return "";
+ }
+ streamSkipUntil('"'); // Skip mode and format
+ String res = stream.readStringUntil('"');
+ waitResponse();
+ return res;
+ }
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ sendAT(GF("+CSQ"));
+ if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
+ return 99;
+ }
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ bool isNetworkConnected()
+ {
+ RegStatus s = getRegistrationStatus();
+ return (s == REG_OK_HOME || s == REG_OK_ROAMING);
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isNetworkConnected()) {
+ return true;
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * GPRS functions
+ */
+ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
+ {
+ gprsDisconnect();
+
+ sendAT(GF("+CGATT=1"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ // TODO: wait AT+CGATT?
+
+ sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
+ waitResponse();
+
+ if (!user) {
+ user = "";
+ }
+ if (!pwd) {
+ pwd = "";
+ }
+ sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CGACT=1,1"));
+ waitResponse(60000L);
+
+ sendAT(GF("+CIPMUX=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool gprsDisconnect()
+ {
+ // Shut the TCP/IP connection
+ sendAT(GF("+CIPSHUT"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ for (int i = 0; i<3; i++) {
+ sendAT(GF("+CGATT=0"));
+ if (waitResponse(5000L) == 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool isGprsConnected()
+ {
+ sendAT(GF("+CGATT?"));
+ if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
+ return false;
+ }
+ int res = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return (res == 1);
+ }
+
+ String getLocalIP()
+ {
+ sendAT(GF("+CIFSR"));
+ String res;
+ if (waitResponse(10000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, "");
+ res.trim();
+ return res;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+ /*
+ * Phone Call functions
+ */
+
+ bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ bool callAnswer()
+ {
+ sendAT(GF("A"));
+ return waitResponse() == 1;
+ }
+
+ // Returns true on pick-up, false on error/busy
+ bool callNumber(const String& number)
+ {
+ if (number == GF("last")) {
+ sendAT(GF("DLST"));
+ } else {
+ sendAT(GF("D\""), number, "\";");
+ }
+
+ if (waitResponse(5000L) != 1) {
+ return false;
+ }
+
+ if (waitResponse(60000L,
+ GF(GSM_NL "+CIEV: \"CALL\",1"),
+ GF(GSM_NL "+CIEV: \"CALL\",0"),
+ GFP(GSM_ERROR)) != 1) {
+ return false;
+ }
+
+ int rsp = waitResponse(60000L,
+ GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
+ GF(GSM_NL "+CIEV: \"CALL\",0"));
+
+ int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL));
+
+ return rsp == 1 && rsp2 == 0;
+ }
+
+ bool callHangup()
+ {
+ sendAT(GF("H"));
+ return waitResponse() == 1;
+ }
+
+ // 0-9,*,#,A,B,C,D
+ bool dtmfSend(char cmd, unsigned duration_ms = 100)
+ {
+ duration_ms = constrain(duration_ms, 100, 1000);
+
+ // The duration parameter is not working, so we simulate it using delay..
+ // TODO: Maybe there's another way...
+
+ //sendAT(GF("+VTD="), duration_ms / 100);
+ //waitResponse();
+
+ sendAT(GF("+VTS="), cmd);
+ if (waitResponse(10000L) == 1) {
+ delay(duration_ms);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Audio functions
+ */
+
+ bool audioSetHeadphones()
+ {
+ sendAT(GF("+SNFS=0"));
+ return waitResponse() == 1;
+ }
+
+ bool audioSetSpeaker()
+ {
+ sendAT(GF("+SNFS=1"));
+ return waitResponse() == 1;
+ }
+
+ bool audioMuteMic(bool mute)
+ {
+ sendAT(GF("+CMUT="), mute);
+ return waitResponse() == 1;
+ }
+
+ /*
+ * Messaging functions
+ */
+
+ String sendUSSD(const String& code)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CSCS=\"HEX\""));
+ waitResponse();
+ sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
+ if (waitResponse(10000L) != 1) {
+ return "";
+ }
+ if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
+ return "";
+ }
+ stream.readStringUntil('"');
+ String hex = stream.readStringUntil('"');
+ stream.readStringUntil(',');
+ int dcs = stream.readStringUntil('\n').toInt();
+
+ if (dcs == 15) {
+ return TinyGsmDecodeHex7bit(hex);
+ } else if (dcs == 72) {
+ return TinyGsmDecodeHex16bit(hex);
+ } else {
+ return hex;
+ }
+ }
+
+ bool sendSMS(const String& number, const String& text)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CMGS=\""), number, GF("\""));
+ if (waitResponse(GF(">")) != 1) {
+ return false;
+ }
+ stream.print(text);
+ stream.write((char)0x1A);
+ stream.flush();
+ return waitResponse(60000L) == 1;
+ }
+
+
+ /*
+ * Location functions
+ */
+
+ String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ /*
+ * Battery functions
+ */
+
+ uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ int getBattPercent()
+ {
+ sendAT(GF("+CBC?"));
+ if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
+ return false;
+ }
+ stream.readStringUntil(',');
+ int res = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return res;
+ }
+
+protected:
+
+ bool modemConnect(const char* host, uint16_t port, uint8_t* mux)
+ {
+ sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
+
+ if (waitResponse(75000L, GF(GSM_NL "+CIPNUM:")) != 1) {
+ return false;
+ }
+ int newMux = stream.readStringUntil('\n').toInt();
+
+ int rsp = waitResponse(75000L,
+ GF("CONNECT OK" GSM_NL),
+ GF("CONNECT FAIL" GSM_NL),
+ GF("ALREADY CONNECT" GSM_NL));
+ if (waitResponse() != 1) {
+ return false;
+ }
+ *mux = newMux;
+
+ return (1 == rsp);
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux)
+ {
+ sendAT(GF("+CIPSEND="), mux, ',', len);
+ if (waitResponse(2000L, GF(GSM_NL ">")) != 1) {
+ return 0;
+ }
+ stream.write((uint8_t*)buff, len);
+ stream.flush();
+ if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) {
+ return 0;
+ }
+ return len;
+ }
+
+ bool modemGetConnected(uint8_t mux)
+ {
+ sendAT(GF("+CIPSTATUS")); //TODO mux?
+ int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
+ GF(",\"INITIAL\""));
+ waitResponse();
+ return 1 == res;
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ bool streamSkipUntil(char c) //TODO: timeout
+ {
+ while (true) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ if (stream.read() == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = stream.read();
+ if (a <= 0) {
+ continue; // Skip 0x00 bytes, just in case
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ } else if (data.endsWith(GF("+CIPRCV:"))) {
+ int mux = stream.readStringUntil(',').toInt();
+ int len = stream.readStringUntil(',').toInt();
+ int len_orig = len;
+ if (len > sockets[mux]->rx.free()) {
+ DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
+ } else {
+ DBG("### Got: ", len, "->", sockets[mux]->rx.free());
+ }
+ while (len--) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ sockets[mux]->rx.put(stream.read());
+ }
+ if (len_orig > sockets[mux]->available()) { // TODO
+ DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
+ }
+ data = "";
+ } else if (data.endsWith(GF("+TCPCLOSED:"))) {
+ int mux = stream.readStringUntil('\n').toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
+ sockets[mux]->sock_connected = false;
+ }
+ data = "";
+ DBG("### Closed: ", mux);
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ if (data.length()) {
+ DBG("### Unhandled:", data);
+ }
+ data = "";
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientESP8266.h b/drivers/TinyGSM/TinyGsmClientESP8266.h
new file mode 100644
index 000000000..76d88eafd
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientESP8266.h
@@ -0,0 +1,591 @@
+/**
+ * file TinyGsmClientESP8266.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientESP8266_h
+#define TinyGsmClientESP8266_h
+
+//#define TINY_GSM_DEBUG Serial
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 512
+#endif
+
+#define TINY_GSM_MUX_COUNT 5
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r\n"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
+
+class TinyGsm
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsm;
+ typedef TinyGsmFifo RxFifo;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsm& modem, uint8_t mux = 1)
+ {
+ init(&modem, mux);
+ }
+
+ bool init(TinyGsm* modem, uint8_t mux = 1)
+ {
+ this->at = modem;
+ this->mux = mux;
+ sock_connected = false;
+
+ at->sockets[mux] = this;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, mux);
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ return connect(host.c_str(), port);
+ }
+
+ virtual void stop()
+ {
+ TINY_GSM_YIELD();
+ at->sendAT(GF("+CIPCLOSE="), mux);
+ sock_connected = false;
+ at->waitResponse();
+ rx.clear();
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ //at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ }
+ return rx.size();
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ size_t cnt = 0;
+ while (cnt < size) {
+ size_t chunk = TinyGsmMin(size-cnt, rx.size());
+ if (chunk > 0) {
+ rx.get(buf, chunk);
+ buf += chunk;
+ cnt += chunk;
+ continue;
+ }
+ // TODO: Read directly into user buffer?
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ //break;
+ }
+ }
+ return cnt;
+ }
+
+ virtual int read()
+ {
+ uint8_t c;
+ if (read(&c, 1) == 1) {
+ return c;
+ }
+ return -1;
+ }
+
+ virtual int peek()
+ {
+ return -1; //TODO
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsm* at;
+ uint8_t mux;
+ bool sock_connected;
+ RxFifo rx;
+ };
+
+ class GsmClientSecure : public GsmClient
+ {
+ public:
+ GsmClientSecure() {}
+
+ GsmClientSecure(TinyGsm& modem, uint8_t mux = 1)
+ : GsmClient(modem, mux)
+ {}
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, mux, true);
+ return sock_connected;
+ }
+ };
+
+public:
+
+ explicit TinyGsm(Stream& stream)
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin()
+ {
+ return init();
+ }
+
+ bool init()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("E0")); // Echo Off
+ if (waitResponse() != 1) {
+ return false;
+ }
+ return true;
+ }
+
+ void setBaud(unsigned long baud)
+ {
+ sendAT(GF("+IPR="), baud);
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF(""));
+ if (waitResponse(200) == 1) {
+ delay(100);
+ return true;
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain()
+ {
+ waitResponse(10, NULL, NULL);
+ }
+
+ bool factoryDefault()
+ {
+ sendAT(GF("+RESTORE"));
+ return waitResponse() == 1;
+ }
+
+ String getModemInfo()
+ {
+ sendAT(GF("+GMR"));
+ String res;
+ if (waitResponse(1000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, " ");
+ res.trim();
+ return res;
+ }
+
+ bool hasSSL()
+ {
+ return true;
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("+RST"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
+ return false;
+ }
+ delay(500);
+ return init();
+ }
+
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ sendAT(GF("+CWJAP_CUR?"));
+ int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
+ if (res1 != 2) {
+ waitResponse();
+ return 0;
+ }
+ streamSkipUntil(','); // Skip SSID
+ streamSkipUntil(','); // Skip BSSID/MAC address
+ streamSkipUntil(','); // Skip Chanel number
+ int res2 = stream.parseInt(); // Read RSSI
+ waitResponse(); // Returns an OK after the value
+ return res2;
+ }
+
+ bool isNetworkConnected()
+ {
+ sendAT(GF("+CIPSTATUS"));
+ int res1 = waitResponse(3000, GF("STATUS:"));
+ int res2 = 0;
+ if (res1 == 1) {
+ res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
+ }
+ // status of ESP8266 station interface
+ // 2 : ESP8266 station connected to an AP and has obtained IP
+ // 3 : ESP8266 station created a TCP or UDP transmission
+ // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected)
+ // 5 : ESP8266 station did NOT connect to an AP
+ waitResponse(); // Returns an OK after the status
+ if (res2 == 2 || res2 == 3 || res2 == 4) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF("+CIPSTATUS"));
+ int res1 = waitResponse(3000, GF("busy p..."), GF("STATUS:"));
+ if (res1 == 2) {
+ int res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
+ if (res2 == 2 || res2 == 3 || res2 == 4) {
+ waitResponse();
+ return true;
+ }
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * WiFi functions
+ */
+ bool networkConnect(const char* ssid, const char* pwd)
+ {
+
+ sendAT(GF("+CIPMUX=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CWMODE_CUR=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
+ if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool networkDisconnect()
+ {
+ sendAT(GF("+CWQAP"));
+ bool retVal = waitResponse(10000L) == 1;
+ waitResponse(GF("WIFI DISCONNECT"));
+ return retVal;
+ }
+
+ String getLocalIP()
+ {
+ sendAT(GF("+CIPSTA_CUR??"));
+ int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
+ if (res1 != 2) {
+ return "";
+ }
+ String res2 = stream.readStringUntil('"');
+ waitResponse();
+ return res2;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+protected:
+
+ bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false)
+ {
+ if (ssl) {
+ sendAT(GF("+CIPSSLSIZE=4096"));
+ waitResponse();
+ }
+ sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), GF("\",\""), host, GF("\","),
+ port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
+ // TODO: Check mux
+ int rsp = waitResponse(75000L,
+ GFP(GSM_OK),
+ GFP(GSM_ERROR),
+ GF("ALREADY CONNECT"));
+ // if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
+ return (1 == rsp);
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux)
+ {
+ sendAT(GF("+CIPSEND="), mux, ',', len);
+ if (waitResponse(GF(">")) != 1) {
+ return 0;
+ }
+ stream.write((uint8_t*)buff, len);
+ stream.flush();
+ if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
+ return 0;
+ }
+ return len;
+ }
+
+ bool modemGetConnected(uint8_t mux)
+ {
+ // TODO: re-check this
+ sendAT(GF("+CIPSTATUS="), mux);
+ int res1 = waitResponse(3000, GF("STATUS:"));
+ int res2;
+ if (res1 == 1) {
+ res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
+ }
+ // status of ESP8266 station interface
+ // 2 : ESP8266 station connected to an AP and has obtained IP
+ // 3 : ESP8266 station created a TCP or UDP transmission
+ // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected)
+ // 5 : ESP8266 station did NOT connect to an AP
+ waitResponse(); // Returns an OK after the status
+ if (res2 == 2 || res2 == 3 || res2 == 4) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ bool streamSkipUntil(char c) //TODO: timeout
+ {
+ while (true) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ if (stream.read() == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = stream.read();
+ if (a <= 0) {
+ continue; // Skip 0x00 bytes, just in case
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ } else if (data.endsWith(GF(GSM_NL "+IPD,"))) {
+ int mux = stream.readStringUntil(',').toInt();
+ int len = stream.readStringUntil(':').toInt();
+ int len_orig = len;
+ if (len > sockets[mux]->rx.free()) {
+ DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
+ } else {
+ DBG("### Got: ", len, "->", sockets[mux]->rx.free());
+ }
+ while (len--) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ sockets[mux]->rx.put(stream.read());
+ }
+ if (len_orig > sockets[mux]->available()) { // TODO
+ DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
+ }
+ data = "";
+ } else if (data.endsWith(GF("CLOSED"))) {
+ int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
+ int coma = data.indexOf(',', muxStart);
+ int mux = data.substring(muxStart, coma).toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
+ sockets[mux]->sock_connected = false;
+ }
+ data = "";
+ DBG("### Closed: ", mux);
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ if (data.length()) {
+ DBG("### Unhandled:", data);
+ }
+ data = "";
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientM590.h b/drivers/TinyGSM/TinyGsmClientM590.h
new file mode 100644
index 000000000..5c6288fba
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientM590.h
@@ -0,0 +1,781 @@
+/**
+ * file TinyGsmClientM590.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientM590_h
+#define TinyGsmClientM590_h
+
+//#define TINY_GSM_DEBUG Serial
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 256
+#endif
+
+#define TINY_GSM_MUX_COUNT 2
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r\n"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+
+enum SimStatus {
+ SIM_ERROR = 0,
+ SIM_READY = 1,
+ SIM_LOCKED = 2,
+};
+
+enum RegStatus {
+ REG_UNREGISTERED = 0,
+ REG_SEARCHING = 3,
+ REG_DENIED = 2,
+ REG_OK_HOME = 1,
+ REG_OK_ROAMING = 5,
+ REG_UNKNOWN = 4,
+};
+
+
+class TinyGsm
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsm;
+ typedef TinyGsmFifo RxFifo;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsm& modem, uint8_t mux = 1)
+ {
+ init(&modem, mux);
+ }
+
+ bool init(TinyGsm* modem, uint8_t mux = 1)
+ {
+ this->at = modem;
+ this->mux = mux;
+ sock_connected = false;
+
+ at->sockets[mux] = this;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, mux);
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ return connect(host.c_str(), port);
+ }
+
+ virtual void stop()
+ {
+ TINY_GSM_YIELD();
+ at->sendAT(GF("+TCPCLOSE="), mux);
+ sock_connected = false;
+ at->waitResponse();
+ rx.clear();
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ //at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ }
+ return rx.size();
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ size_t cnt = 0;
+ while (cnt < size) {
+ size_t chunk = TinyGsmMin(size-cnt, rx.size());
+ if (chunk > 0) {
+ rx.get(buf, chunk);
+ buf += chunk;
+ cnt += chunk;
+ continue;
+ }
+ // TODO: Read directly into user buffer?
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ //break;
+ }
+ }
+ return cnt;
+ }
+
+ virtual int read()
+ {
+ uint8_t c;
+ if (read(&c, 1) == 1) {
+ return c;
+ }
+ return -1;
+ }
+
+ virtual int peek()
+ {
+ return -1; //TODO
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsm* at;
+ uint8_t mux;
+ bool sock_connected;
+ RxFifo rx;
+ };
+
+public:
+
+ explicit TinyGsm(Stream& stream)
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin()
+ {
+ return init();
+ }
+
+ bool init()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
+ if (waitResponse() != 1) {
+ return false;
+ }
+#ifdef TINY_GSM_DEBUG
+ sendAT(GF("+CMEE=2"));
+ waitResponse();
+#endif
+
+ getSimStatus();
+ return true;
+ }
+
+ void setBaud(unsigned long baud)
+ {
+ sendAT(GF("+IPR="), baud);
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF(""));
+ if (waitResponse(200) == 1) {
+ delay(100);
+ return true;
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain()
+ {
+ //while (stream.available()) {
+ waitResponse(10, NULL, NULL);
+ //}
+ }
+
+ bool factoryDefault()
+ {
+ sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
+ waitResponse();
+ sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
+ waitResponse();
+ sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
+ waitResponse();
+ sendAT(GF("+XISP=0")); // Use internal stack
+ waitResponse();
+ sendAT(GF("&W")); // Write configuration
+ return waitResponse() == 1;
+ }
+
+ String getModemInfo()
+ {
+ sendAT(GF("I"));
+ String res;
+ if (waitResponse(1000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, " ");
+ res.trim();
+ return res;
+ }
+
+ bool hasSSL()
+ {
+ return false;
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("+CFUN=15"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ //MODEM:STARTUP
+ waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
+ return init();
+ }
+
+ bool poweroff()
+ {
+ sendAT(GF("+CPWROFF"));
+ return waitResponse(3000L) == 1;
+ }
+
+ bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool sleepEnable(bool enable = true)
+ {
+ sendAT(GF("+ENPWRSAVE="), enable);
+ return waitResponse() == 1;
+ }
+
+ /*
+ * SIM card functions
+ */
+
+ bool simUnlock(const char *pin)
+ {
+ sendAT(GF("+CPIN=\""), pin, GF("\""));
+ return waitResponse() == 1;
+ }
+
+ String getSimCCID()
+ {
+ sendAT(GF("+CCID"));
+ if (waitResponse(GF(GSM_NL "+CCID:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ String getIMEI()
+ {
+ sendAT(GF("+GSN"));
+ if (waitResponse(GF(GSM_NL)) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ SimStatus getSimStatus(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF("+CPIN?"));
+ if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
+ delay(1000);
+ continue;
+ }
+ int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
+ waitResponse();
+ switch (status) {
+ case 2:
+ case 3:
+ return SIM_LOCKED;
+ case 1:
+ return SIM_READY;
+ default:
+ return SIM_ERROR;
+ }
+ }
+ return SIM_ERROR;
+ }
+
+ RegStatus getRegistrationStatus()
+ {
+ sendAT(GF("+CREG?"));
+ if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
+ return REG_UNKNOWN;
+ }
+ streamSkipUntil(','); // Skip format (0)
+ int status = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return (RegStatus)status;
+ }
+
+ String getOperator()
+ {
+ sendAT(GF("+COPS?"));
+ if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
+ return "";
+ }
+ streamSkipUntil('"'); // Skip mode and format
+ String res = stream.readStringUntil('"');
+ waitResponse();
+ return res;
+ }
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ sendAT(GF("+CSQ"));
+ if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
+ return 99;
+ }
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ bool isNetworkConnected()
+ {
+ RegStatus s = getRegistrationStatus();
+ return (s == REG_OK_HOME || s == REG_OK_ROAMING);
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isNetworkConnected()) {
+ return true;
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * GPRS functions
+ */
+ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
+ {
+ gprsDisconnect();
+
+ sendAT(GF("+XISP=0"));
+ waitResponse();
+
+ sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
+ waitResponse();
+
+ if (!user) {
+ user = "";
+ }
+ if (!pwd) {
+ pwd = "";
+ }
+ sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
+ waitResponse();
+
+ sendAT(GF("+XIIC=1"));
+ waitResponse();
+
+ const unsigned long timeout = 60000L;
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isGprsConnected()) {
+ //goto set_dns; // TODO
+ return true;
+ }
+ delay(500);
+ }
+ return false;
+
+set_dns:
+ sendAT(GF("+DNSSERVER=1,8.8.8.8"));
+ waitResponse();
+
+ sendAT(GF("+DNSSERVER=2,8.8.4.4"));
+ waitResponse();
+
+ return true;
+ }
+
+ bool gprsDisconnect()
+ {
+ // TODO: There is no command in AT command set
+ // XIIC=0 does not work
+ return true;
+ }
+
+ bool isGprsConnected()
+ {
+ sendAT(GF("+XIIC?"));
+ if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
+ return false;
+ }
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res == 1;
+ }
+
+ String getLocalIP()
+ {
+ sendAT(GF("+XIIC?"));
+ if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
+ return "";
+ }
+ stream.readStringUntil(',');
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+ /*
+ * Phone Call functions
+ */
+
+ bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ /*
+ * Messaging functions
+ */
+
+ String sendUSSD(const String& code)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CSCS=\"HEX\""));
+ waitResponse();
+ sendAT(GF("D"), code);
+ if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
+ return "";
+ }
+ stream.readStringUntil('"');
+ String hex = stream.readStringUntil('"');
+ stream.readStringUntil(',');
+ int dcs = stream.readStringUntil('\n').toInt();
+
+ if (waitResponse() != 1) {
+ return "";
+ }
+
+ if (dcs == 15) {
+ return TinyGsmDecodeHex8bit(hex);
+ } else if (dcs == 72) {
+ return TinyGsmDecodeHex16bit(hex);
+ } else {
+ return hex;
+ }
+ }
+
+ bool sendSMS(const String& number, const String& text)
+ {
+ sendAT(GF("+CSCS=\"GSM\""));
+ waitResponse();
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CMGS=\""), number, GF("\""));
+ if (waitResponse(GF(">")) != 1) {
+ return false;
+ }
+ stream.print(text);
+ stream.write((char)0x1A);
+ stream.flush();
+ return waitResponse(60000L) == 1;
+ }
+
+ bool sendSMS_UTF16(const String& number, const void* text, size_t len)
+ TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ /*
+ * Location functions
+ */
+
+ String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ /*
+ * Battery functions
+ */
+
+ uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+ int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
+
+protected:
+
+ bool modemConnect(const char* host, uint16_t port, uint8_t mux)
+ {
+ for (int i=0; i<3; i++) { // TODO: no need for loop?
+ String ip = dnsIpQuery(host);
+
+ sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
+ int rsp = waitResponse(75000L,
+ GF(",OK" GSM_NL),
+ GF(",FAIL" GSM_NL),
+ GF("+TCPSETUP:Error" GSM_NL));
+ if (1 == rsp) {
+ return true;
+ } else if (3 == rsp) {
+ sendAT(GF("+TCPCLOSE="), mux);
+ waitResponse();
+ }
+ delay(1000);
+ }
+ return false;
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux)
+ {
+ sendAT(GF("+TCPSEND="), mux, ',', len);
+ if (waitResponse(GF(">")) != 1) {
+ return 0;
+ }
+ stream.write((uint8_t*)buff, len);
+ stream.write((char)0x0D);
+ stream.flush();
+ if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) {
+ return 0;
+ }
+ stream.readStringUntil('\n');
+ return len;
+ }
+
+ bool modemGetConnected(uint8_t mux)
+ {
+ sendAT(GF("+CIPSTATUS="), mux);
+ int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
+ GF(",\"INITIAL\""));
+ waitResponse();
+ return 1 == res;
+ }
+
+ String dnsIpQuery(const char* host)
+ {
+ sendAT(GF("+DNS=\""), host, GF("\""));
+ if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse(GF("+DNS:OK" GSM_NL));
+ res.trim();
+ return res;
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ bool streamSkipUntil(char c) //TODO: timeout
+ {
+ while (true) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ if (stream.read() == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = stream.read();
+ if (a <= 0) {
+ continue; // Skip 0x00 bytes, just in case
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ } else if (data.endsWith(GF("+TCPRECV:"))) {
+ int mux = stream.readStringUntil(',').toInt();
+ int len = stream.readStringUntil(',').toInt();
+ int len_orig = len;
+ if (len > sockets[mux]->rx.free()) {
+ DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
+ } else {
+ DBG("### Got: ", len, "->", sockets[mux]->rx.free());
+ }
+ while (len--) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ sockets[mux]->rx.put(stream.read());
+ }
+ if (len_orig > sockets[mux]->available()) { // TODO
+ DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
+ }
+ data = "";
+ } else if (data.endsWith(GF("+TCPCLOSE:"))) {
+ int mux = stream.readStringUntil(',').toInt();
+ stream.readStringUntil('\n');
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
+ sockets[mux]->sock_connected = false;
+ }
+ data = "";
+ DBG("### Closed: ", mux);
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ if (data.length()) {
+ DBG("### Unhandled:", data);
+ }
+ data = "";
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientSIM800.h b/drivers/TinyGSM/TinyGsmClientSIM800.h
new file mode 100644
index 000000000..265bdc0c8
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientSIM800.h
@@ -0,0 +1,1057 @@
+/**
+ * file TinyGsmClientSIM800.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientSIM800_h
+#define TinyGsmClientSIM800_h
+
+//#define TINY_GSM_DEBUG Serial
+//#define TINY_GSM_USE_HEX
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 64
+#endif
+
+#define TINY_GSM_MUX_COUNT 5
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r\n"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+
+enum SimStatus {
+ SIM_ERROR = 0,
+ SIM_READY = 1,
+ SIM_LOCKED = 2,
+};
+
+enum RegStatus {
+ REG_UNREGISTERED = 0,
+ REG_SEARCHING = 2,
+ REG_DENIED = 3,
+ REG_OK_HOME = 1,
+ REG_OK_ROAMING = 5,
+ REG_UNKNOWN = 4,
+};
+
+
+class TinyGsmSim800
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsmSim800;
+ typedef TinyGsmFifo RxFifo;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsmSim800& modem, uint8_t mux = 1)
+ {
+ init(&modem, mux);
+ }
+
+ bool init(TinyGsmSim800* modem, uint8_t mux = 1)
+ {
+ this->at = modem;
+ this->mux = mux;
+ sock_available = 0;
+ prev_check = 0;
+ sock_connected = false;
+ got_data = false;
+
+ at->sockets[mux] = this;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, mux);
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ return connect(host.c_str(), port);
+ }
+
+ virtual void stop()
+ {
+ TINY_GSM_YIELD();
+ at->sendAT(GF("+CIPCLOSE="), mux);
+ sock_connected = false;
+ at->waitResponse();
+ rx.clear();
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ if (!rx.size() && sock_connected) {
+ // Workaround: sometimes SIM800 forgets to notify about data arrival.
+ // TODO: Currently we ping the module periodically,
+ // but maybe there's a better indicator that we need to poll
+ if (millis() - prev_check > 500) {
+ got_data = true;
+ prev_check = millis();
+ }
+ at->maintain();
+ }
+ return rx.size() + sock_available;
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ at->maintain();
+ size_t cnt = 0;
+ while (cnt < size && sock_connected) {
+ size_t chunk = TinyGsmMin(size-cnt, rx.size());
+ if (chunk > 0) {
+ rx.get(buf, chunk);
+ buf += chunk;
+ cnt += chunk;
+ continue;
+ }
+ // TODO: Read directly into user buffer?
+ at->maintain();
+ if (sock_available > 0) {
+ at->modemRead(rx.free(), mux);
+ } else {
+ break;
+ }
+ }
+ return cnt;
+ }
+
+ virtual int read()
+ {
+ uint8_t c;
+ if (read(&c, 1) == 1) {
+ return c;
+ }
+ return -1;
+ }
+
+ virtual int peek()
+ {
+ return -1; //TODO
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsmSim800* at;
+ uint8_t mux;
+ uint16_t sock_available;
+ uint32_t prev_check;
+ bool sock_connected;
+ bool got_data;
+ RxFifo rx;
+ };
+
+ class GsmClientSecure : public GsmClient
+ {
+ public:
+ GsmClientSecure() {}
+
+ GsmClientSecure(TinyGsmSim800& modem, uint8_t mux = 1)
+ : GsmClient(modem, mux)
+ {}
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, mux, true);
+ return sock_connected;
+ }
+ };
+
+public:
+
+ explicit TinyGsmSim800(Stream& stream)
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin()
+ {
+ return init();
+ }
+
+ bool init()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("&FZ")); // Factory + Reset
+ waitResponse();
+ sendAT(GF("E0")); // Echo Off
+ if (waitResponse() != 1) {
+ return false;
+ }
+ getSimStatus();
+ return true;
+ }
+
+ void setBaud(unsigned long baud)
+ {
+ sendAT(GF("+IPR="), baud);
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ //streamWrite(GF("AAAAA" GSM_NL)); // TODO: extra A's to help detect the baud rate
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF(""));
+ if (waitResponse(200) == 1) {
+ delay(100);
+ return true;
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain()
+ {
+ for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
+ GsmClient* sock = sockets[mux];
+ if (sock && sock->got_data) {
+ sock->got_data = false;
+ sock->sock_available = modemGetAvailable(mux);
+ }
+ }
+ while (stream.available()) {
+ waitResponse(10, NULL, NULL);
+ }
+ }
+
+ bool factoryDefault()
+ {
+ sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
+ waitResponse();
+ sendAT(GF("+IPR=0")); // Auto-baud
+ waitResponse();
+ sendAT(GF("+IFC=0,0")); // No Flow Control
+ waitResponse();
+ sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
+ waitResponse();
+ sendAT(GF("+CSCLK=0")); // Disable Slow Clock
+ waitResponse();
+ sendAT(GF("&W")); // Write configuration
+ return waitResponse() == 1;
+ }
+
+ String getModemInfo()
+ {
+ sendAT(GF("I"));
+ String res;
+ if (waitResponse(1000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, " ");
+ res.trim();
+ return res;
+ }
+
+ bool hasSSL()
+ {
+#if defined(TINY_GSM_MODEM_SIM900)
+ return false;
+#else
+ sendAT(GF("+CIPSSL=?"));
+ if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
+ return false;
+ }
+ return waitResponse() == 1;
+#endif
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("+CFUN=0"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ sendAT(GF("+CFUN=1,1"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ delay(3000);
+ return init();
+ }
+
+ bool poweroff()
+ {
+ sendAT(GF("+CPOWD=1"));
+ return waitResponse(GF("NORMAL POWER DOWN")) == 1;
+ }
+
+ bool radioOff()
+ {
+ sendAT(GF("+CFUN=0"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ delay(3000);
+ return true;
+ }
+
+ /*
+ During sleep, the SIM800 module has its serial communication disabled. In order to reestablish communication
+ pull the DRT-pin of the SIM800 module LOW for at least 50ms. Then use this function to disable sleep mode.
+ The DTR-pin can then be released again.
+ */
+ bool sleepEnable(bool enable = true)
+ {
+ sendAT(GF("+CSCLK="), enable);
+ return waitResponse() == 1;
+ }
+
+ /*
+ * SIM card functions
+ */
+
+ bool simUnlock(const char *pin)
+ {
+ sendAT(GF("+CPIN=\""), pin, GF("\""));
+ return waitResponse() == 1;
+ }
+
+ String getSimCCID()
+ {
+ sendAT(GF("+ICCID"));
+ if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ String getIMEI()
+ {
+ sendAT(GF("+GSN"));
+ if (waitResponse(GF(GSM_NL)) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ SimStatus getSimStatus(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF("+CPIN?"));
+ if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
+ delay(1000);
+ continue;
+ }
+ int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
+ waitResponse();
+ switch (status) {
+ case 2:
+ case 3:
+ return SIM_LOCKED;
+ case 1:
+ return SIM_READY;
+ default:
+ return SIM_ERROR;
+ }
+ }
+ return SIM_ERROR;
+ }
+
+ RegStatus getRegistrationStatus()
+ {
+ sendAT(GF("+CREG?"));
+ if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
+ return REG_UNKNOWN;
+ }
+ streamSkipUntil(','); // Skip format (0)
+ int status = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return (RegStatus)status;
+ }
+
+ String getOperator()
+ {
+ sendAT(GF("+COPS?"));
+ if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
+ return "";
+ }
+ streamSkipUntil('"'); // Skip mode and format
+ String res = stream.readStringUntil('"');
+ waitResponse();
+ return res;
+ }
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ sendAT(GF("+CSQ"));
+ if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
+ return 99;
+ }
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ bool isNetworkConnected()
+ {
+ RegStatus s = getRegistrationStatus();
+ return (s == REG_OK_HOME || s == REG_OK_ROAMING);
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isNetworkConnected()) {
+ return true;
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * GPRS functions
+ */
+ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
+ {
+ gprsDisconnect();
+
+ // Set the Bearer for the IP
+ sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
+ waitResponse();
+
+ sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
+ waitResponse();
+
+ if (user && strlen(user) > 0) {
+ sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
+ waitResponse();
+ }
+ if (pwd && strlen(pwd) > 0) {
+ sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
+ waitResponse();
+ }
+
+ // Define the PDP context
+ sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
+ waitResponse();
+
+ // Activate the PDP context
+ sendAT(GF("+CGACT=1,1"));
+ waitResponse(60000L);
+
+ // Open the definied GPRS bearer context
+ sendAT(GF("+SAPBR=1,1"));
+ waitResponse(85000L);
+ // Query the GPRS bearer context status
+ sendAT(GF("+SAPBR=2,1"));
+ if (waitResponse(30000L) != 1) {
+ return false;
+ }
+
+ // Attach to GPRS
+ sendAT(GF("+CGATT=1"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ // TODO: wait AT+CGATT?
+
+ // Set to multi-IP
+ sendAT(GF("+CIPMUX=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ // Put in "quick send" mode (thus no extra "Send OK")
+ sendAT(GF("+CIPQSEND=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ // Set to get data manually
+ sendAT(GF("+CIPRXGET=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ // Start Task and Set APN, USER NAME, PASSWORD
+ sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ // Bring Up Wireless Connection with GPRS or CSD
+ sendAT(GF("+CIICR"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ // Get Local IP Address, only assigned after connection
+ sendAT(GF("+CIFSR;E0"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+
+ // Configure Domain Name Server (DNS)
+ sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool gprsDisconnect()
+ {
+ // Shut the TCP/IP connection
+ sendAT(GF("+CIPSHUT"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CGATT=0")); // Deactivate the bearer context
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool isGprsConnected()
+ {
+ sendAT(GF("+CGATT?"));
+ if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
+ return false;
+ }
+ int res = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ if (res != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ String getLocalIP()
+ {
+ sendAT(GF("+CIFSR;E0"));
+ String res;
+ if (waitResponse(10000L, res) != 1) {
+ return "";
+ }
+ res.replace(GSM_NL "OK" GSM_NL, "");
+ res.replace(GSM_NL, "");
+ res.trim();
+ return res;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+ /*
+ * Phone Call functions
+ */
+
+ bool setGsmBusy(bool busy = true)
+ {
+ sendAT(GF("+GSMBUSY="), busy ? 1 : 0);
+ return waitResponse() == 1;
+ }
+
+ bool callAnswer()
+ {
+ sendAT(GF("A"));
+ return waitResponse() == 1;
+ }
+
+ // Returns true on pick-up, false on error/busy
+ bool callNumber(const String& number)
+ {
+ if (number == GF("last")) {
+ sendAT(GF("DL"));
+ } else {
+ sendAT(GF("D"), number, ";");
+ }
+ int status = waitResponse(60000L,
+ GFP(GSM_OK),
+ GF("BUSY" GSM_NL),
+ GF("NO ANSWER" GSM_NL),
+ GF("NO CARRIER" GSM_NL));
+ switch (status) {
+ case 1:
+ return true;
+ case 2:
+ case 3:
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ bool callHangup()
+ {
+ sendAT(GF("H"));
+ return waitResponse() == 1;
+ }
+
+ // 0-9,*,#,A,B,C,D
+ bool dtmfSend(char cmd, int duration_ms = 100)
+ {
+ duration_ms = constrain(duration_ms, 100, 1000);
+
+ sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second
+ waitResponse();
+
+ sendAT(GF("+VTS="), cmd);
+ return waitResponse(10000L) == 1;
+ }
+
+ /*
+ * Messaging functions
+ */
+
+ String sendUSSD(const String& code)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CSCS=\"HEX\""));
+ waitResponse();
+ sendAT(GF("+CUSD=1,\""), code, GF("\""));
+ if (waitResponse() != 1) {
+ return "";
+ }
+ if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
+ return "";
+ }
+ stream.readStringUntil('"');
+ String hex = stream.readStringUntil('"');
+ stream.readStringUntil(',');
+ int dcs = stream.readStringUntil('\n').toInt();
+
+ if (dcs == 15) {
+ return TinyGsmDecodeHex8bit(hex);
+ } else if (dcs == 72) {
+ return TinyGsmDecodeHex16bit(hex);
+ } else {
+ return hex;
+ }
+ }
+
+ bool sendSMS(const String& number, const String& text)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ //Set GSM 7 bit default alphabet (3GPP TS 23.038)
+ sendAT(GF("+CSCS=\"GSM\""));
+ waitResponse();
+ sendAT(GF("+CMGS=\""), number, GF("\""));
+ if (waitResponse(GF(">")) != 1) {
+ return false;
+ }
+ stream.print(text);
+ stream.write((char)0x1A);
+ stream.flush();
+ return waitResponse(60000L) == 1;
+ }
+
+ bool sendSMS_UTF16(const String& number, const void* text, size_t len)
+ {
+ sendAT(GF("+CMGF=1"));
+ waitResponse();
+ sendAT(GF("+CSCS=\"HEX\""));
+ waitResponse();
+ sendAT(GF("+CSMP=17,167,0,8"));
+ waitResponse();
+
+ sendAT(GF("+CMGS=\""), number, GF("\""));
+ if (waitResponse(GF(">")) != 1) {
+ return false;
+ }
+
+ uint16_t* t = (uint16_t*)text;
+ for (size_t i=0; i> 8;
+ if (c < 0x10) {
+ stream.print('0');
+ }
+ stream.print(c, HEX);
+ c = t[i] & 0xFF;
+ if (c < 0x10) {
+ stream.print('0');
+ }
+ stream.print(c, HEX);
+ }
+ stream.write((char)0x1A);
+ stream.flush();
+ return waitResponse(60000L) == 1;
+ }
+
+
+ /*
+ * Location functions
+ */
+
+ String getGsmLocation()
+ {
+ sendAT(GF("+CIPGSMLOC=1,1"));
+ if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ /*
+ * Battery functions
+ */
+ // Use: float vBatt = modem.getBattVoltage() / 1000.0;
+ uint16_t getBattVoltage()
+ {
+ sendAT(GF("+CBC"));
+ if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
+ return 0;
+ }
+ streamSkipUntil(','); // Skip
+ streamSkipUntil(','); // Skip
+
+ uint16_t res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ int getBattPercent()
+ {
+ sendAT(GF("+CBC"));
+ if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
+ return false;
+ }
+ stream.readStringUntil(',');
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+protected:
+
+ bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false)
+ {
+#if !defined(TINY_GSM_MODEM_SIM900)
+ sendAT(GF("+CIPSSL="), ssl);
+ int rsp = waitResponse();
+ if (ssl && rsp != 1) {
+ return false;
+ }
+#endif
+ sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
+ rsp = waitResponse(75000L,
+ GF("CONNECT OK" GSM_NL),
+ GF("CONNECT FAIL" GSM_NL),
+ GF("ALREADY CONNECT" GSM_NL),
+ GF("ERROR" GSM_NL),
+ GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails
+ );
+ return (1 == rsp);
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux)
+ {
+ sendAT(GF("+CIPSEND="), mux, ',', len);
+ if (waitResponse(GF(">")) != 1) {
+ return 0;
+ }
+ stream.write((uint8_t*)buff, len);
+ stream.flush();
+ if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) {
+ return 0;
+ }
+ streamSkipUntil(','); // Skip mux
+ return stream.readStringUntil('\n').toInt();
+ }
+
+ size_t modemRead(size_t size, uint8_t mux)
+ {
+#ifdef TINY_GSM_USE_HEX
+ sendAT(GF("+CIPRXGET=3,"), mux, ',', size);
+ if (waitResponse(GF("+CIPRXGET:")) != 1) {
+ return 0;
+ }
+#else
+ sendAT(GF("+CIPRXGET=2,"), mux, ',', size);
+ if (waitResponse(GF("+CIPRXGET:")) != 1) {
+ return 0;
+ }
+#endif
+ streamSkipUntil(','); // Skip mode 2/3
+ streamSkipUntil(','); // Skip mux
+ size_t len = stream.readStringUntil(',').toInt();
+ sockets[mux]->sock_available = stream.readStringUntil('\n').toInt();
+
+ for (size_t i=0; irx.put(c);
+ }
+ waitResponse();
+ return len;
+ }
+
+ size_t modemGetAvailable(uint8_t mux)
+ {
+ sendAT(GF("+CIPRXGET=4,"), mux);
+ size_t result = 0;
+ if (waitResponse(GF("+CIPRXGET:")) == 1) {
+ streamSkipUntil(','); // Skip mode 4
+ streamSkipUntil(','); // Skip mux
+ result = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ }
+ if (!result) {
+ sockets[mux]->sock_connected = modemGetConnected(mux);
+ }
+ return result;
+ }
+
+ bool modemGetConnected(uint8_t mux)
+ {
+ sendAT(GF("+CIPSTATUS="), mux);
+ int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
+ GF(",\"INITIAL\""));
+ waitResponse();
+ return 1 == res;
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ bool streamSkipUntil(char c) //TODO: timeout
+ {
+ while (true) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ if (stream.read() == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = stream.read();
+ if (a <= 0) {
+ continue; // Skip 0x00 bytes, just in case
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
+ String mode = stream.readStringUntil(',');
+ if (mode.toInt() == 1) {
+ int mux = stream.readStringUntil('\n').toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
+ sockets[mux]->got_data = true;
+ }
+ data = "";
+ } else {
+ data += mode;
+ }
+ } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
+ int nl = data.lastIndexOf(GSM_NL, data.length()-8);
+ int coma = data.indexOf(',', nl+2);
+ int mux = data.substring(nl+2, coma).toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
+ sockets[mux]->sock_connected = false;
+ }
+ data = "";
+ DBG("### Closed: ", mux);
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ if (data.length()) {
+ DBG("### Unhandled:", data);
+ }
+ data = "";
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientSIM808.h b/drivers/TinyGSM/TinyGsmClientSIM808.h
new file mode 100644
index 000000000..d6342a1e4
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientSIM808.h
@@ -0,0 +1,163 @@
+/**
+ * file TinyGsmClientSIM808.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientSIM808_h
+#define TinyGsmClientSIM808_h
+
+#include "TinyGsmClientSIM800.h"
+
+class TinyGsmSim808: public TinyGsmSim800
+{
+
+public:
+
+ explicit TinyGsmSim808(Stream& stream)
+ : TinyGsmSim800(stream)
+ {}
+
+ /*
+ * GPS location functions
+ */
+
+ // enable GPS
+ bool enableGPS()
+ {
+ uint16_t state;
+
+ sendAT(GF("+CGNSPWR=1"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool disableGPS()
+ {
+ uint16_t state;
+
+ sendAT(GF("+CGNSPWR=0"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // get the RAW GPS output
+ // works only with ans SIM808 V2
+ String getGPSraw()
+ {
+ sendAT(GF("+CGNSINF"));
+ if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ // get GPS informations
+ // works only with ans SIM808 V2
+ bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0)
+ {
+ //String buffer = "";
+ char chr_buffer[12];
+ bool fix = false;
+
+ sendAT(GF("+CGNSINF"));
+ if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
+ return false;
+ }
+
+ stream.readStringUntil(','); // mode
+ if ( stream.readStringUntil(',').toInt() == 1 ) {
+ fix = true;
+ }
+ stream.readStringUntil(','); //utctime
+ *lat = stream.readStringUntil(',').toFloat(); //lat
+ *lon = stream.readStringUntil(',').toFloat(); //lon
+ if (alt != NULL) {
+ *alt = stream.readStringUntil(',').toFloat(); //lon
+ }
+ if (speed != NULL) {
+ *speed = stream.readStringUntil(',').toFloat(); //speed
+ }
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ stream.readStringUntil(',');
+ if (vsat != NULL) {
+ *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
+ }
+ if (usat != NULL) {
+ *usat = stream.readStringUntil(',').toInt(); //used satelites
+ }
+ stream.readStringUntil('\n');
+
+ waitResponse();
+
+ return fix;
+ }
+
+ // get GPS time
+ // works only with SIM808 V2
+ bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second)
+ {
+ bool fix = false;
+ char chr_buffer[12];
+ sendAT(GF("+CGNSINF"));
+ if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
+ return false;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ String buffer = stream.readStringUntil(',');
+ buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
+ switch (i) {
+ case 0:
+ //mode
+ break;
+ case 1:
+ //fixstatus
+ if ( buffer.toInt() == 1 ) {
+ fix = buffer.toInt();
+ }
+ break;
+ case 2:
+ *year = buffer.substring(0,4).toInt();
+ *month = buffer.substring(4,6).toInt();
+ *day = buffer.substring(6,8).toInt();
+ *hour = buffer.substring(8,10).toInt();
+ *minute = buffer.substring(10,12).toInt();
+ *second = buffer.substring(12,14).toInt();
+ break;
+
+ default:
+ // if nothing else matches, do the default
+ // default is optional
+ break;
+ }
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+
+ if (fix) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientU201.h b/drivers/TinyGSM/TinyGsmClientU201.h
new file mode 100644
index 000000000..d5349aceb
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientU201.h
@@ -0,0 +1,789 @@
+/**
+ * file TinyGsmClientU201.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientU201_h
+#define TinyGsmClientU201_h
+
+//#define TINY_GSM_DEBUG Serial
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 64
+#endif
+
+#define TINY_GSM_MUX_COUNT 5
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r\n"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+
+enum SimStatus {
+ SIM_ERROR = 0,
+ SIM_READY = 1,
+ SIM_LOCKED = 2,
+};
+
+enum RegStatus {
+ REG_UNREGISTERED = 0,
+ REG_SEARCHING = 2,
+ REG_DENIED = 3,
+ REG_OK_HOME = 1,
+ REG_OK_ROAMING = 5,
+ REG_UNKNOWN = 4,
+};
+
+
+class TinyGsmU201
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsmU201;
+ typedef TinyGsmFifo RxFifo;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsmU201& modem, uint8_t mux = 1)
+ {
+ init(&modem, mux);
+ }
+
+ bool init(TinyGsmU201* modem, uint8_t mux = 1)
+ {
+ this->at = modem;
+ this->mux = mux;
+ sock_available = 0;
+ sock_connected = false;
+ got_data = false;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, &mux);
+ at->sockets[mux] = this;
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ return connect(host.c_str(), port);
+ }
+
+ virtual void stop()
+ {
+ TINY_GSM_YIELD();
+ at->sendAT(GF("+USOCL="), mux);
+ sock_connected = false;
+ at->waitResponse();
+ rx.clear();
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ if (!rx.size() && sock_connected) {
+ at->maintain();
+ }
+ return rx.size() + sock_available;
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ at->maintain();
+ size_t cnt = 0;
+ while (cnt < size) {
+ size_t chunk = TinyGsmMin(size-cnt, rx.size());
+ if (chunk > 0) {
+ rx.get(buf, chunk);
+ buf += chunk;
+ cnt += chunk;
+ continue;
+ }
+ // TODO: Read directly into user buffer?
+ at->maintain();
+ if (sock_available > 0) {
+ at->modemRead(rx.free(), mux);
+ } else {
+ break;
+ }
+ }
+ return cnt;
+ }
+
+ virtual int read()
+ {
+ uint8_t c;
+ if (read(&c, 1) == 1) {
+ return c;
+ }
+ return -1;
+ }
+
+ virtual int peek()
+ {
+ return -1; //TODO
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsmU201* at;
+ uint8_t mux;
+ uint16_t sock_available;
+ bool sock_connected;
+ bool got_data;
+ RxFifo rx;
+ };
+
+ class GsmClientSecure : public GsmClient
+ {
+ public:
+ GsmClientSecure() {}
+
+ GsmClientSecure(TinyGsmU201& modem, uint8_t mux = 1)
+ : GsmClient(modem, mux)
+ {}
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ stop();
+ TINY_GSM_YIELD();
+ rx.clear();
+ sock_connected = at->modemConnect(host, port, &mux, true);
+ at->sockets[mux] = this;
+ return sock_connected;
+ }
+ };
+
+public:
+
+#ifdef GSM_DEFAULT_STREAM
+ explicit TinyGsmU201(Stream& stream = GSM_DEFAULT_STREAM)
+#else
+ explicit TinyGsmU201(Stream& stream)
+#endif
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin(const char* pin = NULL)
+ {
+ return init(pin);
+ }
+
+ bool init(const char* pin = NULL)
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("E0")); // Echo Off
+ if (waitResponse() != 1) {
+ return false;
+ }
+ int ret = getSimStatus();
+ if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
+ simUnlock(pin);
+ }
+ return (getSimStatus() == SIM_READY);
+ }
+
+ void setBaud(unsigned long baud)
+ {
+ sendAT(GF("+IPR="), baud);
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF(""));
+ if (waitResponse(200) == 1) {
+ delay(100);
+ return true;
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain()
+ {
+ for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
+ GsmClient* sock = sockets[mux];
+ if (sock && sock->got_data) {
+ sock->got_data = false;
+ sock->sock_available = modemGetAvailable(mux);
+ }
+ }
+ while (stream.available()) {
+ waitResponse(10, NULL, NULL);
+ }
+ }
+
+ bool factoryDefault()
+ {
+ sendAT(GF("+UFACTORY=0,1")); // Factory + Reset + Echo Off
+ waitResponse();
+ sendAT(GF("+CFUN=16")); // Auto-baud
+ return waitResponse() == 1;
+ }
+
+ String getModemInfo() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool hasSSL()
+ {
+ return true;
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ if (!testAT()) {
+ return false;
+ }
+ sendAT(GF("+CFUN=16"));
+ if (waitResponse(10000L) != 1) {
+ return false;
+ }
+ delay(3000);
+ return init();
+ }
+
+ bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ /*
+ * SIM card functions
+ */
+
+ bool simUnlock(const char *pin)
+ {
+ sendAT(GF("+CPIN=\""), pin, GF("\""));
+ return waitResponse() == 1;
+ }
+
+ String getSimCCID()
+ {
+ sendAT(GF("+CCID"));
+ if (waitResponse(GF(GSM_NL "+CCID:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ String getIMEI()
+ {
+ sendAT(GF("+CGSN"));
+ if (waitResponse(GF(GSM_NL)) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ SimStatus getSimStatus(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ sendAT(GF("+CPIN?"));
+ if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
+ delay(1000);
+ continue;
+ }
+ int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
+ waitResponse();
+ switch (status) {
+ case 2:
+ case 3:
+ return SIM_LOCKED;
+ case 1:
+ return SIM_READY;
+ default:
+ return SIM_ERROR;
+ }
+ }
+ return SIM_ERROR;
+ }
+
+ RegStatus getRegistrationStatus()
+ {
+ sendAT(GF("+CGREG?"));
+ if (waitResponse(GF(GSM_NL "+CGREG:")) != 1) {
+ return REG_UNKNOWN;
+ }
+ streamSkipUntil(','); // Skip format (0)
+ int status = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ return (RegStatus)status;
+ }
+
+ String getOperator()
+ {
+ sendAT(GF("+COPS?"));
+ if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
+ return "";
+ }
+ streamSkipUntil('"'); // Skip mode and format
+ String res = stream.readStringUntil('"');
+ waitResponse();
+ return res;
+ }
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ sendAT(GF("+CSQ"));
+ if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
+ return 99;
+ }
+ int res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ bool isNetworkConnected()
+ {
+ RegStatus s = getRegistrationStatus();
+ return (s == REG_OK_HOME || s == REG_OK_ROAMING);
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isNetworkConnected()) {
+ return true;
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * GPRS functions
+ */
+ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
+ {
+ gprsDisconnect();
+
+ sendAT(GF("+CGATT=1"));
+ waitResponse(5000L);
+
+ sendAT(GF("+UPSD=0,1,\""), apn, '"');
+ waitResponse();
+
+ if (user && strlen(user) > 0) {
+ sendAT(GF("+UPSD=0,2,\""), user, '"');
+ waitResponse();
+ }
+ if (pwd && strlen(pwd) > 0) {
+ sendAT(GF("+UPSD=0,3,\""), pwd, '"');
+ waitResponse();
+ }
+
+ sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP
+ waitResponse();
+
+ sendAT(GF("+UPSDA=0,3"));
+ waitResponse(6000L);
+
+ // Open a GPRS context
+ sendAT(GF("+UPSND=0,8"));
+ if (waitResponse(GF(",8,1")) != 1) {
+ return false;
+ }
+ return true;
+ }
+
+ bool gprsDisconnect()
+ {
+ sendAT(GF("+UPSDA=0,4"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CGATT=0"));
+ if (waitResponse(60000L) != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool isGprsConnected()
+ {
+ sendAT(GF("+CGATT?"));
+ if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
+ return false;
+ }
+ int res = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ if (res != 1) {
+ return false;
+ }
+
+ sendAT(GF("+CIFSR"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ String getLocalIP()
+ {
+ sendAT(GF("+CIFSR;E0"));
+ String res;
+ if (waitResponse(10000L, res) != 1) {
+ return "";
+ }
+ res.trim();
+ return res;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+ /*
+ * Phone Call functions
+ */
+
+ bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ /*
+ * Messaging functions
+ */
+
+ String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool sendSMS(const String& number, const String& text) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool sendSMS_UTF16(const String& number, const void* text,
+ size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+
+ /*
+ * Location functions
+ */
+
+ String getGsmLocation()
+ {
+ sendAT(GF("+ULOC=2,3,0,120,1"));
+ if (waitResponse(GF(GSM_NL "+UULOC:")) != 1) {
+ return "";
+ }
+ String res = stream.readStringUntil('\n');
+ waitResponse();
+ res.trim();
+ return res;
+ }
+
+ /*
+ * Battery functions
+ */
+ // Use: float vBatt = modem.getBattVoltage() / 1000.0;
+ uint16_t getBattVoltage()
+ {
+ sendAT(GF("+CIND"));
+ if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
+ return 0;
+ }
+
+ uint16_t res = stream.readStringUntil(',').toInt();
+ waitResponse();
+ return res;
+ }
+
+ int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+protected:
+
+ bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false)
+ {
+ sendAT(GF("+USOCR=6"));
+ if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) {
+ return false;
+ }
+ *mux = stream.readStringUntil('\n').toInt();
+ waitResponse();
+
+ if (ssl) {
+ sendAT(GF("+USOSEC="), *mux, ",1");
+ waitResponse();
+ }
+
+ sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
+ int rsp = waitResponse(75000L);
+ return (1 == rsp);
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux)
+ {
+ sendAT(GF("+USOWR="), mux, ',', len);
+ if (waitResponse(GF("@")) != 1) {
+ return -1;
+ }
+ // 50ms delay, see AT manual section 25.10.4
+ delay(50);
+ stream.write((uint8_t*)buff, len);
+ stream.flush();
+ if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
+ return -1;
+ }
+ streamSkipUntil(','); // Skip mux
+ return stream.readStringUntil('\n').toInt();
+ }
+
+ size_t modemRead(size_t size, uint8_t mux)
+ {
+ sendAT(GF("+USORD="), mux, ',', size);
+ if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
+ return 0;
+ }
+ streamSkipUntil(','); // Skip mux
+ size_t len = stream.readStringUntil(',').toInt();
+ streamSkipUntil('\"');
+
+ for (size_t i=0; irx.put(c);
+ }
+ streamSkipUntil('\"');
+ waitResponse();
+ return len;
+ }
+
+ size_t modemGetAvailable(uint8_t mux)
+ {
+ sendAT(GF("+USORD="), mux, ',', 0);
+ size_t result = 0;
+ if (waitResponse(GF(GSM_NL "+USORD:")) == 1) {
+ streamSkipUntil(','); // Skip mux
+ result = stream.readStringUntil('\n').toInt();
+ waitResponse();
+ }
+ if (!result) {
+ sockets[mux]->sock_connected = modemGetConnected(mux);
+ }
+ return result;
+ }
+
+ bool modemGetConnected(uint8_t mux)
+ {
+ sendAT(GF("+USOCTL="), mux, ",10");
+ if (waitResponse(GF(GSM_NL "+USOCTL:")) != 1) {
+ return false;
+ }
+
+ streamSkipUntil(','); // Skip mux
+ streamSkipUntil(','); // Skip type
+ int result = stream.readStringUntil('\n').toInt();
+
+ return result != 0;
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ bool streamSkipUntil(char c) //TODO: timeout
+ {
+ while (true) {
+ while (!stream.available()) {
+ TINY_GSM_YIELD();
+ }
+ if (stream.read() == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = stream.read();
+ if (a < 0) {
+ continue;
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ } else if (data.endsWith(GF(GSM_NL "+UUSORD:"))) {
+ int mux = stream.readStringUntil(',').toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
+ sockets[mux]->got_data = true;
+ }
+ data = "";
+ } else if (data.endsWith(GF(GSM_NL "+UUSOCL:"))) {
+ int mux = stream.readStringUntil('\n').toInt();
+ if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
+ sockets[mux]->sock_connected = false;
+ }
+ data = "";
+ DBG("### Closed: ", mux);
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ if (data.length()) {
+ DBG("### Unhandled:", data);
+ }
+ data = "";
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmClientXBee.h b/drivers/TinyGSM/TinyGsmClientXBee.h
new file mode 100644
index 000000000..8efef857a
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmClientXBee.h
@@ -0,0 +1,752 @@
+/**
+ * file TinyGsmClientXBee.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmClientXBee_h
+#define TinyGsmClientXBee_h
+
+//#define TINY_GSM_DEBUG Serial
+
+#if !defined(TINY_GSM_RX_BUFFER)
+#define TINY_GSM_RX_BUFFER 256
+#endif
+
+#define TINY_GSM_MUX_COUNT 1 // Multi-plexing isn't supported using command mode
+
+#include "TinyGsmCommon.h"
+
+#define GSM_NL "\r"
+static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
+static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
+
+enum SimStatus {
+ SIM_ERROR = 0,
+ SIM_READY = 1,
+ SIM_LOCKED = 2,
+};
+
+enum XBeeType {
+ S6B = 0,
+ LTEC1 = 1,
+};
+
+enum RegStatus {
+ REG_UNREGISTERED = 0,
+ REG_SEARCHING = 2,
+ REG_DENIED = 3,
+ REG_OK_HOME = 1,
+ REG_OK_ROAMING = 5,
+ REG_UNKNOWN = 4,
+};
+
+
+class TinyGsm
+{
+
+public:
+
+ class GsmClient : public Client
+ {
+ friend class TinyGsm;
+
+ public:
+ GsmClient() {}
+
+ GsmClient(TinyGsm& modem, uint8_t mux = 0)
+ {
+ init(&modem, mux);
+ }
+
+ bool init(TinyGsm* modem, uint8_t mux = 0)
+ {
+ this->at = modem;
+ this->mux = mux;
+ sock_connected = false;
+
+ at->sockets[mux] = this;
+
+ return true;
+ }
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ at->streamClear(); // Empty anything remaining in the buffer;
+ at->commandMode();
+ sock_connected = at->modemConnect(host, port, mux, false);
+ at->writeChanges();
+ at->exitCommand();
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ at->streamClear(); // Empty anything remaining in the buffer;
+ at->commandMode();
+ sock_connected = at->modemConnect(ip, port, mux, false);
+ at->writeChanges();
+ at->exitCommand();
+ return sock_connected;
+ }
+
+ // This is a hack to shut the socket by setting the timeout to zero and
+ // then sending an empty line to the server.
+ virtual void stop()
+ {
+ at->streamClear(); // Empty anything remaining in the buffer;
+ at->commandMode();
+ at->sendAT(GF("TM0")); // Set socket timeout to 0;
+ at->waitResponse();
+ at->writeChanges();
+ at->exitCommand();
+ at->modemSend("", 1, mux);
+ at->commandMode();
+ at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds;
+ at->waitResponse();
+ at->writeChanges();
+ at->exitCommand();
+ at->streamClear(); // Empty anything remaining in the buffer;
+ sock_connected = false;
+ }
+
+ virtual size_t write(const uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ //at->maintain();
+ return at->modemSend(buf, size, mux);
+ }
+
+ virtual size_t write(uint8_t c)
+ {
+ return write(&c, 1);
+ }
+
+ virtual int available()
+ {
+ TINY_GSM_YIELD();
+ return at->stream.available();
+ }
+
+ virtual int read(uint8_t *buf, size_t size)
+ {
+ TINY_GSM_YIELD();
+ return at->stream.readBytes(buf, size);
+ }
+
+ virtual int read()
+ {
+ TINY_GSM_YIELD();
+ return at->stream.read();
+ }
+
+ virtual int peek()
+ {
+ return at->stream.peek();
+ }
+ virtual void flush()
+ {
+ at->stream.flush();
+ }
+
+ virtual uint8_t connected()
+ {
+ if (available()) {
+ return true;
+ }
+ return sock_connected;
+ }
+ virtual operator bool()
+ {
+ return connected();
+ }
+
+ /*
+ * Extended API
+ */
+
+ String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ private:
+ TinyGsm* at;
+ uint8_t mux;
+ bool sock_connected;
+ };
+
+ class GsmClientSecure : public GsmClient
+ {
+ public:
+ GsmClientSecure() {}
+
+ GsmClientSecure(TinyGsm& modem, uint8_t mux = 1)
+ : GsmClient(modem, mux)
+ {}
+
+ public:
+ virtual int connect(const char *host, uint16_t port)
+ {
+ at->streamClear(); // Empty anything remaining in the buffer;
+ at->commandMode();
+ sock_connected = at->modemConnect(host, port, mux, true);
+ at->writeChanges();
+ at->exitCommand();
+ return sock_connected;
+ }
+
+ virtual int connect(IPAddress ip, uint16_t port)
+ {
+ at->streamClear(); // Empty anything remaining in the buffer;
+ at->commandMode();
+ sock_connected = at->modemConnect(ip, port, mux, true);
+ at->writeChanges();
+ at->exitCommand();
+ return sock_connected;
+ }
+ };
+
+public:
+
+ explicit TinyGsm(Stream& stream)
+ : stream(stream)
+ {
+ memset(sockets, 0, sizeof(sockets));
+ }
+
+ /*
+ * Basic functions
+ */
+ bool begin()
+ {
+ return init();
+ }
+
+ bool init()
+ {
+ guardTime = 1100;
+ commandMode();
+ sendAT(GF("AP0")); // Put in transparent mode
+ waitResponse();
+ sendAT(GF("GT64")); // shorten the guard time to 100ms
+ waitResponse();
+ writeChanges();
+ sendAT(GF("HS")); // Get the "Hardware Series"; 0x601 for S6B (Wifi)
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ String res = streamReadUntil('\r'); // Does not send an OK, just the result
+ exitCommand();
+ if (res == "601") {
+ beeType = S6B;
+ } else {
+ beeType = LTEC1;
+ }
+ guardTime = 125;
+ return true;
+ }
+
+ bool testAT(unsigned long timeout = 10000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (commandMode()) {
+ sendAT();
+ if (waitResponse(200) == 1) {
+ return true;
+ }
+ exitCommand();
+ }
+ delay(100);
+ }
+ return false;
+ }
+
+ void maintain() {}
+
+ bool factoryDefault()
+ {
+ commandMode();
+ sendAT(GF("RE"));
+ bool ret_val = waitResponse() == 1;
+ writeChanges();
+ exitCommand();
+ return ret_val;
+ }
+
+ bool hasSSL()
+ {
+ if (beeType == S6B) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /*
+ * Power functions
+ */
+
+ bool restart()
+ {
+ commandMode();
+ sendAT(GF("FR"));
+ if (waitResponse() != 1) {
+ return false;
+ }
+ delay (2000); // Actually resets about 2 seconds later
+ for (unsigned long start = millis(); millis() - start < 60000L; ) {
+ if (commandMode()) {
+ exitCommand();
+ return true;
+ }
+ }
+ exitCommand();
+ return false;;
+ }
+
+ void setupPinSleep()
+ {
+ commandMode();
+ sendAT(GF("SM"),1);
+ waitResponse();
+ if (beeType == S6B) {
+ sendAT(GF("SO"),200);
+ waitResponse();
+ }
+ writeChanges();
+ exitCommand();
+ }
+
+ /*
+ * SIM card functions
+ */
+
+ bool simUnlock(const char *pin) // Not supported
+ {
+ return false;
+ }
+
+ String getSimCCID()
+ {
+ commandMode();
+ sendAT(GF("S#"));
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ String res = streamReadUntil('\r'); // Does not send an OK, just the result
+ exitCommand();
+ return res;
+ }
+
+ String getIMEI()
+ {
+ commandMode();
+ sendAT(GF("IM"));
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ String res = streamReadUntil('\r'); // Does not send an OK, just the result
+ exitCommand();
+ return res;
+ }
+
+ SimStatus getSimStatus(unsigned long timeout = 10000L)
+ {
+ return SIM_READY; // unsupported
+ }
+
+ RegStatus getRegistrationStatus()
+ {
+ commandMode();
+ sendAT(GF("AI"));
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ String res = streamReadUntil('\r'); // Does not send an OK, just the result
+ exitCommand();
+
+ if(res == GF("0")) {
+ return REG_OK_HOME;
+ }
+
+ else if(res == GF("13") || res == GF("2A")) {
+ return REG_UNREGISTERED;
+ }
+
+ else if(res == GF("FF") || res == GF("22") || res == GF("23") ||
+ res == GF("40") || res == GF("41") || res == GF("42")) {
+ return REG_SEARCHING;
+ }
+
+ else if(res == GF("24") || res == GF("25") || res == GF("27")) {
+ return REG_DENIED;
+ }
+
+ else {
+ return REG_UNKNOWN;
+ }
+ }
+
+ String getOperator()
+ {
+ commandMode();
+ sendAT(GF("MN"));
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ String res = streamReadUntil('\r'); // Does not send an OK, just the result
+ exitCommand();
+ return res;
+ }
+
+ /*
+ * Generic network functions
+ */
+
+ int getSignalQuality()
+ {
+ commandMode();
+ if (beeType == S6B) {
+ sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity
+ } else {
+ sendAT(GF("DB")); // ask for the cell strength in dBm
+ }
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (!stream.available() && millis() - startMillis < 1000) {};
+ char buf[2] = {0}; // Set up buffer for response
+ buf[0] = streamRead();
+ buf[1] = streamRead();
+ // DBG(buf[0], buf[1], "\n");
+ exitCommand();
+ int intr = strtol(buf, 0, 16);
+ if (beeType == S6B) {
+ return -93 + intr; // the maximum sensitivity is -93dBm
+ } else {
+ return -1*intr; // need to convert to negative number
+ }
+ }
+
+ bool isNetworkConnected()
+ {
+ RegStatus s = getRegistrationStatus();
+ return (s == REG_OK_HOME || s == REG_OK_ROAMING);
+ }
+
+ bool waitForNetwork(unsigned long timeout = 60000L)
+ {
+ for (unsigned long start = millis(); millis() - start < timeout; ) {
+ if (isNetworkConnected()) {
+ return true;
+ }
+ delay(250);
+ }
+ return false;
+ }
+
+ /*
+ * WiFi functions
+ */
+ bool networkConnect(const char* ssid, const char* pwd)
+ {
+
+ commandMode();
+
+ sendAT(GF("EE"), 2); // Set security to WPA2
+ waitResponse();
+
+ sendAT(GF("ID"), ssid);
+ if (waitResponse() != 1) {
+ goto fail;
+ }
+
+ sendAT(GF("PK"), pwd);
+ if (waitResponse() != 1) {
+ goto fail;
+ }
+
+ writeChanges();
+ exitCommand();
+
+ return true;
+
+fail:
+ exitCommand();
+ return false;
+ }
+
+ bool networkDisconnect()
+ {
+ return false; // Doesn't support disconnecting
+ }
+
+ String getLocalIP()
+ {
+ commandMode();
+ sendAT(GF("MY"));
+ String IPaddr;
+ IPaddr.reserve(16);
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (stream.available() < 8 && millis() - startMillis < 30000) {};
+ IPaddr = streamReadUntil('\r'); // read result
+ return IPaddr;
+ }
+
+ IPAddress localIP()
+ {
+ return TinyGsmIpFromString(getLocalIP());
+ }
+
+ /*
+ * GPRS functions
+ */
+ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
+ {
+ commandMode();
+ sendAT(GF("AN"), apn); // Set the APN
+ waitResponse();
+ writeChanges();
+ exitCommand();
+ return true;
+ }
+
+ bool gprsDisconnect() // TODO
+ {
+ return false;
+ }
+
+ /*
+ * Messaging functions
+ */
+
+ String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
+
+ bool sendSMS(const String& number, const String& text)
+ {
+ commandMode();
+ sendAT(GF("IP"), 2); // Put in text messaging mode
+ waitResponse();
+ sendAT(GF("PH"), number); // Set the phone number
+ waitResponse();
+ sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return)
+ waitResponse();
+ writeChanges();
+ exitCommand();
+ stream.print(text);
+ stream.write((char)0x0D); // close off with the carriage return
+ return true;
+ }
+
+
+private:
+
+ int modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false)
+ {
+ sendAT(GF("LA"), host);
+ String strIP;
+ strIP.reserve(16);
+ // wait for the response
+ unsigned long startMillis = millis();
+ while (stream.available() < 8 && millis() - startMillis < 30000) {};
+ strIP = streamReadUntil('\r'); // read result
+ IPAddress ip = TinyGsmIpFromString(strIP);
+ return modemConnect(ip, port, mux, ssl);
+ }
+
+ int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false)
+ {
+ String host;
+ host.reserve(16);
+ host += ip[0];
+ host += ".";
+ host += ip[1];
+ host += ".";
+ host += ip[2];
+ host += ".";
+ host += ip[3];
+ if (ssl) {
+ sendAT(GF("IP"), 4); // Put in TCP mode
+ waitResponse();
+ } else {
+ sendAT(GF("IP"), 1); // Put in TCP mode
+ waitResponse();
+ }
+ sendAT(GF("DL"), host); // Set the "Destination Address Low"
+ waitResponse();
+ sendAT(GF("DE"), String(port, HEX)); // Set the destination port
+ int rsp = waitResponse();
+ return rsp;
+ }
+
+ int modemSend(const void* buff, size_t len, uint8_t mux = 0)
+ {
+ stream.write((uint8_t*)buff, len);
+ stream.flush();
+ return len;
+ }
+
+ bool modemGetConnected(uint8_t mux = 0)
+ {
+ commandMode();
+ sendAT(GF("AI"));
+ int res = waitResponse(GF("0"));
+ exitCommand();
+ return 1 == res;
+ }
+
+public:
+
+ /* Utilities */
+
+ template
+ void streamWrite(T last)
+ {
+ stream.print(last);
+ }
+
+ template
+ void streamWrite(T head, Args... tail)
+ {
+ stream.print(head);
+ streamWrite(tail...);
+ }
+
+ int streamRead()
+ {
+ return stream.read();
+ }
+
+ String streamReadUntil(char c)
+ {
+ TINY_GSM_YIELD();
+ String return_string = stream.readStringUntil(c);
+ return_string.trim();
+ // DBG(return_string, c);
+ return return_string;
+ }
+
+ void streamClear(void)
+ {
+ while (stream.available()) {
+ streamRead();
+ }
+ }
+
+ bool commandMode(void)
+ {
+ delay(guardTime); // cannot send anything for 1 second before entering command mode
+ streamWrite(GF("+++")); // enter command mode
+ // DBG("\r\n+++\r\n");
+ return 1 == waitResponse(guardTime*2);
+ }
+
+ void writeChanges(void)
+ {
+ sendAT(GF("WR")); // Write changes to flash
+ waitResponse();
+ sendAT(GF("AC")); // Apply changes
+ waitResponse();
+ }
+
+ void exitCommand(void)
+ {
+ sendAT(GF("CN")); // Exit command mode
+ waitResponse();
+ }
+
+ template
+ void sendAT(Args... cmd)
+ {
+ streamWrite("AT", cmd..., GSM_NL);
+ stream.flush();
+ TINY_GSM_YIELD();
+ //DBG("### AT:", cmd...);
+ }
+
+ // TODO: Optimize this!
+ uint8_t waitResponse(uint32_t timeout, String& data,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ /*String r1s(r1); r1s.trim();
+ String r2s(r2); r2s.trim();
+ String r3s(r3); r3s.trim();
+ String r4s(r4); r4s.trim();
+ String r5s(r5); r5s.trim();
+ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
+ data.reserve(64);
+ int index = 0;
+ unsigned long startMillis = millis();
+ do {
+ TINY_GSM_YIELD();
+ while (stream.available() > 0) {
+ int a = streamRead();
+ if (a <= 0) {
+ continue; // Skip 0x00 bytes, just in case
+ }
+ data += (char)a;
+ if (r1 && data.endsWith(r1)) {
+ index = 1;
+ goto finish;
+ } else if (r2 && data.endsWith(r2)) {
+ index = 2;
+ goto finish;
+ } else if (r3 && data.endsWith(r3)) {
+ index = 3;
+ goto finish;
+ } else if (r4 && data.endsWith(r4)) {
+ index = 4;
+ goto finish;
+ } else if (r5 && data.endsWith(r5)) {
+ index = 5;
+ goto finish;
+ }
+ }
+ } while (millis() - startMillis < timeout);
+finish:
+ if (!index) {
+ data.trim();
+ data.replace(GSM_NL GSM_NL, GSM_NL);
+ data.replace(GSM_NL, "\r\n" " ");
+ if (data.length()) {
+ DBG("### Unhandled:", data, "\r\n");
+ } else {
+ DBG("### NO RESPONSE!\r\n");
+ }
+ } else {
+ data.trim();
+ data.replace(GSM_NL GSM_NL, GSM_NL);
+ data.replace(GSM_NL, "\r\n ");
+ if (data.length()) {
+ // DBG("<<< ", data);
+ }
+ }
+ return index;
+ }
+
+ uint8_t waitResponse(uint32_t timeout,
+ GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ String data;
+ return waitResponse(timeout, data, r1, r2, r3, r4, r5);
+ }
+
+ uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
+ GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
+ {
+ return waitResponse(1000, r1, r2, r3, r4, r5);
+ }
+
+public:
+ Stream& stream;
+
+protected:
+ int guardTime;
+ XBeeType beeType;
+ GsmClient* sockets[TINY_GSM_MUX_COUNT];
+};
+
+#endif
diff --git a/drivers/TinyGSM/TinyGsmCommon.h b/drivers/TinyGSM/TinyGsmCommon.h
new file mode 100644
index 000000000..458cc90f5
--- /dev/null
+++ b/drivers/TinyGSM/TinyGsmCommon.h
@@ -0,0 +1,195 @@
+/**
+ * file TinyGsmCommon.h
+ * author Volodymyr Shymanskyy
+ * license LGPL-3.0
+ * copyright Copyright (c) 2016 Volodymyr Shymanskyy
+ * date Nov 2016
+ */
+
+#ifndef TinyGsmCommon_h
+#define TinyGsmCommon_h
+
+#if defined(SPARK) || defined(PARTICLE)
+#include "Particle.h"
+#elif defined(ARDUINO)
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#endif
+
+#include
+#include "TinyGsmFifo.h"
+
+#ifndef TINY_GSM_YIELD
+#define TINY_GSM_YIELD() { delay(0); }
+#endif
+
+#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type")))
+#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
+
+#if defined(__AVR__)
+#define TINY_GSM_PROGMEM PROGMEM
+typedef const __FlashStringHelper* GsmConstStr;
+#define GFP(x) (reinterpret_cast(x))
+#define GF(x) F(x)
+#else
+#define TINY_GSM_PROGMEM
+typedef const char* GsmConstStr;
+#define GFP(x) x
+#define GF(x) x
+#endif
+
+#ifdef TINY_GSM_DEBUG
+namespace
+{
+template
+static void DBG(T last)
+{
+ TINY_GSM_DEBUG.println(last);
+}
+
+template
+static void DBG(T head, Args... tail)
+{
+ TINY_GSM_DEBUG.print(head);
+ TINY_GSM_DEBUG.print(' ');
+ DBG(tail...);
+}
+}
+#else
+#define DBG(...)
+#endif
+
+template
+const T& TinyGsmMin(const T& a, const T& b)
+{
+ return (b < a) ? b : a;
+}
+
+template
+const T& TinyGsmMax(const T& a, const T& b)
+{
+ return (b < a) ? a : b;
+}
+
+template
+uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200)
+{
+ static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 };
+
+ for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) {
+ uint32_t rate = rates[i];
+ if (rate < minimum || rate > maximum) {
+ continue;
+ }
+
+ DBG("Trying baud rate", rate, "...");
+ SerialAT.begin(rate);
+ delay(10);
+ for (int i=0; i<3; i++) {
+ SerialAT.print("AT\r\n");
+ String input = SerialAT.readString();
+ if (input.indexOf("OK") >= 0) {
+ DBG("Modem responded at rate", rate);
+ return rate;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline
+IPAddress TinyGsmIpFromString(const String& strIP)
+{
+ int Parts[4] = {0, };
+ int Part = 0;
+ for (uint8_t i=0; i 3) {
+ return IPAddress(0,0,0,0);
+ }
+ continue;
+ } else if (c >= '0' && c <= '9') {
+ Parts[Part] *= 10;
+ Parts[Part] += c - '0';
+ } else {
+ if (Part == 3) {
+ break;
+ }
+ }
+ }
+ return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
+}
+
+static inline
+String TinyGsmDecodeHex7bit(String &instr)
+{
+ String result;
+ byte reminder = 0;
+ int bitstate = 7;
+ for (unsigned i=0; i> bitstate;
+ bitstate--;
+ if (bitstate == 0) {
+ char c = reminder;
+ result += c;
+ reminder = 0;
+ bitstate = 7;
+ }
+ }
+ return result;
+}
+
+static inline
+String TinyGsmDecodeHex8bit(String &instr)
+{
+ String result;
+ for (unsigned i=0; i
+
+class TinyGsmFifo
+{
+public:
+
+ TinyGsmFifo()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ _r = 0;
+ _w = 0;
+ }
+
+ // writing thread/context API
+ //-------------------------------------------------------------
+
+ bool writeable(void)
+ {
+ return free() > 0;
+ }
+
+ int free(void)
+ {
+ int s = _r - _w;
+ if (s <= 0) {
+ s += N;
+ }
+ return s - 1;
+ }
+
+ bool put(const T& c)
+ {
+ int i = _w;
+ int j = i;
+ i = _inc(i);
+ if (i == _r) { // !writeable()
+ return false;
+ }
+ _b[j] = c;
+ _w = i;
+ return true;
+ }
+
+ int put(const T* p, int n, bool t = false)
+ {
+ int c = n;
+ while (c) {
+ int f;
+ while ((f = free()) == 0) { // wait for space
+ if (!t) {
+ return n - c; // no more space and not blocking
+ }
+ /* nothing / just wait */;
+ }
+ // check free space
+ if (c < f) {
+ f = c;
+ }
+ int w = _w;
+ int m = N - w;
+ // check wrap
+ if (f > m) {
+ f = m;
+ }
+ memcpy(&_b[w], p, f);
+ _w = _inc(w, f);
+ c -= f;
+ p += f;
+ }
+ return n - c;
+ }
+
+ // reading thread/context API
+ // --------------------------------------------------------
+
+ bool readable(void)
+ {
+ return (_r != _w);
+ }
+
+ size_t size(void)
+ {
+ int s = _w - _r;
+ if (s < 0) {
+ s += N;
+ }
+ return s;
+ }
+
+ bool get(T* p)
+ {
+ int r = _r;
+ if (r == _w) { // !readable()
+ return false;
+ }
+ *p = _b[r];
+ _r = _inc(r);
+ return true;
+ }
+
+ int get(T* p, int n, bool t = false)
+ {
+ int c = n;
+ while (c) {
+ int f;
+ for (;;) { // wait for data
+ f = size();
+ if (f) {
+ break; // free space
+ }
+ if (!t) {
+ return n - c; // no space and not blocking
+ }
+ /* nothing / just wait */;
+ }
+ // check available data
+ if (c < f) {
+ f = c;
+ }
+ int r = _r;
+ int m = N - r;
+ // check wrap
+ if (f > m) {
+ f = m;
+ }
+ memcpy(p, &_b[r], f);
+ _r = _inc(r, f);
+ c -= f;
+ p += f;
+ }
+ return n - c;
+ }
+
+private:
+ int _inc(int i, int n = 1)
+ {
+ return (i + n) % N;
+ }
+
+ T _b[N];
+ int _w;
+ int _r;
+};
+
+#endif
diff --git a/drivers/TinyGSM/keywords.txt b/drivers/TinyGSM/keywords.txt
new file mode 100644
index 000000000..33f98c429
--- /dev/null
+++ b/drivers/TinyGSM/keywords.txt
@@ -0,0 +1,26 @@
+#######################################
+# Data types (KEYWORD1)
+#######################################
+TinyGsm KEYWORD1
+TinyGsmClient KEYWORD1
+TinyGsmClientSecure KEYWORD1
+
+SerialAT KEYWORD1
+SerialMon KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+begin KEYWORD2
+restart KEYWORD2
+waitForNetwork KEYWORD2
+getSimStatus KEYWORD2
+gprsConnect KEYWORD2
+gprsDisconnect KEYWORD2
+isGprsConnected KEYWORD2
+isNetworkConnected KEYWORD2
+factoryReset KEYWORD2
+
+#######################################
+# Literals (LITERAL1)
+#######################################
diff --git a/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino
index 998627221..ca3a59d90 100644
--- a/examples/AirQualitySensor/AirQualitySensor.ino
+++ b/examples/AirQualitySensor/AirQualitySensor.ino
@@ -53,10 +53,10 @@
//which is derived from the chart in datasheet
/***********************Software Related Macros************************************/
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
-#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
-//cablibration phase
+#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interval(in milliseconds) between each samples in the
+//calibration phase
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
-#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
+#define READ_SAMPLE_TIMES (5) //define the time interval(in milliseconds) between each samples in
//normal operation
/**********************Application Related Macros**********************************/
#define GAS_LPG (0)
@@ -165,8 +165,8 @@ float MQCalibration(int mq_pin)
/***************************** MQRead *********************************************
Input: mq_pin - analog channel
Output: Rs of the sensor
-Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
- The Rs changes as the sensor is in the different consentration of the target
+Remarks: This function use MQResistanceCalculation to calculate the sensor resistance (Rs).
+ The Rs changes as the sensor is in the different concentration of the target
gas. The sample times and the time interval between samples could be configured
by changing the definition of the macros.
************************************************************************************/
diff --git a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
index 8ba3e011c..c02262a86 100644
--- a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
+++ b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
@@ -23,7 +23,7 @@
* Interrupt driven binary switch example with dual interrupts
* Author: Patrick 'Anticimex' Fallberg
* Connect one button or door/window reed switch between
- * digitial I/O pin 3 (BUTTON_PIN below) and GND and the other
+ * digital I/O pin 3 (BUTTON_PIN below) and GND and the other
* one in similar fashion on digital I/O pin 2.
* This example is designed to fit Arduino Nano/Pro Mini
*
diff --git a/examples/CO2Sensor/CO2Sensor.ino b/examples/CO2Sensor/CO2Sensor.ino
index 7b3bf2e1d..f19940a32 100644
--- a/examples/CO2Sensor/CO2Sensor.ino
+++ b/examples/CO2Sensor/CO2Sensor.ino
@@ -28,7 +28,7 @@
* Pad 6: PWM output ==> pin 6
*
* From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html
- * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm.
+ * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accuracy of ±200ppm.
* The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula:
* CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms)
* From: http://airqualityegg.wikispaces.com/Sensor+Tests
@@ -95,7 +95,7 @@ void loop()
long co2ppm = 2 * ((duration/1000) - 2);
//Serial.print(co2ppm);
if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) {
- send(msg.set((long)ceil(co2ppm)));
+ send(msg.set((int32_t)ceil(co2ppm)));
lastAIQ = ceil(co2ppm);
}
diff --git a/examples/DimmableLEDActuator/DimmableLEDActuator.ino b/examples/DimmableLEDActuator/DimmableLEDActuator.ino
index d64de95b4..167be9da2 100644
--- a/examples/DimmableLEDActuator/DimmableLEDActuator.ino
+++ b/examples/DimmableLEDActuator/DimmableLEDActuator.ino
@@ -62,7 +62,7 @@ MyMessage lightMsg(0, V_LIGHT);
*/
void setup()
{
- // Pull the gateway's current dim level - restore light level upon sendor node power-up
+ // Pull the gateway's current dim level - restore light level upon node power-up
request( 0, V_DIMMER );
}
diff --git a/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino
index 4d18d6cf0..c67b6a9bb 100644
--- a/examples/DimmableLight/DimmableLight.ino
+++ b/examples/DimmableLight/DimmableLight.ino
@@ -48,7 +48,7 @@
#define LIGHT_OFF 0
#define LIGHT_ON 1
-#define SN "Dimable Light"
+#define SN "Dimmable Light"
#define SV "1.0"
int16_t LastLightState=LIGHT_OFF;
@@ -70,7 +70,7 @@ void setup()
}
}
- //Here you actualy switch on/off the light with the last known dim level
+ //Here you actually switch on/off the light with the last known dim level
SetCurrentState2Hardware();
Serial.println( "Node ready to receive messages..." );
diff --git a/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino
index 1ccf55230..eb250ac42 100644
--- a/examples/DustSensor/DustSensor.ino
+++ b/examples/DustSensor/DustSensor.ino
@@ -83,7 +83,7 @@ void loop()
// recover voltage
calcVoltage = voMeasured * (5.0 / 1024.0);
- // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/
+ // linear equation taken from http://www.howmuchsnow.com/arduino/airquality/
// Chris Nafis (c) 2012
dustDensity = (0.17 * calcVoltage - 0.1)*1000;
diff --git a/examples/DustSensorDSM/DustSensorDSM.ino b/examples/DustSensorDSM/DustSensorDSM.ino
index 75649731b..418c7ae28 100644
--- a/examples/DustSensorDSM/DustSensorDSM.ino
+++ b/examples/DustSensorDSM/DustSensorDSM.ino
@@ -95,7 +95,7 @@ void loop()
Serial.print("\n");
if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) {
- send(dustMsgPM25.set((long)ceil(concentrationPM25)));
+ send(dustMsgPM25.set((int32_t)ceil(concentrationPM25)));
lastDUSTPM25 = ceil(concentrationPM25);
}
@@ -110,7 +110,7 @@ void loop()
long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01;
if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) {
- send(dustMsgPM10.set((long)ppmv));
+ send(dustMsgPM10.set((int32_t)ppmv));
lastDUSTPM10 = ceil(concentrationPM10);
}
diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
index f14a1cfcf..94862608e 100644
--- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
+++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
@@ -19,18 +19,18 @@
*******************************
*
* REVISION HISTORY
- * Version 1.0 - Henrik EKblad
+ * Version 1.0 - Henrik Ekblad
*
* DESCRIPTION
- * This sketch provides an example how to implement a distance sensor using HC-SR04
- * Use this sensor to measure KWH and Watt of your house meeter
- * You need to set the correct pulsefactor of your meeter (blinks per KWH).
- * The sensor starts by fetching current KWH value from gateway.
- * Reports both KWH and Watt back to gateway.
+ * This sketch provides an example how to implement a LM393 PCB
+ * Use this sensor to measure kWh and Watt of your house meter
+ * You need to set the correct pulsefactor of your meter (blinks per kWh).
+ * The sensor starts by fetching current kWh value from gateway.
+ * Reports both kWh and Watt back to gateway.
*
* Unfortunately millis() won't increment when the Arduino is in
* sleepmode. So we cannot make this sensor sleep if we also want
- * to calculate/report watt-number.
+ * to calculate/report watt value.
* http://www.mysensors.org/build/pulse_power
*/
@@ -46,13 +46,13 @@
#include
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!)
-#define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter
-#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false.
-#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers.
+#define PULSE_FACTOR 1000 // Number of blinks per of your meter
+#define SLEEP_MODE false // Watt value can only be reported when sleep mode is false.
+#define MAX_WATT 10000 // Max watt value to report. This filters outliers.
#define CHILD_ID 1 // Id of the sensor child
uint32_t SEND_FREQUENCY =
- 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
+ 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway.
double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour
bool pcReceived = false;
volatile uint32_t pulseCount = 0;
@@ -60,10 +60,10 @@ volatile uint32_t lastBlink = 0;
volatile uint32_t watt = 0;
uint32_t oldPulseCount = 0;
uint32_t oldWatt = 0;
-double oldKwh;
+double oldkWh;
uint32_t lastSend;
MyMessage wattMsg(CHILD_ID,V_WATT);
-MyMessage kwhMsg(CHILD_ID,V_KWH);
+MyMessage kWhMsg(CHILD_ID,V_KWH);
MyMessage pcMsg(CHILD_ID,V_VAR1);
@@ -97,8 +97,8 @@ void loop()
if (pcReceived && (SLEEP_MODE || sendTime)) {
// New watt value has been calculated
if (!SLEEP_MODE && watt != oldWatt) {
- // Check that we dont get unresonable large watt value.
- // could hapen when long wraps or false interrupt triggered
+ // Check that we don't get unreasonable large watt value.
+ // could happen when long wraps or false interrupt triggered
if (watt<((uint32_t)MAX_WATT)) {
send(wattMsg.set(watt)); // Send watt value to gw
}
@@ -107,19 +107,19 @@ void loop()
oldWatt = watt;
}
- // Pulse cout has changed
+ // Pulse count value has changed
if (pulseCount != oldPulseCount) {
send(pcMsg.set(pulseCount)); // Send pulse count value to gw
- double kwh = ((double)pulseCount/((double)PULSE_FACTOR));
+ double kWh = ((double)pulseCount/((double)PULSE_FACTOR));
oldPulseCount = pulseCount;
- if (kwh != oldKwh) {
- send(kwhMsg.set(kwh, 4)); // Send kwh value to gw
- oldKwh = kwh;
+ if (kWh != oldkWh) {
+ send(kWhMsg.set(kWh, 4)); // Send kWh value to gw
+ oldkWh = kWh;
}
}
lastSend = now;
} else if (sendTime && !pcReceived) {
- // No count received. Try requesting it again
+ // No pulse count value received. Try requesting it again
request(CHILD_ID, V_VAR1);
lastSend=now;
}
@@ -133,7 +133,7 @@ void receive(const MyMessage &message)
{
if (message.type==V_VAR1) {
pulseCount = oldPulseCount = message.getLong();
- Serial.print("Received last pulse count from gw:");
+ Serial.print("Received last pulse count value from gw:");
Serial.println(pulseCount);
pcReceived = true;
}
@@ -151,4 +151,4 @@ void onPulse()
lastBlink = newBlink;
}
pulseCount++;
-}
\ No newline at end of file
+}
diff --git a/examples/GatewayESP32/GatewayESP32.ino b/examples/GatewayESP32/GatewayESP32.ino
new file mode 100644
index 000000000..c2d1f9954
--- /dev/null
+++ b/examples/GatewayESP32/GatewayESP32.ino
@@ -0,0 +1,76 @@
+/**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ *******************************
+ *
+ * REVISION HISTORY
+ * Version 1.0 - tekka
+ *
+ * DESCRIPTION
+ * The ESP32 gateway sends data received from sensors to the WiFi link.
+ * The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
+ *
+ * Make sure to fill in your ssid and WiFi password below.
+ */
+
+// Enable debug prints to serial monitor
+#define MY_DEBUG
+
+// Enables and select radio type (if attached)
+#define MY_RADIO_RF24
+//#define MY_RADIO_RFM69
+//#define MY_RADIO_RFM95
+
+#define MY_GATEWAY_ESP32
+
+#define MY_WIFI_SSID "MySSID"
+#define MY_WIFI_PASSWORD "MyVerySecretPassword"
+
+// Set the hostname for the WiFi Client. This is the hostname
+// it will pass to the DHCP server if not static.
+#define MY_HOSTNAME "ESP32_GW"
+
+// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
+//#define MY_IP_ADDRESS 192,168,1,100
+
+// If using static ip you can define Gateway and Subnet address as well
+//#define MY_IP_GATEWAY_ADDRESS 192,168,1,1
+//#define MY_IP_SUBNET_ADDRESS 255,255,255,0
+
+// The port to keep open on node server mode
+#define MY_PORT 5003
+
+// How many clients should be able to connect to this gateway (default 1)
+#define MY_GATEWAY_MAX_CLIENTS 2
+
+#include
+
+void setup()
+{
+ // Setup locally attached sensors
+}
+
+void presentation()
+{
+ // Present locally attached sensors here
+}
+
+void loop()
+{
+ // Send locally attached sensors data here
+}
diff --git a/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino
new file mode 100644
index 000000000..9783ddd2d
--- /dev/null
+++ b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino
@@ -0,0 +1,90 @@
+/**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ *******************************
+ *
+ * REVISION HISTORY
+ * Version 1.0 - tekka
+ *
+ * DESCRIPTION
+ * The ESP32 gateway sends data received from sensors to the WiFi link.
+ * The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
+ *
+ * Make sure to fill in your ssid and WiFi password below.
+ */
+
+// Enable debug prints to serial monitor
+#define MY_DEBUG
+
+// Enables and select radio type (if attached)
+#define MY_RADIO_RF24
+//#define MY_RADIO_RFM69
+//#define MY_RADIO_RFM95
+
+#define MY_GATEWAY_MQTT_CLIENT
+#define MY_GATEWAY_ESP32
+
+// Set this node's subscribe and publish topic prefix
+#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
+#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
+
+// Set MQTT client id
+#define MY_MQTT_CLIENT_ID "mysensors-1"
+
+// Enable these if your MQTT broker requires usenrame/password
+//#define MY_MQTT_USER "username"
+//#define MY_MQTT_PASSWORD "password"
+
+// Set WIFI SSID and password
+#define MY_WIFI_SSID "MySSID"
+#define MY_WIFI_PASSWORD "MyVerySecretPassword"
+
+// Set the hostname for the WiFi Client. This is the hostname
+// it will pass to the DHCP server if not static.
+#define MY_HOSTNAME "ESP32_MQTT_GW"
+
+// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
+//#define MY_IP_ADDRESS 192,168,178,87
+
+// If using static ip you can define Gateway and Subnet address as well
+//#define MY_IP_GATEWAY_ADDRESS 192,168,178,1
+//#define MY_IP_SUBNET_ADDRESS 255,255,255,0
+
+// MQTT broker ip address.
+#define MY_CONTROLLER_IP_ADDRESS 192, 168, 1, 5
+
+// The MQTT broker port to to open
+#define MY_PORT 1883
+
+#include
+
+void setup()
+{
+ // Setup locally attached sensors
+}
+
+void presentation()
+{
+ // Present locally attached sensors here
+}
+
+void loop()
+{
+ // Send locally attech sensors data here
+}
+
diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino
index b8c277b64..32bbf332f 100644
--- a/examples/GatewayESP8266/GatewayESP8266.ino
+++ b/examples/GatewayESP8266/GatewayESP8266.ino
@@ -30,35 +30,21 @@
*
* VERA CONFIGURATION:
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
- * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
+ * E.g. If you want to use the default values in this sketch enter: 192.168.178.66:5003
*
* LED purposes:
* - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs in your sketch, only the LEDs that is defined is used.
- * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
- * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ * - ERR (red) - fast blink on error during transmission error or receive crc error
*
- * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
- * nRF24L01+ ESP8266
- * VCC VCC
- * CE GPIO4
- * CSN/CS GPIO15
- * SCK GPIO14
- * MISO GPIO12
- * MOSI GPIO13
- * GND GND
+ * See https://www.mysensors.org/build/connect_radio for wiring instructions.
*
- * Not all ESP8266 modules have all pins available on their external interface.
- * This code has been tested on an ESP-12 module.
- * The ESP8266 requires a certain pin configuration to download code, and another one to run code:
- * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
- * - Connect GPIO15 via 10K pulldown resistor to GND
- * - Connect CH_PD via 10K resistor to VCC
- * - Connect GPIO2 via 10K resistor to VCC
- * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
+ * If you are using a "barebone" ESP8266, see
+ * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266
*
- * Inclusion mode button:
- * - Connect GPIO5 via switch to GND ('inclusion switch')
+ * Inclusion mode button:
+ * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch')
*
* Hardware SHA204 signing is currently not supported!
*
@@ -78,15 +64,15 @@
#define MY_GATEWAY_ESP8266
-#define MY_ESP8266_SSID "MySSID"
-#define MY_ESP8266_PASSWORD "MyVerySecretPassword"
+#define MY_WIFI_SSID "MySSID"
+#define MY_WIFI_PASSWORD "MyVerySecretPassword"
// Enable UDP communication
//#define MY_USE_UDP // If using UDP you need to set MY_CONTROLLER_IP_ADDRESS below
// Set the hostname for the WiFi Client. This is the hostname
// it will pass to the DHCP server if not static.
-//#define MY_ESP8266_HOSTNAME "sensor-gateway"
+//#define MY_HOSTNAME "sensor-gateway"
// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
//#define MY_IP_ADDRESS 192,168,178,87
@@ -113,7 +99,7 @@
// Set inclusion mode duration (in seconds)
//#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
-//#define MY_INCLUSION_MODE_BUTTON_PIN 3
+//#define MY_INCLUSION_MODE_BUTTON_PIN D1
// Set blinking period
//#define MY_DEFAULT_LED_BLINK_PERIOD 300
diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
index 0cc91cade..f517cb5a1 100644
--- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
+++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
@@ -27,30 +27,17 @@
*
* LED purposes:
* - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs in your sketch
- * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
- * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ * - ERR (red) - fast blink on error during transmission error or receive crc error
*
- * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
- * nRF24L01+ ESP8266
- * VCC VCC
- * CE GPIO4
- * CSN/CS GPIO15
- * SCK GPIO14
- * MISO GPIO12
- * MOSI GPIO13
+ * See https://www.mysensors.org/build/connect_radio for wiring instructions.
*
- * Not all ESP8266 modules have all pins available on their external interface.
- * This code has been tested on an ESP-12 module.
- * The ESP8266 requires a certain pin configuration to download code, and another one to run code:
- * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
- * - Connect GPIO15 via 10K pulldown resistor to GND
- * - Connect CH_PD via 10K resistor to VCC
- * - Connect GPIO2 via 10K resistor to VCC
- * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
+ * If you are using a "barebone" ESP8266, see
+ * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266
*
- * Inclusion mode button:
- * - Connect GPIO5 via switch to GND ('inclusion switch')
+ * Inclusion mode button:
+ * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch')
*
* Hardware SHA204 signing is currently not supported!
*
@@ -78,17 +65,17 @@
// Set MQTT client id
#define MY_MQTT_CLIENT_ID "mysensors-1"
-// Enable these if your MQTT broker requires usenrame/password
+// Enable these if your MQTT broker requires username/password
//#define MY_MQTT_USER "username"
//#define MY_MQTT_PASSWORD "password"
// Set WIFI SSID and password
-#define MY_ESP8266_SSID "MySSID"
-#define MY_ESP8266_PASSWORD "MyVerySecretPassword"
+#define MY_WIFI_SSID "MySSID"
+#define MY_WIFI_PASSWORD "MyVerySecretPassword"
// Set the hostname for the WiFi Client. This is the hostname
// it will pass to the DHCP server if not static.
-// #define MY_ESP8266_HOSTNAME "mqtt-sensor-gateway"
+// #define MY_HOSTNAME "mqtt-sensor-gateway"
// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
//#define MY_IP_ADDRESS 192,168,178,87
@@ -100,6 +87,9 @@
// MQTT broker ip address.
#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68
+//MQTT broker if using URL instead of ip address.
+// #define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org"
+
// The MQTT broker port to to open
#define MY_PORT 1883
@@ -110,7 +100,7 @@
// Set inclusion mode duration (in seconds)
//#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
-//#define MY_INCLUSION_MODE_BUTTON_PIN 3
+//#define MY_INCLUSION_MODE_BUTTON_PIN D1
// Set blinking period
//#define MY_DEFAULT_LED_BLINK_PERIOD 300
@@ -135,6 +125,6 @@ void presentation()
void loop()
{
- // Send locally attech sensors data here
+ // Send locally attached sensors data here
}
diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino
index 76badfd33..f83fe52e7 100644
--- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino
+++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino
@@ -31,34 +31,20 @@
*
* VERA CONFIGURATION:
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
- * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
+ * E.g. If you want to use the default values in this sketch enter: 192.168.178.66:5003
*
* LED purposes:
* - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
- * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
- * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ * - ERR (red) - fast blink on error during transmission error or receive crc error
*
- * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
- * nRF24L01+ ESP8266
- * VCC VCC
- * CE GPIO4
- * CSN/CS GPIO15
- * SCK GPIO14
- * MISO GPIO12
- * MOSI GPIO13
- * GND GND
+ * See https://www.mysensors.org/build/connect_radio for wiring instructions.
*
- * Not all ESP8266 modules have all pins available on their external interface.
- * This code has been tested on an ESP-12 module.
- * The ESP8266 requires a certain pin configuration to download code, and another one to run code:
- * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
- * - Connect GPIO15 via 10K pulldown resistor to GND
- * - Connect CH_PD via 10K resistor to VCC
- * - Connect GPIO2 via 10K resistor to VCC
- * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
+ * If you are using a "barebone" ESP8266, see
+ * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266
*
- * Inclusion mode button:
+ * Inclusion mode button:
* - Connect GPIO5 via switch to GND ('inclusion switch')
*
* Hardware SHA204 signing is currently not supported!
@@ -79,12 +65,12 @@
#define MY_GATEWAY_ESP8266
-#define MY_ESP8266_SSID "MySSID"
-#define MY_ESP8266_PASSWORD "MyVerySecretPassword"
+#define MY_WIFI_SSID "MySSID"
+#define MY_WIFI_PASSWORD "MyVerySecretPassword"
// Set the hostname for the WiFi Client. This is the hostname
// it will pass to the DHCP server if not static.
-// #define MY_ESP8266_HOSTNAME "sensor-ota-gateway"
+// #define MY_HOSTNAME "sensor-ota-gateway"
// Enable UDP communication
//#define MY_USE_UDP // If using UDP you need to set MY_CONTROLLER_IP_ADDRESS below
@@ -170,7 +156,7 @@ void presentation()
void loop()
{
- // Send locally attech sensors data here
+ // Send locally attached sensors data here
ArduinoOTA.handle();
}
diff --git a/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino b/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino
new file mode 100644
index 000000000..c9b572840
--- /dev/null
+++ b/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino
@@ -0,0 +1,137 @@
+/**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ *******************************
+ *
+ * REVISION HISTORY
+ * Version 1.0 - Rait Lotamõis
+ *
+ * DESCRIPTION
+ * The TinyGSM MQTT gateway sends radio network (or locally attached sensors) data to your MQTT broker using a GSM modem or optionally an ESP8266 as a WiFi modem.
+ * The node also listens to MY_MQTT_TOPIC_PREFIX and sends out those messages to the radio network
+ *
+ * LED purposes:
+ * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
+ * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
+ * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ */
+
+
+// Enable debug prints to serial monitor
+#define MY_DEBUG
+
+// Enables and select radio type (if attached)
+#define MY_RADIO_NRF24
+//#define MY_RADIO_RFM69
+//#define MY_RADIO_RFM95
+
+#define MY_GATEWAY_MQTT_CLIENT
+
+// Enable GSM modem support
+#define MY_GATEWAY_TINYGSM
+
+// Define your modem
+#define TINY_GSM_MODEM_SIM800
+// #define TINY_GSM_MODEM_SIM808
+// #define TINY_GSM_MODEM_SIM900
+// #define TINY_GSM_MODEM_A6
+// #define TINY_GSM_MODEM_A7
+// #define TINY_GSM_MODEM_M590
+// #define TINY_GSM_ESP8266
+
+// leave empty anything that does not apply
+#define MY_GSM_APN "internet"
+//#define MY_GSM_PIN "1234"
+#define MY_GSM_USR ""
+//If using a GSM modem, this stands for your GSM connection password. If using WiFi, it's your wireless password.
+#define MY_GSM_PSW ""
+//#define MY_GSM_SSID ""
+
+// Use Hardware Serial on Mega, Leonardo, Micro
+//#define SerialAT Serial1
+// or Software Serial on Uno, Nano
+#include
+#define MY_GSM_RX 4
+#define MY_GSM_TX 5
+
+// If your Mosquitto is old fashioned and does not support 3.1.1
+//#define MQTT_VERSION MQTT_VERSION_3_1
+
+// Set this node's subscribe and publish topic prefix
+#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
+#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
+
+// Set MQTT client id
+#define MY_MQTT_CLIENT_ID "mysensors-1"
+
+// Enable these if your MQTT broker requires usenrame/password
+//#define MY_MQTT_USER "username"
+//#define MY_MQTT_PASSWORD "password"
+
+// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
+//#define MY_IP_ADDRESS 192,168,32,220
+
+// If using static ip you can define Gateway and Subnet address as well
+//#define MY_IP_GATEWAY_ADDRESS 192,168,32,1
+//#define MY_IP_SUBNET_ADDRESS 255,255,255,0
+
+// MQTT broker ip address or url. Define one or the other.
+//#define MY_CONTROLLER_URL_ADDRESS "mymqttbroker.com"
+#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68
+
+// The MQTT broker port to to open
+#define MY_PORT 1883
+
+/*
+// Enable inclusion mode
+#define MY_INCLUSION_MODE_FEATURE
+// Enable Inclusion mode button on gateway
+//#define MY_INCLUSION_BUTTON_FEATURE
+// Set inclusion mode duration (in seconds)
+#define MY_INCLUSION_MODE_DURATION 60
+// Digital pin used for inclusion mode button
+//#define MY_INCLUSION_MODE_BUTTON_PIN 3
+
+// Set blinking period
+#define MY_DEFAULT_LED_BLINK_PERIOD 300
+
+// Flash leds on rx/tx/err
+// Uncomment to override default HW configurations
+//#define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin
+//#define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin
+//#define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED
+*/
+
+#include
+
+void setup()
+{
+ // Setup locally attached sensors
+}
+
+void presentation()
+{
+ // Present locally attached sensors here
+}
+
+void loop()
+{
+ // Send locally attached sensors data here
+}
+
diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino
index f7bc2f306..3913bc2bb 100644
--- a/examples/GatewaySerial/GatewaySerial.ino
+++ b/examples/GatewaySerial/GatewaySerial.ino
@@ -20,7 +20,7 @@
*
* DESCRIPTION
* The ArduinoGateway prints data received from sensors on the serial link.
-* The gateway accepts input on seral which will be sent out on radio network.
+* The gateway accepts input on serial which will be sent out on radio network.
*
* The GW code is designed for Arduino Nano 328p / 16MHz
*
@@ -30,9 +30,9 @@
*
* LEDs (OPTIONAL):
* - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs
-* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
-* - ERR (red) - fast blink on error during transmission error or recieve crc error
+* - ERR (red) - fast blink on error during transmission error or receive crc error
*
*/
@@ -53,7 +53,7 @@
// Enable serial gateway
#define MY_GATEWAY_SERIAL
-// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
+// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
#if F_CPU == 8000000L
#define MY_BAUD_RATE 38400
#endif
diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino
index 1cca1b0be..36750ebbc 100644
--- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino
+++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino
@@ -28,9 +28,9 @@
* - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series
*
* LEDs (OPTIONAL):
-* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
-* - ERR (red) - fast blink on error during transmission error or recieve crc error
+* - ERR (red) - fast blink on error during transmission error or receive crc error
*
* If your Arduino board has additional serial ports
* you can use to connect the RS485 module.
diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino
index f42352942..6d7a488c4 100644
--- a/examples/GatewayW5100/GatewayW5100.ino
+++ b/examples/GatewayW5100/GatewayW5100.ino
@@ -33,9 +33,9 @@
*
* LED purposes:
* - To use the feature, uncomment MY_DEFAULT_xxx_LED_PIN in the sketch below
- * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
- * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ * - ERR (red) - fast blink on error during transmission error or receive crc error
*
* See http://www.mysensors.org/build/ethernet_gateway for wiring instructions.
*
@@ -96,7 +96,7 @@
// The MAC address can be anything you want but should be unique on your network.
// Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use.
-// Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address.
+// Note that most of the Arduino examples use "DEAD BEEF FEED" for the MAC address.
#define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
// Enable inclusion mode
diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
index df270f7d1..3f1cad082 100644
--- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
+++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
@@ -27,9 +27,9 @@
*
* LED purposes:
* - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
- * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
- * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ * - ERR (red) - fast blink on error during transmission error or receive crc error
*
* See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
* nRF24L01+ ESP8266
@@ -96,7 +96,7 @@
#define MY_RF24_CS_PIN 6
#endif
-// Enable these if your MQTT broker requires usenrame/password
+// Enable these if your MQTT broker requires username/password
//#define MY_MQTT_USER "username"
//#define MY_MQTT_PASSWORD "password"
diff --git a/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino
index 505bc8c49..3716ffd36 100644
--- a/examples/LightSensor/LightSensor.ino
+++ b/examples/LightSensor/LightSensor.ino
@@ -22,7 +22,7 @@
* Version 1.0 - Henrik EKblad
*
* DESCRIPTION
- * Example sketch showing how to measue light level using a LM393 photo-resistor
+ * Example sketch showing how to measure light level using a LM393 photo-resistor
* http://www.mysensors.org/build/light
*/
diff --git a/examples/LogOTAGateway/LogOTAGateway.ino b/examples/LogOTAGateway/LogOTAGateway.ino
index 7d8a80a40..c1e62d75b 100644
--- a/examples/LogOTAGateway/LogOTAGateway.ino
+++ b/examples/LogOTAGateway/LogOTAGateway.ino
@@ -20,7 +20,7 @@
*
* DESCRIPTION
* The ArduinoGateway prints data received from sensors on the serial link.
-* The gateway accepts input on seral which will be sent out on radio network.
+* The gateway accepts input on serial which will be sent out on radio network.
*
* The GW code is designed for Arduino Nano 328p / 16MHz
*
@@ -30,9 +30,9 @@
*
* LEDs (OPTIONAL):
* - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs
-* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
-* - ERR (red) - fast blink on error during transmission error or recieve crc error
+* - ERR (red) - fast blink on error during transmission error or receive crc error
*
* OTA DEBUG MESSAGES
* - Add the OTADebugReceive(message) into receive(const MyMessage &message) on a serial connected node
@@ -59,7 +59,7 @@
// Enable serial gateway
#define MY_GATEWAY_SERIAL
-// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
+// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
#if F_CPU == 8000000L
#define MY_BAUD_RATE 38400
#endif
diff --git a/examples/LogOTANode/LogOTANode.ino b/examples/LogOTANode/LogOTANode.ino
index 891cd548e..aaf1384d2 100644
--- a/examples/LogOTANode/LogOTANode.ino
+++ b/examples/LogOTANode/LogOTANode.ino
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2015 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -67,8 +67,8 @@ void loop()
c++;
// A debug message
- DEBUG_OUTPUT(PSTR("DEBUG\nc=%" PRId16 "\nmillis=" PRId32 "\n"), c, hwMillis());
+ DEBUG_OUTPUT(PSTR("DEBUG\nc=%" PRId16 "\nmillis=%" PRId32 "\n"), c, hwMillis());
// Send a log message with ACK to a node
- OTALog(0, true, PSTR("LOG\nc=%" PRId16 "\nmillis=" PRId32 "\n"), c, hwMillis());
-}
+ OTALog(0, true, PSTR("LOG\nc=%" PRId16 "\nmillis=%" PRId32 "\n"), c, hwMillis());
+}
\ No newline at end of file
diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino
index 158deff4b..1eeeafa9d 100644
--- a/examples/MockMySensors/MockMySensors.ino
+++ b/examples/MockMySensors/MockMySensors.ino
@@ -45,7 +45,7 @@
// will make the sketch too large for a pro mini's memory so it's probably best to try
// one at a time.
-#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors
+#define ID_S_ARMED 0 // dummy to control armed stated for several sensors
#define ID_S_DOOR 1
//#define ID_S_MOTION 2
//#define ID_S_SMOKE 3
@@ -91,7 +91,7 @@ bool metric = true;
long randNumber;
-//Instanciate Messages objects
+//Instantiate Messages objects
#ifdef ID_S_ARMED
bool isArmed;
@@ -857,7 +857,7 @@ void temp()
void hum()
{
- Serial.print("Humitidty is: " );
+ Serial.print("Humidity is: " );
Serial.println(randNumber);
send(msg_S_HUM.set(randNumber));
@@ -873,7 +873,7 @@ void baro()
long pressure = map(randNumber,1,100,870,1086);// hPa?
int forecast = map(randNumber,1,100,0,5);
- Serial.print("Atmosferic Pressure is: " );
+ Serial.print("Atmospheric Pressure is: " );
Serial.println(pressure);
send(msg_S_BARO_P.set(pressure));
@@ -907,7 +907,7 @@ void wind()
void rain()
{
- Serial.print("Rain ammount is: " );
+ Serial.print("Rain amount is: " );
Serial.println(randNumber);
send(msg_S_RAIN_A.set(randNumber));
@@ -1488,7 +1488,7 @@ void receive(const MyMessage &message)
#endif
default:
- Serial.print("Unknown/UnImplemented message type: ");
+ Serial.print("Unknown/Unimplemented message type: ");
Serial.println(message.type);
}
diff --git a/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino
index 593757ba2..0fd8461da 100644
--- a/examples/PingPongSensor/PingPongSensor.ino
+++ b/examples/PingPongSensor/PingPongSensor.ino
@@ -1,7 +1,7 @@
/***
- * This is a simple sketch used to demenstrate and test node-to-node MySensor's communication.
+ * This is a simple sketch used to demonstrate and test node-to-node MySensors communication.
* To use this sketch, assemble MySensors nodes - they need nothing more than a radio
- * 1. Flash each node with the same sketch, open the console and type either 0 or 1 to the respective nodes to set thei ID
+ * 1. Flash each node with the same sketch, open the console and type either 0 or 1 to the respective nodes to set their ID
* 2. You only need to set the node id once, and restart the nodes
* 3. To being a ping-pong test, simply type T in the console for one of the nodes.
*
@@ -47,7 +47,7 @@ void loop()
// Interactive command and control
// Entering a number from 0 or 1 will write the node 200 (YING) or 201 (YANG) to EEPROM
- // Entering T on either node will initiatve a ping-pong test.
+ // Entering T on either node will initiate a ping-pong test.
if (Serial.available()) {
byte inChar = Serial.read();
uint8_t node = getNodeId();
diff --git a/examples/RepeaterNode/RepeaterNode.ino b/examples/RepeaterNode/RepeaterNode.ino
index bee56d3bb..768b55537 100644
--- a/examples/RepeaterNode/RepeaterNode.ino
+++ b/examples/RepeaterNode/RepeaterNode.ino
@@ -22,7 +22,7 @@
* Version 1.0 - Henrik Ekblad
*
* DESCRIPTION
- * Example sketch showing how to create a node thay repeates messages
+ * Example sketch showing how to create a node that repeats messages
* from nodes far from gateway back to gateway.
* It is important that nodes that has enabled repeater mode calls
* process() frequently. Repeaters should never sleep.
diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino
index b47393705..d626b7f61 100644
--- a/examples/SecretKnockSensor/SecretKnockSensor.ino
+++ b/examples/SecretKnockSensor/SecretKnockSensor.ino
@@ -139,7 +139,7 @@ void loop()
digitalWrite(ledPin, HIGH); // Turn on the red light too so the user knows we're programming.
chirp(500, 1500); // And play a tone in case the user can't see the LED.
chirp(500, 1000);
- } else { // If we are in programing mode, turn it off.
+ } else { // If we are in programming mode, turn it off.
programModeActive = false;
digitalWrite(ledPin, LOW);
chirp(500, 1000); // Turn off the programming LED and play a sad note.
@@ -302,8 +302,7 @@ bool validateKnock()
less of a pain to use if you're tempo is a little slow or fast.
*/
int totaltimeDifferences = 0;
- int timeDiff = 0;
- for (i=0; i < maximumKnocks; i++) { // Normalize the times
+ for (int timeDiff = 0, i=0; i < maximumKnocks; i++) { // Normalize the times
knockReadings[i]= map(knockReadings[i], 0, maxKnockInterval, 0, 100);
timeDiff = abs(knockReadings[i] - secretCode[i]);
if (timeDiff >
diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino
index 882d52366..17eeac542 100644
--- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino
+++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino
@@ -234,6 +234,10 @@
#define GENERATE_SOMETHING
#endif
+#if defined(MY_LOCK_MCU)
+#undefine MY_LOCK_MCU // The Sketch after SecurityPersonaliter should lock the MCU
+#endif
+
/********************************** Preprocessor sanitychecks *************************************/
#if defined(GENERATE_SOFT_SERIAL) && !defined(USE_SOFT_SIGNING)
#error Cannot generate soft serial using ATSHA204A, use USE_SOFT_SINGING for this
@@ -439,9 +443,7 @@ void setup()
hwRandomNumberInit();
#endif
- Serial.begin(MY_BAUD_RATE);
while(!Serial); // For USB enabled devices, wait for USB enumeration before continuing
- hwInit();
print_greeting();
diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino
index 1a62255f5..1c682ac8e 100644
--- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino
+++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino
@@ -20,7 +20,7 @@
*
* DESCRIPTION
* The ArduinoGateway prints data received from sensors on the serial link.
-* The gateway accepts input on seral which will be sent out on radio network.
+* The gateway accepts input on serial which will be sent out on radio network.
*
* This GW code is designed for Sensebender GateWay / (Arduino Zero variant)
*
@@ -29,9 +29,9 @@
*
* LEDs on board (default assignments):
* - Orange: USB RX/TX - Blink when receiving / transmitting on USB CDC device
-* - Yellow: RX - Blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+* - Yellow: RX - Blink fast on radio message received. In inclusion mode will blink fast only on presentation received
* - Green : TX - Blink fast on radio message transmitted. In inclusion mode will blink slowly
-* - Red : ERR - Fast blink on error during transmission error or recieve crc error
+* - Red : ERR - Fast blink on error during transmission error or receive crc error
* - Blue : free - (use with LED_BLUE macro)
*
*/
@@ -53,7 +53,7 @@
// Enable serial gateway
#define MY_GATEWAY_SERIAL
-// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
+// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & Sensebender)
#if F_CPU == 8000000L
#define MY_BAUD_RATE 38400
#endif
@@ -124,8 +124,8 @@ void preHwInit()
for (int i=0; i< num_of_leds; i++) {
pinMode(leds[i], OUTPUT);
}
- uint8_t led_state = 0;
if (digitalRead(MY_SWC1)) {
+ uint8_t led_state = 0;
while (!Serial) {
digitalWrite(LED_BLUE, led_state);
led_state ^= 0x01;
@@ -135,7 +135,7 @@ void preHwInit()
digitalWrite(LED_BLUE, LOW);
if (Serial) {
Serial.println("Sensebender GateWay test routine");
- Serial.print("Mysensors core version : ");
+ Serial.print("MySensors core version : ");
Serial.println(MYSENSORS_LIBRARY_VERSION);
Serial.print("GateWay sketch version : ");
Serial.println(SKETCH_VERSION);
diff --git a/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino
index bc76be3f1..719d8ced7 100644
--- a/examples/SoilMoistSensor/SoilMoistSensor.ino
+++ b/examples/SoilMoistSensor/SoilMoistSensor.ino
@@ -36,8 +36,8 @@
* 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution.
*
* Connection:
- * D6, D7: alternative powering to avoid sensor degradation
- * A0, A1: alternative resistance mesuring
+ * D6, D7: alternative powering to avoid sensor degradation
+ * A0, A1: alternative resistance measuring
*
* Based on:
* "Vinduino" portable soil moisture sensor code V3.00
@@ -138,7 +138,7 @@ void loop()
Serial.println ();
//send back the values
- send(msg.set((long int)ceil(sensor1)));
+ send(msg.set((int32_t)ceil(sensor1)));
// delay until next measurement (msec)
sleep(SLEEP_TIME);
}
diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
index 3f707563b..1afd45a34 100644
--- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
+++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
@@ -23,7 +23,7 @@
* Version 1.1 - GizMoCuz
*
* DESCRIPTION
- * Use this sensor to measure volume and flow of your house watermeter.
+ * Use this sensor to measure volume and flow of your house water meter.
* You need to set the correct pulsefactor of your meter (pulses per m3).
* The sensor starts by fetching current volume reading from gateway (VAR 1).
* Reports both volume and flow back to gateway.
@@ -47,7 +47,7 @@
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
-#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter)
+#define PULSE_FACTOR 1000 // Number of blinks per m3 of your meter (One rotation/liter)
#define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false.
@@ -96,7 +96,7 @@ void presentation()
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Water Meter", "1.1");
- // Register this device as Waterflow sensor
+ // Register this device as Water flow sensor
present(CHILD_ID, S_WATER);
}
@@ -120,8 +120,8 @@ void loop()
Serial.print("l/min:");
Serial.println(flow);
- // Check that we dont get unresonable large flow value.
- // could hapen when long wraps or false interrupt triggered
+ // Check that we don't get unreasonable large flow value.
+ // could happen when long wraps or false interrupt triggered
if (flow<((uint32_t)MAX_FLOW)) {
send(flowMsg.set(flow, 2)); // Send flow value to gw
}
@@ -178,7 +178,7 @@ void onPulse()
if (interval!=0) {
lastPulse = millis();
if (interval<500000L) {
- // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
+ // Sometimes we get interrupt on RISING, 500000 = 0.5 second debounce ( max 120 l/min)
return;
}
flow = (60000000.0 /interval) / ppl;
diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp
index da5ba055e..22771a8ba 100644
--- a/examples_linux/mysgw.cpp
+++ b/examples_linux/mysgw.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -24,18 +24,17 @@
// For more options run ./configure --help
// Config file
-//#define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat"
+//#define MY_LINUX_CONFIG_FILE "/etc/mysensors.conf"
// How many clients should be able to connect to this gateway (default 1)
#define MY_GATEWAY_MAX_CLIENTS 10
// Serial config
// Enable this if you are using an Arduino connected to the USB
-//#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0"
+//#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0"
// Enable this if you need to connect to a controller running on the same device
-//#define MY_LINUX_IS_SERIAL_PTY
-// Choose a symlink name for the PTY device
-//#define MY_LINUX_SERIAL_PTY "/dev/ttyMySensorsGateway"
+// You also need to define MY_LINUX_SERIAL_PORT above with the symlink name for the PTY device
+//#define MY_LINUX_SERIAL_IS_PTY
// Grant access to the specified system group for the serial device
//#define MY_LINUX_SERIAL_GROUPNAME "tty"
@@ -46,7 +45,7 @@
//#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
//#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
-// Enable these if your MQTT broker requires usenrame/password
+// Enable these if your MQTT broker requires username/password
//#define MY_MQTT_USER "username"
//#define MY_MQTT_PASSWORD "password"
diff --git a/hal/architecture/AVR/MyHwAVR.cpp b/hal/architecture/AVR/MyHwAVR.cpp
index 8a3bf22ec..de3ff86dc 100644
--- a/hal/architecture/AVR/MyHwAVR.cpp
+++ b/hal/architecture/AVR/MyHwAVR.cpp
@@ -20,6 +20,7 @@
#include "MyHwAVR.h"
#include "avr/boot.h"
+
bool hwInit(void)
{
#if !defined(MY_DISABLED_SERIAL)
@@ -38,7 +39,7 @@ volatile uint8_t _wakeUp1Interrupt =
volatile uint8_t _wakeUp2Interrupt =
INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback.
-void wakeUp1()
+void wakeUp1(void)
{
// Disable sleep. When an interrupt occurs after attachInterrupt,
// but before sleeping the CPU would not wake up.
@@ -50,7 +51,7 @@ void wakeUp1()
_wokeUpByInterrupt = _wakeUp1Interrupt;
}
}
-void wakeUp2()
+void wakeUp2(void)
{
sleep_disable();
detachInterrupt(_wakeUp2Interrupt);
@@ -60,7 +61,7 @@ void wakeUp2()
}
}
-inline bool interruptWakeUp()
+inline bool interruptWakeUp(void)
{
return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
}
@@ -86,7 +87,7 @@ void hwPowerDown(const uint8_t wdto)
// disable ADC for power saving
ADCSRA &= ~(1 << ADEN);
// save WDT settings
- uint8_t WDTsave = WDTCSR;
+ const uint8_t WDTsave = WDTCSR;
if (wdto != WDTO_SLEEP_FOREVER) {
wdt_enable(wdto);
// enable WDT interrupt before system reset
@@ -98,7 +99,7 @@ void hwPowerDown(const uint8_t wdto)
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_enable();
-#if defined __AVR_ATmega328P__
+#if defined(__AVR_ATmega328P__)
sleep_bod_disable();
#endif
// Enable interrupts & sleep until WDT or ext. interrupt
@@ -140,16 +141,32 @@ void hwInternalSleep(uint32_t ms)
int8_t hwSleep(uint32_t ms)
{
- hwInternalSleep(ms);
- return MY_WAKE_UP_BY_TIMER;
+ // Return what woke the mcu.
+ // Default: no interrupt triggered, timer wake up
+ int8_t ret = MY_WAKE_UP_BY_TIMER;
+ if (ms > 0u) {
+ // sleep for defined time
+ hwInternalSleep(ms);
+ } else {
+ // sleep until ext interrupt triggered
+ hwPowerDown(WDTO_SLEEP_FOREVER);
+ }
+ if (interruptWakeUp()) {
+ ret = static_cast(_wokeUpByInterrupt);
+ }
+ // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
+ _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
+
+ return ret;
}
-int8_t hwSleep(uint8_t interrupt, uint8_t mode, uint32_t ms)
+int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
{
- return hwSleep(interrupt,mode,INVALID_INTERRUPT_NUM,0u,ms);
+ return hwSleep(interrupt, mode, INVALID_INTERRUPT_NUM, 0u, ms);
}
-int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
+int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
+ const uint8_t mode2,
uint32_t ms)
{
// ATMega328P supports following modes to wake from sleep: LOW, CHANGE, RISING, FALLING
@@ -203,14 +220,13 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo
return ret;
}
-inline void hwRandomNumberInit()
+inline void hwRandomNumberInit(void)
{
// This function initializes the random number generator with a seed
// of 32 bits. This method is good enough to earn FIPS 140-2 conform
// random data. This should reach to generate 32 Bit for randomSeed().
uint32_t seed = 0;
- uint32_t start = millis();
- uint32_t timeout = start + 20;
+ uint32_t timeout = millis() + 20;
// Trigger floating effect of an unconnected pin
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP);
@@ -219,7 +235,7 @@ inline void hwRandomNumberInit()
// Generate 32 bits of datas
for (uint8_t i=0; i<32; i++) {
- int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN);
+ const int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN);
// Wait until the analog value has changed
while ((pinValue == analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) && (timeout>=millis())) {
seed ^= (millis() << i);
@@ -230,11 +246,10 @@ inline void hwRandomNumberInit()
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT);
// Pause a short while
delay(seed % 10);
- timeout = millis()+20;
+ timeout = millis() + 20;
}
}
}
-
randomSeed(seed);
}
@@ -247,14 +262,18 @@ bool hwUniqueID(unique_id_t* uniqueID)
*((uint8_t*)uniqueID + 1) = boot_signature_byte_get(0x02);
*((uint8_t*)uniqueID + 2) = boot_signature_byte_get(0x04);
*((uint8_t*)uniqueID + 3) = boot_signature_byte_get(0x01); //OSCCAL
+#if defined(__AVR_ATmega328PB__)
// ATMEGA328PB specifics, has unique ID
- //for(uint8_t idx = 0; idx < 10; idx++) {
- // *((uint8_t*)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx);
- //}
- return false; // false, since no unique ID returned
+ for(uint8_t idx = 0; idx < 10; idx++) {
+ *((uint8_t*)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx);
+ }
+ return true; // unique ID returned
+#else
+ return false; // no unique ID returned
+#endif
}
-uint16_t hwCPUVoltage()
+uint16_t hwCPUVoltage(void)
{
// Measure Vcc against 1.1V Vref
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
@@ -275,16 +294,19 @@ uint16_t hwCPUVoltage()
return (1125300UL) / ADC;
}
-uint16_t hwCPUFrequency()
+uint16_t hwCPUFrequency(void)
{
cli();
+ // save WDT & timer settings
+ const uint8_t WDTsave = WDTCSR;
+ const uint8_t TCCR1Asave = TCCR1A;
+ const uint8_t TCCR1Csave = TCCR1C;
// setup timer1
TIFR1 = 0xFF;
TCNT1 = 0;
TCCR1A = 0;
TCCR1C = 0;
- // save WDT settings
- uint8_t WDTsave = WDTCSR;
+ // set wdt
wdt_enable(WDTO_500MS);
// enable WDT interrupt mode => first timeout WDIF, 2nd timeout reset
WDTCSR |= (1 << WDIE);
@@ -300,11 +322,14 @@ uint16_t hwCPUFrequency()
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = WDTsave;
sei();
+ // restore timer settings
+ TCCR1A = TCCR1Asave;
+ TCCR1C = TCCR1Csave;
// return frequency in 1/10MHz (accuracy +- 10%)
return TCNT1 * 2048UL / 100000UL;
}
-uint16_t hwFreeMem()
+uint16_t hwFreeMem(void)
{
extern int __heap_start, *__brkval;
int v;
diff --git a/hal/architecture/AVR/MyHwAVR.h b/hal/architecture/AVR/MyHwAVR.h
index a189f70d8..863ed641c 100644
--- a/hal/architecture/AVR/MyHwAVR.h
+++ b/hal/architecture/AVR/MyHwAVR.h
@@ -55,8 +55,8 @@ bool hwInit(void);
#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length))
#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length))
-inline void hwRandomNumberInit();
-void hwInternalSleep(unsigned long ms);
+inline void hwRandomNumberInit(void);
+void hwInternalSleep(uint32_t ms);
#ifndef DOXYGEN
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
diff --git a/hal/architecture/ESP32/MyHwESP32.cpp b/hal/architecture/ESP32/MyHwESP32.cpp
new file mode 100644
index 000000000..25578fc35
--- /dev/null
+++ b/hal/architecture/ESP32/MyHwESP32.cpp
@@ -0,0 +1,168 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Arduino core for ESP32: https://github.com/espressif/arduino-esp32
+ *
+ * MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti
+ *
+ */
+
+#include "MyHwESP32.h"
+
+bool hwInit(void)
+{
+#if !defined(MY_DISABLED_SERIAL)
+ MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1);
+#endif
+ return EEPROM.begin(MY_EEPROM_SIZE);
+}
+
+void hwReadConfigBlock(void *buf, void *addr, size_t length)
+{
+ uint8_t *dst = static_cast(buf);
+ int offs = reinterpret_cast(addr);
+ while (length-- > 0) {
+ *dst++ = EEPROM.read(offs++);
+ }
+}
+
+void hwWriteConfigBlock(void *buf, void *addr, size_t length)
+{
+ uint8_t *src = static_cast(buf);
+ int offs = reinterpret_cast(addr);
+ while (length-- > 0) {
+ EEPROM.write(offs++, *src++);
+ }
+ EEPROM.commit();
+}
+
+uint8_t hwReadConfig(const int addr)
+{
+ uint8_t value;
+ hwReadConfigBlock(&value, reinterpret_cast(addr), 1);
+ return value;
+}
+
+void hwWriteConfig(const int addr, uint8_t value)
+{
+ if (hwReadConfig(addr) != value) {
+ hwWriteConfigBlock(&value, reinterpret_cast(addr), 1);
+ }
+}
+
+bool hwUniqueID(unique_id_t *uniqueID)
+{
+ uint64_t val = ESP.getEfuseMac();
+ (void)memcpy((void *)uniqueID, (void *)&val, 8);
+ (void)memset((void *)(uniqueID + 8), MY_HWID_PADDING_BYTE, 8); // padding
+ return true;
+}
+
+ssize_t hwGetentropy(void *__buffer, size_t __length)
+{
+ // cut length if > 256
+ if (__length > 256) {
+ __length = 256;
+ }
+ uint8_t *dst = (uint8_t *)__buffer;
+ // get random numbers
+ for (size_t i = 0; i < __length; i++) {
+ dst[i] = (uint8_t)esp_random();
+ }
+ return __length;
+}
+
+int8_t hwSleep(uint32_t ms)
+{
+ // TODO: Not supported!
+ (void)ms;
+ return MY_SLEEP_NOT_POSSIBLE;
+}
+
+int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
+{
+ // TODO: Not supported!
+ (void)interrupt;
+ (void)mode;
+ (void)ms;
+ return MY_SLEEP_NOT_POSSIBLE;
+}
+
+int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
+ const uint8_t mode2,
+ uint32_t ms)
+{
+ // TODO: Not supported!
+ (void)interrupt1;
+ (void)mode1;
+ (void)interrupt2;
+ (void)mode2;
+ (void)ms;
+ return MY_SLEEP_NOT_POSSIBLE;
+}
+
+uint16_t hwCPUVoltage(void)
+{
+ // in mV
+ return FUNCTION_NOT_SUPPORTED;
+}
+
+uint16_t hwCPUFrequency(void)
+{
+ // in 1/10Mhz
+ return static_cast(ESP.getCpuFreqMHz() * 10);
+}
+
+uint8_t hwCPUTemperature(void)
+{
+ // CPU temperature in °C
+ return static_cast(temperatureRead());
+}
+
+uint16_t hwFreeMem(void)
+{
+ return static_cast(ESP.getFreeHeap());
+}
+
+void hwDebugPrint(const char *fmt, ...)
+{
+ char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
+#ifdef MY_GATEWAY_SERIAL
+ // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
+ snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "), C_INTERNAL, I_LOG_MESSAGE,
+ millis());
+ MY_SERIALDEVICE.print(fmtBuffer);
+#else
+ // prepend timestamp
+ MY_SERIALDEVICE.print(millis());
+ MY_SERIALDEVICE.print(" ");
+#endif
+ va_list args;
+ va_start(args, fmt);
+#ifdef MY_GATEWAY_SERIAL
+ // Truncate message if this is gateway node
+ vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
+ fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
+ fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
+#else
+ vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
+#endif
+ va_end(args);
+ MY_SERIALDEVICE.print(fmtBuffer);
+ MY_SERIALDEVICE.flush();
+}
diff --git a/hal/architecture/ESP32/MyHwESP32.h b/hal/architecture/ESP32/MyHwESP32.h
new file mode 100644
index 000000000..64d6ac786
--- /dev/null
+++ b/hal/architecture/ESP32/MyHwESP32.h
@@ -0,0 +1,89 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2018 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Arduino core for ESP32: https://github.com/espressif/arduino-esp32
+ *
+ * MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti
+ *
+ * Radio wiring ESP32(Node32s): RF24, RFM69, RFM95:
+ *
+ * | IO | RF24 | RFM69 | RFM95 |
+ * |------|------|-------|-------|
+ * | MOSI | 23 | 23 | 23 |
+ * | MISO | 19 | 19 | 19 |
+ * | SCK | 18 | 18 | 18 |
+ * | CSN | 5 | 5 | 5 |
+ * | CE | 17 | - | - |
+ * | RST | - | 17 | 17 |
+ * | IRQ | 16* | 16 | 16 |
+ * * = optional
+ *
+ */
+
+#ifndef MyHwESP32_h
+#define MyHwESP32_h
+
+#include
+#include "EEPROM.h"
+
+#ifdef __cplusplus
+#include
+#endif
+
+#define MY_SERIALDEVICE Serial
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+#define MIN min
+#define MAX max
+
+#define MY_EEPROM_SIZE 1024
+
+#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
+#define hwDigitalRead(__pin) digitalRead(__pin)
+#define hwPinMode(__pin, __value) pinMode(__pin, __value)
+#define hwWatchdogReset()
+#define hwReboot() ESP.restart()
+#define hwMillis() millis()
+#define hwMicros() micros()
+#define hwRandomNumberInit() randomSeed(esp_random())
+
+bool hwInit(void);
+void hwReadConfigBlock(void *buf, void *addr, size_t length);
+void hwWriteConfigBlock(void *buf, void *addr, size_t length);
+void hwWriteConfig(const int addr, uint8_t value);
+uint8_t hwReadConfig(const int addr);
+ssize_t hwGetentropy(void *__buffer, size_t __length);
+#define MY_HW_HAS_GETENTROPY
+
+/**
+* Restore interrupt state.
+* Helper function for MY_CRITICAL_SECTION.
+*/
+static __inline__ void __psRestore(const uint32_t *__s)
+{
+ XTOS_RESTORE_INTLEVEL(*__s);
+}
+
+#ifndef DOXYGEN
+#define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = XTOS_DISABLE_ALL_INTERRUPTS, __ToDo = 1; __ToDo ; __ToDo = 0 )
+#endif /* DOXYGEN */
+
+
+#endif
diff --git a/hal/architecture/ESP32/MyMainESP32.cpp b/hal/architecture/ESP32/MyMainESP32.cpp
new file mode 100644
index 000000000..99be1711d
--- /dev/null
+++ b/hal/architecture/ESP32/MyMainESP32.cpp
@@ -0,0 +1,49 @@
+/*
+* The MySensors Arduino library handles the wireless radio link and protocol
+* between your home built sensors/actuators and HA controller of choice.
+* The sensors forms a self healing radio network with optional repeaters. Each
+* repeater and gateway builds a routing tables in EEPROM which keeps track of the
+* network topology allowing messages to be routed to nodes.
+*
+* Created by Henrik Ekblad
+* Copyright (C) 2013-2018 Sensnology AB
+* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+*
+* Documentation: http://www.mysensors.org
+* Support Forum: http://forum.mysensors.org
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+*/
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "Arduino.h"
+
+#if CONFIG_AUTOSTART_ARDUINO
+
+#if CONFIG_FREERTOS_UNICORE
+#define ARDUINO_RUNNING_CORE 0
+#else
+#define ARDUINO_RUNNING_CORE 1
+#endif
+
+void MySensorsTask(void *pvParameters)
+{
+ _begin(); // Startup MySensors library
+ for (;;) {
+ micros(); // update overflow
+ _process(); // Process incoming data
+ loop(); // Call sketch loop
+ }
+}
+
+extern "C" void app_main()
+{
+ initArduino();
+ xTaskCreatePinnedToCore(MySensorsTask, "MySensorsTask", 8192, NULL, 1, NULL, ARDUINO_RUNNING_CORE);
+}
+
+#endif
diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.cpp b/hal/architecture/Linux/MyHwLinuxGeneric.cpp
index 6256e6618..8be3de8d0 100644
--- a/hal/architecture/Linux/MyHwLinuxGeneric.cpp
+++ b/hal/architecture/Linux/MyHwLinuxGeneric.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -27,8 +27,9 @@
#include
#include "SoftEeprom.h"
#include "log.h"
+#include "config.h"
-static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes
+static SoftEeprom eeprom;
static FILE *randomFp = NULL;
bool hwInit(void)
@@ -43,6 +44,10 @@ bool hwInit(void)
#endif
#endif
+ if (eeprom.init(conf.eeprom_file, conf.eeprom_size) != 0) {
+ exit(1);
+ }
+
return true;
}
@@ -165,8 +170,37 @@ void hwPinMode(uint8_t pin, uint8_t mode)
void hwDebugPrint(const char *fmt, ...)
{
+#ifndef MY_DISABLED_SERIAL
+#ifdef MY_DEBUGDEVICE
+ char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
+#ifdef MY_GATEWAY_SERIAL
+ // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
+ snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%" PRIu8 ";0;%" PRIu8 ";%" PRIu32 " "),
+ C_INTERNAL, I_LOG_MESSAGE, hwMillis());
+ MY_DEBUGDEVICE.print(fmtBuffer);
+#else
+ // prepend timestamp
+ MY_DEBUGDEVICE.print(hwMillis());
+ MY_DEBUGDEVICE.print(" ");
+#endif
+ va_list args;
+ va_start (args, fmt );
+ vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
+#ifdef MY_GATEWAY_SERIAL
+ // Truncate message if this is gateway node
+ fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
+ fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
+#endif
+ va_end (args);
+ MY_DEBUGDEVICE.print(fmtBuffer);
+ MY_DEBUGDEVICE.flush();
+#else
va_list args;
va_start(args, fmt);
vlogDebug(fmt, args);
va_end(args);
+#endif
+#else
+ (void)fmt;
+#endif
}
diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.h b/hal/architecture/Linux/MyHwLinuxGeneric.h
index a933632c9..220a72089 100644
--- a/hal/architecture/Linux/MyHwLinuxGeneric.h
+++ b/hal/architecture/Linux/MyHwLinuxGeneric.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -23,16 +23,16 @@
#include
#include
#include "SerialPort.h"
-#include "SerialSimulator.h"
+#include "StdInOutStream.h"
-#ifdef MY_GATEWAY_SERIAL
-#ifdef MY_LINUX_IS_SERIAL_PTY
-SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true);
+#ifdef MY_LINUX_SERIAL_PORT
+#ifdef MY_LINUX_SERIAL_IS_PTY
+SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, true);
#else
-SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT);
+SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, false);
#endif
#else
-SerialSimulator Serial = SerialSimulator();
+StdInOutStream Serial = StdInOutStream();
#endif
#ifndef MY_SERIALDEVICE
diff --git a/hal/architecture/Linux/MyMainLinux.cpp b/hal/architecture/Linux/MyMainLinuxGeneric.cpp
similarity index 58%
rename from hal/architecture/Linux/MyMainLinux.cpp
rename to hal/architecture/Linux/MyMainLinuxGeneric.cpp
index f67ea2f31..6003f9c1a 100644
--- a/hal/architecture/Linux/MyMainLinux.cpp
+++ b/hal/architecture/Linux/MyMainLinuxGeneric.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -28,6 +28,7 @@
#include
#include
#include "log.h"
+#include "config.h"
#include "MySensorsCore.h"
void handle_sigint(int sig)
@@ -48,7 +49,7 @@ void handle_sigint(int sig)
MY_SERIALDEVICE.end();
#endif
- closelog();
+ logClose();
exit(EXIT_SUCCESS);
}
@@ -104,18 +105,13 @@ void print_usage()
{
printf("Usage: mysgw [options]\n\n" \
"Options:\n" \
+ " -c, --config-file Config file. [" MY_LINUX_CONFIG_FILE "]\n" \
" -h, --help Display a short summary of all program options.\n" \
- " -d, --debug Enable debug.\n" \
- " -b, --background Run as a background process.\n"
- " --gen-soft-hmac-key Generate and print a soft hmac key.\n"
- " --gen-soft-serial-key Generate and print a soft serial key.\n"
- " --gen-aes-key Generate and print an aes encryption key.\n"
- " --print-soft-hmac-key Print the soft hmac key from the config file.\n"
- " --print-soft-serial-key Print the soft serial key from the config file.\n"
- " --print-aes-key Print the aes encryption key from the config file.\n"
- " --set-soft-hmac-key Write a soft hmac key to the config file.\n"
- " --set-soft-serial-key Write a soft serial key to the config file.\n"
- " --set-aes-key Write an aes encryption key to the config file.\n");
+ " -q, --quiet Quiet mode, disable log messages written to the terminal.\n" \
+ " --daemon Run as a daemon.\n" \
+ " --gen-soft-hmac-key Generate and print a soft hmac key.\n" \
+ " --gen-soft-serial-key Generate and print a soft serial key.\n" \
+ " --gen-aes-key Generate and print an aes encryption key.\n");
}
void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
@@ -127,14 +123,14 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
key_ptr = key;
}
- printf("SOFT_HMAC_KEY | ");
+ printf("soft_hmac_key=");
for (int i = 0; i < 32; i++) {
printf("%02X", key_ptr[i]);
}
printf("\n\n");
printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
- printf("#define MY_SOFT_HMAC_KEY ");
+ printf("#define MY_HMAC_KEY ");
for (int i=0; i<32; i++) {
printf("%#02X", key_ptr[i]);
if (i < 31) {
@@ -144,20 +140,26 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
printf("\n\n");
}
-void generate_soft_sign_hmac_key()
+void generate_soft_sign_hmac_key(char *config_file = NULL)
{
uint8_t key[32];
+ printf("Generating key...");
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
+ printf(" done.\n");
+ printf("To use the new key, update the value in %s witn:\n",
+ config_file?config_file:MY_LINUX_CONFIG_FILE);
print_soft_sign_hmac_key(key);
- printf("To use this key, run mysgw with:\n"
- " --set-soft-hmac-key=");
- for (int i = 0; i < 32; i++) {
- printf("%02X", key[i]);
- }
- printf("\n");
+#if defined(MY_SIGNING_SIMPLE_PASSWD)
+ printf("Note: The gateway was built with simplified signing using the password: %s\n" \
+ " Any key set with soft_hmac_key option in the config file is ignored.\n\n",
+ MY_SIGNING_SIMPLE_PASSWD);
+#elif !defined(MY_SIGNING_FEATURE)
+ printf("Note: The gateway was not built with signing support.\n" \
+ " Any key set with soft_hmac_key option in the config file is ignored.\n\n");
+#endif
}
void set_soft_sign_hmac_key(char *key_str)
@@ -165,7 +167,7 @@ void set_soft_sign_hmac_key(char *key_str)
uint8_t key[32];
if (strlen(key_str) != 64) {
- printf("invalid key!\n");
+ logWarning("Invalid HMAC key!\n");
} else {
for (int i = 0; i < 64; ++i) {
int n;
@@ -185,7 +187,6 @@ void set_soft_sign_hmac_key(char *key_str)
}
}
hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
- print_soft_sign_hmac_key();
}
}
@@ -198,7 +199,7 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL)
key_ptr = key;
}
- printf("SOFT_SERIAL | ");
+ printf("soft_serial_key=");
for (int i = 0; i < 9; i++) {
printf("%02X", key_ptr[i]);
}
@@ -215,20 +216,26 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL)
printf("\n\n");
}
-void generate_soft_sign_serial_key()
+void generate_soft_sign_serial_key(char *config_file = NULL)
{
uint8_t key[9];
+ printf("Generating key...");
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
+ printf(" done.\n");
+ printf("To use the new key, update the value in %s witn:\n",
+ config_file?config_file:MY_LINUX_CONFIG_FILE);
print_soft_sign_serial_key(key);
- printf("To use this key, run mysgw with:\n"
- " --set-soft-serial-key=");
- for (int i = 0; i < 9; i++) {
- printf("%02X", key[i]);
- }
- printf("\n");
+#if defined(MY_SIGNING_SIMPLE_PASSWD)
+ printf("Note: The gateway was built with simplified signing using the password: %s\n" \
+ " Any key set with soft_serial_key option in the config file is ignored.\n\n",
+ MY_SIGNING_SIMPLE_PASSWD);
+#elif !defined(MY_SIGNING_FEATURE)
+ printf("Note: The gateway was not built with signing support.\n" \
+ " Any key set with soft_serial_key option in the config file is ignored.\n\n");
+#endif
}
void set_soft_sign_serial_key(char *key_str)
@@ -236,7 +243,7 @@ void set_soft_sign_serial_key(char *key_str)
uint8_t key[9];
if (strlen(key_str) != 18) {
- printf("invalid key!\n");
+ logWarning("Invalid soft serial key!\n");
} else {
for (int i = 0; i < 18; ++i) {
int n;
@@ -256,7 +263,6 @@ void set_soft_sign_serial_key(char *key_str)
}
}
hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
- print_soft_sign_serial_key();
}
}
@@ -265,16 +271,11 @@ void print_aes_key(uint8_t *key_ptr = NULL)
uint8_t key[16];
if (key_ptr == NULL) {
-#ifdef MY_SIGNING_SIMPLE_PASSWD
- memset(key, 0, 16);
- memcpy(key, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
-#else
hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
-#endif
key_ptr = key;
}
- printf("AES_KEY | ");
+ printf("aes_key=");
for (int i = 0; i < 16; i++) {
printf("%02X", key_ptr[i]);
}
@@ -291,20 +292,26 @@ void print_aes_key(uint8_t *key_ptr = NULL)
printf("\n\n");
}
-void generate_aes_key()
+void generate_aes_key(char *config_file = NULL)
{
uint8_t key[16];
+ printf("Generating key...");
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
+ printf(" done.\n");
+ printf("To use the new key, update the value in %s witn:\n",
+ config_file?config_file:MY_LINUX_CONFIG_FILE);
print_aes_key(key);
- printf("To use this key, run mysgw with:\n"
- " --set-aes-key=");
- for (int i = 0; i < 16; i++) {
- printf("%02X", key[i]);
- }
- printf("\n");
+#if defined(MY_ENCRYPTION_SIMPLE_PASSWD)
+ printf("Note: The gateway was built with simplified encryption using the password: %s\n" \
+ " Any key set with aes_key option in the config file is ignored.\n\n",
+ MY_ENCRYPTION_SIMPLE_PASSWD);
+#elif !defined(MY_ENCRYPTION_FEATURE)
+ printf("Note: The gateway was not built with encryption support.\n" \
+ " Any key set with aes_key option in the config file is ignored.\n\n");
+#endif
}
void set_aes_key(char *key_str)
@@ -312,7 +319,7 @@ void set_aes_key(char *key_str)
uint8_t key[16];
if (strlen(key_str) != 32) {
- printf("invalid key!\n");
+ logWarning("Invalid AES key!\n");
} else {
for (int i = 0; i < 32; ++i) {
int n;
@@ -332,100 +339,106 @@ void set_aes_key(char *key_str)
}
}
hwWriteConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
- print_aes_key();
}
}
int main(int argc, char *argv[])
{
- int opt, log_opts, debug = 0, foreground = 1;
- char *key = NULL;
+ int opt, daemon = 0, quiet = 0;
+ char *config_file = NULL;
+ bool gen_soft_sign_hmac_key = false;
+ bool gen_soft_sign_serial_key = false;
+ bool gen_aes_key = false;
/* register the signal handler */
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigint);
+ signal(SIGPIPE, handle_sigint);
hwRandomNumberInit();
static struct option long_options[] = {
+ {"config-file", required_argument, 0, 'c'},
+ {"daemon", no_argument, 0, 'J'},
{"help", no_argument, 0, 'h'},
- {"debug", no_argument, 0, 'd'},
- {"background", no_argument, 0, 'b'},
+ {"quiet", no_argument, 0, 'q'},
{"gen-soft-hmac-key", no_argument, 0, 'A'},
{"gen-soft-serial-key", no_argument, 0, 'B'},
{"gen-aes-key", no_argument, 0, 'C'},
- {"print-soft-hmac-key", no_argument, 0, 'D'},
- {"print-soft-serial-key", no_argument, 0, 'E'},
- {"print-aes-key", no_argument, 0, 'F'},
- {"set-soft-hmac-key", required_argument, 0, 'G'},
- {"set-soft-serial-key", required_argument, 0, 'H'},
- {"set-aes-key", required_argument, 0, 'I'},
{0, 0, 0, 0}
};
int long_index = 0;
- while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) {
+ while ((opt = getopt_long(argc, argv,"chqABCJ", long_options, &long_index )) != -1) {
switch (opt) {
+ case 'c':
+ config_file = strdup(optarg);
+ break;
case 'h':
print_usage();
exit(EXIT_SUCCESS);
- case 'd':
- debug = 1;
- break;
- case 'b':
- foreground = 0;
+ case 'q':
+ quiet = 1;
break;
case 'A':
- generate_soft_sign_hmac_key();
- exit(EXIT_SUCCESS);
+ gen_soft_sign_hmac_key = true;
+ break;
case 'B':
- generate_soft_sign_serial_key();
- exit(EXIT_SUCCESS);
+ gen_soft_sign_serial_key = true;
+ break;
case 'C':
- generate_aes_key();
- exit(EXIT_SUCCESS);
- case 'D':
- print_soft_sign_hmac_key();
- exit(EXIT_SUCCESS);
- case 'E':
- print_soft_sign_serial_key();
- exit(EXIT_SUCCESS);
- case 'F':
- print_aes_key();
- exit(EXIT_SUCCESS);
- case 'G':
- key = strdup(optarg);
- set_soft_sign_hmac_key(key);
- exit(EXIT_SUCCESS);
- case 'H':
- key = strdup(optarg);
- set_soft_sign_serial_key(key);
- exit(EXIT_SUCCESS);
- case 'I':
- key = strdup(optarg);
- set_aes_key(key);
- exit(EXIT_SUCCESS);
+ gen_aes_key = true;
+ break;
+ case 'J':
+ daemon = 1;
+ break;
default:
print_usage();
exit(EXIT_SUCCESS);
}
}
- log_opts = LOG_CONS;
- if (foreground && isatty(STDIN_FILENO)) {
- // Also print syslog to stderror
- log_opts |= LOG_PERROR;
- }
- if (!debug) {
- // Ignore debug type messages
- setlogmask(LOG_UPTO (LOG_INFO));
+ if (gen_soft_sign_hmac_key || gen_soft_sign_serial_key || gen_aes_key) {
+ if (gen_soft_sign_hmac_key) {
+ generate_soft_sign_hmac_key(config_file);
+ }
+ if (gen_soft_sign_serial_key) {
+ generate_soft_sign_serial_key(config_file);
+ }
+ if (gen_aes_key) {
+ generate_aes_key(config_file);
+ }
+ exit(EXIT_SUCCESS);
}
- logOpen(log_opts, LOG_USER);
- if (!foreground && !debug) {
+ if (daemon) {
if (daemonize() != 0) {
exit(EXIT_FAILURE);
}
+ quiet = 1;
+ }
+
+ if (config_parse(config_file?config_file:MY_LINUX_CONFIG_FILE) != 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ logSetQuiet(quiet);
+ logSetLevel(conf.verbose);
+
+ if (conf.log_file) {
+ if (logSetFile(conf.log_filepath) != 0) {
+ logError("Failed to open log file.\n");
+ }
+ }
+
+ if (conf.log_pipe) {
+ if (logSetPipe(conf.log_pipe_file) != 0) {
+ logError("Failed to open log pipe.\n");
+ }
+ }
+
+ if (conf.syslog) {
+ logSetSyslog(LOG_CONS, LOG_USER);
}
logInfo("Starting gateway...\n");
@@ -433,6 +446,38 @@ int main(int argc, char *argv[])
_begin(); // Startup MySensors library
+ // EEPROM is initialized within _begin()
+ // any operation on it must be done hereafter
+
+#if defined(MY_SIGNING_FEATURE) && !defined(MY_SIGNING_SIMPLE_PASSWD)
+ // Check if we need to update the signing keys in EEPROM
+ if (conf.soft_hmac_key) {
+ set_soft_sign_hmac_key(conf.soft_hmac_key);
+ } else {
+ logError("soft_hmac_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
+ exit(EXIT_FAILURE);
+ }
+ if (conf.soft_serial_key) {
+ set_soft_sign_serial_key(conf.soft_serial_key);
+ } else {
+ logError("soft_serial_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
+ exit(EXIT_FAILURE);
+ }
+#endif
+#if defined(MY_ENCRYPTION_FEATURE) && !defined(MY_ENCRYPTION_SIMPLE_PASSWD)
+ // Check if we need to update the encryption key in EEPROM
+ if (conf.aes_key) {
+ set_aes_key(conf.aes_key);
+ } else {
+ logError("aes_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ if (config_file) {
+ free(config_file);
+ }
+
for (;;) {
_process(); // Process incoming data
if (loop) {
diff --git a/hal/architecture/NRF5/MyHwNRF5.cpp b/hal/architecture/NRF5/MyHwNRF5.cpp
index b1b7dc7f1..921bbf8a3 100644
--- a/hal/architecture/NRF5/MyHwNRF5.cpp
+++ b/hal/architecture/NRF5/MyHwNRF5.cpp
@@ -66,6 +66,31 @@ void hwWriteConfig(int adr, uint8_t value)
bool hwInit()
{
+#ifdef MY_LOCK_MCU
+#ifdef NRF51
+ // Lock MCU
+ if((uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos) !=
+ UICR_RBPCONF_PALL_Enabled) {
+ Flash.write((uint32_t *)&NRF_UICR->RBPCONF, (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk));
+ hwReboot();
+ }
+#else
+ // Lock MCU
+ if((uint32_t)((NRF_UICR->APPROTECT & UICR_APPROTECT_PALL_Msk) >> UICR_APPROTECT_PALL_Pos) !=
+ UICR_APPROTECT_PALL_Enabled) {
+ Flash.write((uint32_t *)&NRF_UICR->APPROTECT, (NRF_UICR->APPROTECT & ~UICR_APPROTECT_PALL_Msk));
+ hwReboot();
+ }
+#endif
+#endif
+
+#if defined(NRF51) && defined(CONFIG_ENABLE_PINRESET)
+ // Enabling reset for NRF51 isn't handled by arduino-nrf5. Enable it, if requested.
+ NRF_POWER->RESET = POWER_RESET_RESET_Enabled;
+ NRF_POWER->RAMON |= (POWER_RAMON_ONRAM0_RAM0On << POWER_RAMON_ONRAM0_Pos) |
+ (POWER_RAMON_ONRAM1_RAM1On << POWER_RAMON_ONRAM1_Pos);
+#endif
+
// Clock is manged by sleep modes. Radio depends on HFCLK.
// Force to start HFCLK
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
diff --git a/hal/architecture/SAMD/MyHwSAMD.h b/hal/architecture/SAMD/MyHwSAMD.h
index a5670929d..178ec102f 100644
--- a/hal/architecture/SAMD/MyHwSAMD.h
+++ b/hal/architecture/SAMD/MyHwSAMD.h
@@ -40,6 +40,7 @@ extEEPROM eep(MY_EXT_EEPROM_SIZE, 1, MY_EXT_EEPROM_PAGE_SIZE,
#define MIN(a,b) min(a,b)
#define MAX(a,b) max(a,b)
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
+#define vsnprintf_P(s, n, f, ...) vsnprintf((s), (n), (f), __VA_ARGS__)
// Define these as macros to save valuable space
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
diff --git a/hal/transport/MyTransportHAL.h b/hal/transport/MyTransportHAL.h
index a651b1681..a3da5133a 100644
--- a/hal/transport/MyTransportHAL.h
+++ b/hal/transport/MyTransportHAL.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -20,10 +20,10 @@
#ifndef MyTransportHAL_h
#define MyTransportHAL_h
-#define INVALID_SNR ((int16_t)-256) //!< INVALID_SNR
-#define INVALID_RSSI ((int16_t)-256) //!< INVALID_RSSI
-#define INVALID_PERCENT ((int16_t)-100) //!< INVALID_PERCENT
-#define INVALID_LEVEL ((int16_t)-256) //!< INVALID_LEVEL
+#define INVALID_SNR ((int16_t)-256) //!< INVALID_SNR
+#define INVALID_RSSI ((int16_t)-256) //!< INVALID_RSSI
+#define INVALID_PERCENT ((int16_t)-100) //!< INVALID_PERCENT
+#define INVALID_LEVEL ((int16_t)-256) //!< INVALID_LEVEL
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
#if defined(MY_RADIO_NRF5_ESB)
@@ -46,14 +46,14 @@
* @brief Signal report selector
*/
typedef enum {
- SR_RX_RSSI, //!< SR_RX_RSSI
- SR_TX_RSSI, //!< SR_TX_RSSI
- SR_RX_SNR, //!< SR_RX_SNR
- SR_TX_SNR, //!< SR_TX_SNR
- SR_TX_POWER_LEVEL, //!< SR_TX_POWER_LEVEL
- SR_TX_POWER_PERCENT, //!< SR_TX_POWER_PERCENT
- SR_UPLINK_QUALITY, //!< SR_UPLINK_QUALITY
- SR_NOT_DEFINED //!< SR_NOT_DEFINED
+ SR_RX_RSSI, //!< SR_RX_RSSI
+ SR_TX_RSSI, //!< SR_TX_RSSI
+ SR_RX_SNR, //!< SR_RX_SNR
+ SR_TX_SNR, //!< SR_TX_SNR
+ SR_TX_POWER_LEVEL, //!< SR_TX_POWER_LEVEL
+ SR_TX_POWER_PERCENT, //!< SR_TX_POWER_PERCENT
+ SR_UPLINK_QUALITY, //!< SR_UPLINK_QUALITY
+ SR_NOT_DEFINED //!< SR_NOT_DEFINED
} signalReport_t;
@@ -69,7 +69,7 @@ void transportSetAddress(const uint8_t address);
/**
* @brief Retrieve node address
*/
-uint8_t transportGetAddress(void);
+uint8_t transportGetAddress(void) __attribute__((unused));
/**
* @brief Send message
* @param to recipient
@@ -78,7 +78,7 @@ uint8_t transportGetAddress(void);
* @param noACK do not wait for ACK
* @return true if message sent successfully
*/
-bool transportSend(const uint8_t to, const void* data, const uint8_t len,
+bool transportSend(const uint8_t to, const void *data, const uint8_t len,
const bool noACK = false);
/**
* @brief Verify if RX FIFO has pending messages
@@ -86,7 +86,7 @@ bool transportSend(const uint8_t to, const void* data, const uint8_t len,
*/
bool transportAvailable(void);
/**
-* @brief Sanity check for transport: is transport still responsive?
+* @brief Sanity check for transport: is transport HW still responsive?
* @return true if transport HW is ok
*/
bool transportSanityCheck(void);
@@ -94,7 +94,7 @@ bool transportSanityCheck(void);
* @brief Receive message from FIFO
* @return length of received message (header + payload)
*/
-uint8_t transportReceive(void* data);
+uint8_t transportReceive(void *data);
/**
* @brief Power down transport HW (if corresponding MY_XYZ_POWER_PIN defined)
*/
@@ -113,30 +113,36 @@ void transportSleep(void);
void transportStandBy(void);
/**
* @brief transportGetSendingRSSI
-* @return RSSI
+* @return RSSI of outgoing message (via ACK packet)
*/
int16_t transportGetSendingRSSI(void);
/**
* @brief transportGetReceivingRSSI
-* @return RSSI
+* @return RSSI of incoming message
*/
int16_t transportGetReceivingRSSI(void);
/**
* @brief transportGetSendingSNR
-* @return SNR
+* @return SNR of outgoing message (via ACK packet)
*/
int16_t transportGetSendingSNR(void);
/**
* @brief transportGetReceivingSNR
-* @return SNR
+* @return SNR of incoming message
*/
int16_t transportGetReceivingSNR(void);
/**
* @brief transportGetTxPowerPercent
-* @return TX power in percent
+* @return TX power level in percent
*/
int16_t transportGetTxPowerPercent(void);
/**
+* @brief transportSetTxPowerPercent
+* @param powerPercent power level in percent
+* @return True if power level set
+*/
+bool transportSetTxPowerPercent(const uint8_t powerPercent) __attribute__((unused));
+/**
* @brief transportGetTxPowerLevel
* @return TX power in dBm
*/
diff --git a/hal/transport/MyTransportNRF5_ESB.cpp b/hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp
similarity index 76%
rename from hal/transport/MyTransportNRF5_ESB.cpp
rename to hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp
index 93f1366bf..ddc29a6b4 100644
--- a/hal/transport/MyTransportNRF5_ESB.cpp
+++ b/hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp
@@ -2,12 +2,11 @@
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
- * repeater and gateway builds a routing tables in EEPROM which keeps track of
- * the
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2015 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Copyright (C) 2017 Frank Holtz
* Full contributor list:
* https://github.com/mysensors/Arduino/graphs/contributors
@@ -20,37 +19,33 @@
* version 2 as published by the Free Software Foundation.
*/
-#include "MyTransportHAL.h"
#include "drivers/NRF5/Radio.h"
#include "drivers/NRF5/Radio_ESB.h"
#include "drivers/CircularBuffer/CircularBuffer.h"
#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
-#include "drivers/AES/AES.h"
-#endif
-
-#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
-AES _aes;
-uint8_t _dataenc[32] = {0};
-uint8_t _psk[16];
+#include "drivers/AES/AES.cpp"
+AES NRF5_ESB_aes;
+uint8_t NRF5_ESB_dataenc[32] = {0};
#endif
bool transportInit(void)
{
#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
-#ifdef MY_SIGNING_SIMPLE_PASSWD
- memset(_psk, 0, 16);
- memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
+ uint8_t NRF5_ESB_psk[16];
+#ifdef MY_ENCRYPTION_SIMPLE_PASSWD
+ (void)memset(NRF5_ESB_psk, 0, 16);
+ (void)memcpy(NRF5_ESB_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16));
#else
- hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+ hwReadConfigBlock((void*)NRF5_ESB_psk, (void*)EEPROM_RF_ENCRYPTION_KEY_ADDRESS,
+ 16);
#endif
// set up AES-key
- _aes.set_key(_psk, 16);
+ NRF5_ESB_aes.set_key(NRF5_ESB_psk, 16);
// Make sure it is purged from memory when set
- memset(_psk, 0, 16);
+ (void)memset(NRF5_ESB_psk, 0, 16);
#endif
-
return NRF5_ESB_initialize();
}
@@ -69,13 +64,13 @@ bool transportSend(const uint8_t to, const void *data, const uint8_t len, const
{
#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
// copy input data because it is read-only
- (void)memcpy(_dataenc, data, len);
+ (void)memcpy(NRF5_ESB_dataenc, data, len);
// has to be adjusted, WIP!
- _aes.set_IV(0);
+ NRF5_ESB_aes.set_IV(0);
const uint8_t finalLength = len > 16 ? 32 : 16;
// encrypt data
- _aes.cbc_encrypt(_dataenc, _dataenc, finalLength / 16);
- return NRF5_ESB_sendMessage(to, _dataenc, finalLength, noACK);
+ NRF5_ESB_aes.cbc_encrypt(NRF5_ESB_dataenc, NRF5_ESB_dataenc, finalLength / 16);
+ return NRF5_ESB_sendMessage(to, NRF5_ESB_dataenc, finalLength, noACK);
#else
return NRF5_ESB_sendMessage(to, data, len, noACK);
#endif
@@ -97,10 +92,10 @@ uint8_t transportReceive(void *data)
len = NRF5_ESB_readMessage(data);
#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION)
// has to be adjusted, WIP!
- _aes.set_IV(0);
+ NRF5_ESB_aes.set_IV(0);
// decrypt data
- if (_aes.cbc_decrypt((uint8_t *)(data), (uint8_t *)(data),
- len > 16 ? 2 : 1) != AES_SUCCESS) {
+ if (NRF5_ESB_aes.cbc_decrypt((uint8_t *)(data), (uint8_t *)(data),
+ len > 16 ? 2 : 1) != AES_SUCCESS) {
len = 0;
}
#endif
diff --git a/hal/transport/MyTransportRF24.cpp b/hal/transport/RF24/MyTransportRF24.cpp
similarity index 83%
rename from hal/transport/MyTransportRF24.cpp
rename to hal/transport/RF24/MyTransportRF24.cpp
index 10d694963..85b1b0b10 100644
--- a/hal/transport/MyTransportRF24.cpp
+++ b/hal/transport/RF24/MyTransportRF24.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -17,11 +17,12 @@
* version 2 as published by the Free Software Foundation.
*/
-#include "MyTransportHAL.h"
#include "drivers/RF24/RF24.h"
#if defined(MY_RF24_ENABLE_ENCRYPTION)
-#include "drivers/AES/AES.h"
+#include "drivers/AES/AES.cpp"
+AES RF24_aes;
+uint8_t RF24_dataenc[32] = {0};
#endif
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
@@ -59,25 +60,20 @@ static void transportRxCallback(void)
}
#endif
-#if defined(MY_RF24_ENABLE_ENCRYPTION)
-AES _aes;
-uint8_t _dataenc[32] = {0};
-uint8_t _psk[16];
-#endif
-
bool transportInit(void)
{
#if defined(MY_RF24_ENABLE_ENCRYPTION)
-#ifdef MY_SIGNING_SIMPLE_PASSWD
- memset(_psk, 0, 16);
- memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
+ uint8_t RF24_psk[16];
+#ifdef MY_ENCRYPTION_SIMPLE_PASSWD
+ (void)memset(RF24_psk, 0, 16);
+ (void)memcpy(RF24_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16));
#else
- hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+ hwReadConfigBlock((void *)RF24_psk, (void *)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
#endif
//set up AES-key
- _aes.set_key(_psk, 16);
+ RF24_aes.set_key(RF24_psk, 16);
// Make sure it is purged from memory when set
- memset(_psk, 0, 16);
+ (void)memset(RF24_psk, 0, 16);
#endif
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
@@ -97,17 +93,17 @@ uint8_t transportGetAddress(void)
return RF24_getNodeID();
}
-bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK)
+bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK)
{
#if defined(MY_RF24_ENABLE_ENCRYPTION)
// copy input data because it is read-only
- (void)memcpy(_dataenc,data,len);
+ (void)memcpy(RF24_dataenc,data,len);
// has to be adjusted, WIP!
- _aes.set_IV(0);
+ RF24_aes.set_IV(0);
const uint8_t finalLength = len > 16 ? 32 : 16;
//encrypt data
- _aes.cbc_encrypt(_dataenc, _dataenc, finalLength /16);
- return RF24_sendMessage(to, _dataenc, finalLength, noACK);
+ RF24_aes.cbc_encrypt(RF24_dataenc, RF24_dataenc, finalLength / 16);
+ return RF24_sendMessage(to, RF24_dataenc, finalLength, noACK);
#else
return RF24_sendMessage(to, data, len, noACK);
#endif
@@ -128,7 +124,7 @@ bool transportSanityCheck(void)
return RF24_sanityCheck();
}
-uint8_t transportReceive(void* data)
+uint8_t transportReceive(void *data)
{
uint8_t len = 0;
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
@@ -143,9 +139,9 @@ uint8_t transportReceive(void* data)
#endif
#if defined(MY_RF24_ENABLE_ENCRYPTION)
// has to be adjusted, WIP!
- _aes.set_IV(0);
+ RF24_aes.set_IV(0);
// decrypt data
- if (_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) {
+ if (RF24_aes.cbc_decrypt((uint8_t *)data, (uint8_t *)data, len > 16 ? 2 : 1) != AES_SUCCESS) {
len = 0;
}
#endif
@@ -176,6 +172,7 @@ int16_t transportGetSendingRSSI(void)
{
return RF24_getSendingRSSI();
}
+
int16_t transportGetReceivingRSSI(void)
{
// not available, only bool RPD
@@ -206,5 +203,3 @@ bool transportSetTxPowerPercent(const uint8_t powerPercent)
{
return RF24_setTxPowerPercent(powerPercent);
}
-
-
diff --git a/hal/transport/MyTransportRFM69.cpp b/hal/transport/RFM69/MyTransportRFM69.cpp
similarity index 74%
rename from hal/transport/MyTransportRFM69.cpp
rename to hal/transport/RFM69/MyTransportRFM69.cpp
index 39c5562f6..b1ff3db1f 100644
--- a/hal/transport/MyTransportRFM69.cpp
+++ b/hal/transport/RFM69/MyTransportRFM69.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -17,8 +17,6 @@
* version 2 as published by the Free Software Foundation.
*/
-#include "MyTransportHAL.h"
-
#if defined(MY_RFM69_NEW_DRIVER)
#include "drivers/RFM69/new/RFM69_new.h"
@@ -26,23 +24,26 @@
bool transportInit(void)
{
const bool result = RFM69_initialise(MY_RFM69_FREQUENCY);
-#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM69_ATC_MODE_DISABLED)
- // only enable ATC mode nodes
+#if defined(MY_GATEWAY_FEATURE) || defined(MY_RFM69_ATC_MODE_DISABLED)
+ // ATC mode function not used
+ (void)RFM69_ATCmode;
+#else
RFM69_ATCmode(true, MY_RFM69_ATC_TARGET_RSSI_DBM);
#endif
#ifdef MY_RFM69_ENABLE_ENCRYPTION
- uint8_t _psk[16];
-#ifdef MY_SIGNING_SIMPLE_PASSWD
- memset(_psk, 0, 16);
- memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
+ uint8_t RFM69_psk[16];
+#ifdef MY_ENCRYPTION_SIMPLE_PASSWD
+ (void)memset(RFM69_psk, 0, 16);
+ (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16));
#else
- hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+ hwReadConfigBlock((void *)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
#endif
- RFM69_encrypt((const char*)_psk);
- (void)memset(_psk, 0, 16); // Make sure it is purged from memory when set
+ RFM69_encrypt((const char *)RFM69_psk);
+ (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set
+#else
+ (void)RFM69_encrypt;
#endif
-
return result;
}
@@ -56,7 +57,7 @@ uint8_t transportGetAddress(void)
return RFM69_getAddress();
}
-bool transportSend(const uint8_t to, const void* data, uint8_t len, const bool noACK)
+bool transportSend(const uint8_t to, const void *data, uint8_t len, const bool noACK)
{
if (noACK) {
(void)RFM69_sendWithRetry(to, data, len, 0, 0);
@@ -67,6 +68,7 @@ bool transportSend(const uint8_t to, const void* data, uint8_t len, const bool n
bool transportAvailable(void)
{
+ RFM69_handler();
return RFM69_available();
}
@@ -75,9 +77,9 @@ bool transportSanityCheck(void)
return RFM69_sanityCheck();
}
-uint8_t transportReceive(void* data)
+uint8_t transportReceive(void *data)
{
- return RFM69_recv((uint8_t*)data, MAX_MESSAGE_LENGTH);
+ return RFM69_receive((uint8_t *)data, MAX_MESSAGE_LENGTH);
}
void transportSleep(void)
@@ -106,7 +108,7 @@ bool transportSetTxPowerLevel(const uint8_t powerLevel)
return RFM69_setTxPowerLevel(powerLevel);
}
-void transportSetTargetRSSI(int16_t targetSignalStrength)
+void transportSetTargetRSSI(const int16_t targetSignalStrength)
{
#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM69_ATC_MODE_DISABLED)
RFM69_ATCmode(true, targetSignalStrength);
@@ -144,6 +146,7 @@ int16_t transportGetTxPowerLevel(void)
{
return RFM69_getTxPowerLevel();
}
+
bool transportSetTxPowerPercent(const uint8_t powerPercent)
{
return RFM69_setTxPowerPercent(powerPercent);
@@ -167,15 +170,15 @@ bool transportInit(void)
// Start up the radio library (_address will be set later by the MySensors library)
if (_radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID)) {
#ifdef MY_RFM69_ENABLE_ENCRYPTION
- uint8_t _psk[16];
-#ifdef MY_SIGNING_SIMPLE_PASSWD
- memset(_psk, 0, 16);
- memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
+ uint8_t RFM69_psk[16];
+#ifdef MY_ENCRYPTION_SIMPLE_PASSWD
+ (void)memset(RFM69_psk, 0, 16);
+ (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16));
#else
- hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+ hwReadConfigBlock((void *)RFM69_psk, (void *)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
#endif
- _radio.encrypt((const char*)_psk);
- (void)memset(_psk, 0, 16); // Make sure it is purged from memory when set
+ _radio.encrypt((const char *)RFM69_psk);
+ (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set
#endif
return true;
}
@@ -193,7 +196,7 @@ uint8_t transportGetAddress(void)
return _address;
}
-bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK)
+bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK)
{
if (noACK) {
(void)_radio.sendWithRetry(to, data, len, 0, 0);
@@ -212,11 +215,11 @@ bool transportSanityCheck(void)
return _radio.sanityCheck();
}
-uint8_t transportReceive(void* data)
+uint8_t transportReceive(void *data)
{
// save payload length
const uint8_t dataLen = _radio.DATALEN < MAX_MESSAGE_LENGTH? _radio.DATALEN : MAX_MESSAGE_LENGTH;
- (void)memcpy((void*)data, (void*)_radio.DATA, dataLen);
+ (void)memcpy((void *)data, (void *)_radio.DATA, dataLen);
// Send ack back if this message wasn't a broadcast
if (_radio.ACKRequested()) {
_radio.sendACK();
@@ -233,10 +236,12 @@ void transportStandBy(void)
{
_radio.standBy();
}
+
void transportPowerDown(void)
{
_radio.powerDown();
}
+
void transportPowerUp(void)
{
_radio.powerUp();
@@ -272,4 +277,11 @@ int16_t transportGetTxPowerLevel(void)
return INVALID_LEVEL;
}
+bool transportSetTxPowerLevel(const uint8_t powerLevel)
+{
+ // not implemented
+ (void)powerLevel;
+ return false;
+}
+
#endif
diff --git a/hal/transport/MyTransportRFM95.cpp b/hal/transport/RFM95/MyTransportRFM95.cpp
similarity index 60%
rename from hal/transport/MyTransportRFM95.cpp
rename to hal/transport/RFM95/MyTransportRFM95.cpp
index 5d6278f7b..5e3bd648a 100644
--- a/hal/transport/MyTransportRFM95.cpp
+++ b/hal/transport/RFM95/MyTransportRFM95.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -15,14 +15,38 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
- *
*/
-#include "MyTransportHAL.h"
#include "drivers/RFM95/RFM95.h"
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+#include "drivers/AES/AES.h"
+#endif
+
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+AES RFM95_aes;
+uint8_t RFM95_dataenc[32] = {0};
+#endif
+
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+#include "drivers/AES/AES.cpp"
+#endif
bool transportInit(void)
{
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+ uint8_t RFM95_psk[16];
+#ifdef MY_SIGNING_SIMPLE_PASSWD
+ memset(RFM95_psk, 0, 16);
+ memcpy(RFM95_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16));
+#else
+ hwReadConfigBlock((void*)RFM95_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+#endif
+ //set up AES-key
+ RFM95_aes.set_key(RFM95_psk, 16);
+ // Make sure it is purged from memory when set
+ memset(RFM95_psk, 0, 16);
+#endif
+
const bool result = RFM95_initialise(MY_RFM95_FREQUENCY);
#if defined(MY_RFM95_TCXO)
RFM95_enableTCXO();
@@ -44,17 +68,33 @@ uint8_t transportGetAddress(void)
return RFM95_getAddress();
}
-bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK)
+bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK)
{
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+ // copy input data because it is read-only
+ (void)memcpy(RFM95_dataenc,data,len);
+ // has to be adjusted, WIP!
+ RFM95_aes.set_IV(0);
+ const uint8_t finalLength = len > 16 ? 32 : 16;
+ //encrypt data
+ RFM95_aes.cbc_encrypt(RFM95_dataenc, RFM95_dataenc, finalLength /16);
+ if (noACK) {
+ (void)RFM95_sendWithRetry(to, RFM95_dataenc, finalLength, 0, 0);
+ return true;
+ }
+ return RFM95_sendWithRetry(to, RFM95_dataenc, finalLength);
+#else
if (noACK) {
(void)RFM95_sendWithRetry(to, data, len, 0, 0);
return true;
}
return RFM95_sendWithRetry(to, data, len);
+#endif
}
bool transportAvailable(void)
{
+ RFM95_handler();
return RFM95_available();
}
@@ -63,9 +103,17 @@ bool transportSanityCheck(void)
return RFM95_sanityCheck();
}
-uint8_t transportReceive(void* data)
+uint8_t transportReceive(void *data)
{
- const uint8_t len = RFM95_recv((uint8_t*)data, MAX_MESSAGE_LENGTH);
+ uint8_t len = RFM95_receive((uint8_t*)data, MAX_MESSAGE_LENGTH);
+#if defined(MY_RFM95_ENABLE_ENCRYPTION)
+ // has to be adjusted, WIP!
+ RFM95_aes.set_IV(0);
+ // decrypt data
+ if (RFM95_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) {
+ len = 0;
+ }
+#endif
return len;
}
diff --git a/hal/transport/MyTransportRS485.cpp b/hal/transport/RS485/MyTransportRS485.cpp
similarity index 98%
rename from hal/transport/MyTransportRS485.cpp
rename to hal/transport/RS485/MyTransportRS485.cpp
index 1f4a1256f..00e869598 100644
--- a/hal/transport/MyTransportRS485.cpp
+++ b/hal/transport/RS485/MyTransportRS485.cpp
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2017 Sensnology AB
+ * Copyright (C) 2013-2018 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -52,9 +52,6 @@
// Serial Transport
-
-#include "MyTransportHAL.h"
-
#ifdef __linux__
#include "SerialPort.h"
#endif
@@ -158,6 +155,12 @@ bool _serialProcess()
_recPhase = 1;
_recPos = 0;
+ //Avoid _data[] overflow
+ if (_recLen >= MY_RS485_MAX_MESSAGE_LENGTH) {
+ _serialReset();
+ break;
+ }
+
//Check if we should process this message
//We reject the message if we are the sender
//We reject if we are not the receiver and message is not a broadcast
@@ -367,15 +370,17 @@ void transportPowerDown(void)
void transportPowerUp(void)
{
-
+ // not implemented
}
+
void transportSleep(void)
{
-
+ // not implemented
}
+
void transportStandBy(void)
{
-
+ // not implemented
}
int16_t transportGetSendingRSSI(void)
diff --git a/initscripts/mysgw.systemd b/initscripts/mysgw.systemd
index 41e7279e5..d983ab27f 100644
--- a/initscripts/mysgw.systemd
+++ b/initscripts/mysgw.systemd
@@ -3,7 +3,7 @@ Description=MySensors Gateway daemon
Requires=network.target
[Service]
-ExecStart=%gateway_dir%/mysgw
+ExecStart=%gateway_dir%/mysgw -q
[Install]
WantedBy=multi-user.target
diff --git a/initscripts/mysgw.sysvinit b/initscripts/mysgw.sysvinit
index a511f0567..c24fde902 100644
--- a/initscripts/mysgw.sysvinit
+++ b/initscripts/mysgw.sysvinit
@@ -17,7 +17,7 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
DESC="MySensors Gateway"
NAME=mysgw
DAEMON=%gateway_dir%/$NAME
-DAEMON_ARGS="-b"
+DAEMON_ARGS="--daemon -q"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
diff --git a/keywords.txt b/keywords.txt
index 11951d69b..3361eec01 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -30,98 +30,137 @@ smartSleep KEYWORD2
# Constants (LITERAL1)
#######################################
# General
-MY_CORE_ONLY LITERAL1
-MY_DISABLE_REMOTE_RESET LITERAL1
-MY_SMART_SLEEP_WAIT_DURATION LITERAL1
MY_BAUD_RATE LITERAL1
+MY_CORE_ONLY LITERAL1
+MY_CORE_MIN_VERSION LITERAL1
+MY_CORE_VERSION LITERAL1
MY_CRITICAL_SECTION LITERAL1
+MY_DISABLE_RAM_ROUTING_TABLE_FEATURE LITERAL1
+MY_DISABLE_REMOTE_RESET LITERAL1
+MY_DISABLED_SERIAL LITERAL1
+MY_INDICATION_HANDLER LITERAL1
MY_RX_MESSAGE_BUFFER_SIZE LITERAL1
MY_RX_MESSAGE_BUFFER_FEATURE LITERAL1
+MY_SERIAL_OUTPUT_SIZE LITERAL1
+MY_SLEEP_NOT_POSSIBLE LITERAL1
+MY_SMART_SLEEP_WAIT_DURATION LITERAL1
+MY_SPLASH_SCREEN_DISABLED LITERAL1
+MY_WAKE_UP_BY_TIMER LITERAL1
# transport
AUTO LITERAL1
-MY_NODE_ID LITERAL1
+MY_CORE_COMPATIBILITY_CHECK LITERAL1
MY_DEBUG_VERBOSE_TRANSPORT LITERAL1
+MY_NODE_ID LITERAL1
MY_PARENT_NODE_ID LITERAL1
MY_PARENT_NODE_IS_STATIC LITERAL1
-MY_REGISTRATION_FEATURE LITERAL1
-MY_REGISTRATION_DEFAULT LITERAL1
+MY_PASSIVE_NODE LITERAL1
+MY_RAM_ROUTING_TABLE_FEATURE LITERAL1
MY_REGISTRATION_CONTROLLER LITERAL1
-MY_CORE_COMPATIBILITY_CHECK LITERAL1
+MY_REGISTRATION_DEFAULT LITERAL1
+MY_REGISTRATION_FEATURE LITERAL1
+MY_REGISTRATION_RETRIES LITERAL1
+MY_REPEATER_FEATURE LITERAL1
+MY_ROUTING_TABLE_SAVE_INTERVAL_MS LITERAL1
+MY_SIGNAL_REPORT_ENABLED LITERAL1
+MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS LITERAL1
+MY_SMART_SLEEP_WAIT_DURATION_MS LITERAL1
+MY_TRANSPORT_CHKUPL_INTERVAL_MS LITERAL1
+MY_TRANSPORT_DISCOVERY_INTERVAL_MS LITERAL1
+MY_TRANSPORT_MAX_TSM_FAILURES LITERAL1
+MY_TRANSPORT_MAX_TX_FAILURES LITERAL1
MY_TRANSPORT_SANITY_CHECK LITERAL1
MY_TRANSPORT_SANITY_CHECK_INTERVAL LITERAL1
+MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS LITERAL1
+MY_TRANSPORT_STATE_RETRIES LITERAL1
+MY_TRANSPORT_STATE_TIMEOUT_MS LITERAL1
+MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE_MS LITERAL1
+MY_TRANSPORT_TIMEOUT_FAILURE_STATE_MS LITERAL1
+MY_TRANSPORT_UPLINK_CHECK_DISABLED LITERAL1
MY_TRANSPORT_WAIT_READY_MS LITERAL1
-MY_REPEATER_FEATURE LITERAL1
-MY_PASSIVE_NODE LITERAL1
# debug
MY_DEBUG LITERAL1
MY_DEBUGDEVICE LITERAL1
-MY_DEBUG_OTA LITERAL1
-MY_DEBUG_OTA_DISABLE_ACK LITERAL1
+MY_DEBUG_VERBOSE_GATEWAY LITERAL1
MY_SPECIAL_DEBUG LITERAL1
# OTA
-MY_OTA_FIRMWARE_FEATURE LITERAL1
-MY_OTA_FLASH_SS LITERAL1
-MY_OTA_FLASH_JDECID LITERAL1
-MY_SPIFLASH_SST25TYPE LITERAL1
+MY_DEBUG_OTA LITERAL1
+MY_DEBUG_OTA_DISABLE_ACK LITERAL1
MY_DEBUG_VERBOSE_OTA_UPDATE LITERAL1
-MY_WITH_LEDS_BLINKING_INVERSE LITERAL1
+MY_DEFAULT_ERR_LED_PIN LITERAL1
MY_DEFAULT_LED_BLINK_PERIOD LITERAL1
-MY_WITH_LEDS_BLINKING_INVERSE LITERAL1
MY_DEFAULT_RX_LED_PIN LITERAL1
MY_DEFAULT_TX_LED_PIN LITERAL1
-MY_DEFAULT_ERR_LED_PIN LITERAL1
MY_INCLUSION_MODE_FEATURE LITERAL1
MY_INCLUSION_BUTTON_FEATURE LITERAL1
MY_INCLUSION_MODE_BUTTON_PIN LITERAL1
MY_INCLUSION_MODE_DURATION LITERAL1
+MY_INCLUSION_LED_PIN LITERAL1
+MY_OTA_FIRMWARE_FEATURE LITERAL1
+MY_OTA_FLASH_SS LITERAL1
+MY_OTA_FLASH_JDECID LITERAL1
MY_OTA_LOG_RECEIVER_FEATURE LITERAL1
MY_OTA_LOG_SENDER_FEATURE LITERAL1
-MY_DEBUG_OTA LITERAL1
-MY_DEBUG_OTA_DISABLE_ACK LITERAL1
+MY_OTA_USE_I2C_EEPROM LITERAL1
+MY_SPIFLASH_SST25TYPE LITERAL1
+MY_WITH_LEDS_BLINKING_INVERSE LITERAL1
# Signing
MY_DEBUG_VERBOSE_SIGNING LITERAL1
-MY_SIGNING_SIMPLE_PASSWD LITERAL1
+MY_ENCRYPTION_SIMPLE_PASSWD LITERAL1
+MY_NODE_LOCK_FEATURE LITERAL1
+MY_NODE_UNLOCK_PIN LITERAL1
+MY_NODE_LOCK_COUNTER_MAX LITERAL1
+MY_SECURITY_SIMPLE_PASSWD LITERAL1
MY_SIGNING_ATSHA204 LITERAL1
-MY_SIGNING_SOFT LITERAL1
-MY_VERIFICATION_TIMEOUT_MS LITERAL1
-MY_SIGNING_NODE_WHITELISTING LITERAL1
MY_SIGNING_ATSHA204_PIN LITERAL1
+MY_SIGNING_NODE_WHITELISTING LITERAL1
+MY_SIGNING_SIMPLE_PASSWD LITERAL1
+MY_SIGNING_SOFT LITERAL1
MY_SIGNING_SOFT_RANDOMSEED_PIN LITERAL1
MY_SIGNING_REQUEST_SIGNATURES LITERAL1
MY_SIGNING_WEAK_SECURITY LITERAL1
-MY_NODE_LOCK_FEATURE LITERAL1
-MY_NODE_UNLOCK_PIN LITERAL1
-MY_NODE_LOCK_COUNTER_MAX LITERAL1
+MY_VERIFICATION_TIMEOUT_MS LITERAL1
# Random
MY_HW_HAS_GETENTROPY LITERAL1
hwGetentropy KEYWORD2
+# TinyGSM
+MY_GATEWAY_TINYGSM LITERAL1
+MY_GSM_APN LITERAL1
+MY_GSM_BAUDRATE LITERAL1
+MY_GSM_PIN LITERAL1
+MY_GSM_PSW LITERAL1
+MY_GSM_RX LITERAL1
+MY_GSM_SSID LITERAL1
+MY_GSM_TX LITERAL1
+MY_GSM_USR LITERAL1
+
# SoftSPI
MY_SOFTSPI LITERAL1
-MY_SOFT_SPI_SCK_PIN LITERAL1
MY_SOFT_SPI_MISO_PIN LITERAL1
MY_SOFT_SPI_MOSI_PIN LITERAL1
+MY_SOFT_SPI_SCK_PIN LITERAL1
# RF24
-MY_RADIO_RF24 LITERAL1
MY_DEBUG_VERBOSE_RF24 LITERAL1
+MY_RADIO_RF24 LITERAL1
+MY_RF24_ADDR_WIDTH LITERAL1
+MY_RF24_BASE_RADIO_ID LITERAL1
MY_RF24_ENABLE_ENCRYPTION LITERAL1
-MY_RF24_SPI_SPEED LITERAL1
MY_RF24_CE_PIN LITERAL1
+MY_RF24_CHANNEL LITERAL1
MY_RF24_CS_PIN LITERAL1
+MY_RF24_DATARATE LITERAL1
MY_RF24_IRQ_PIN LITERAL1
MY_RF24_PA_LEVEL LITERAL1
-MY_RF24_CHANNEL LITERAL1
-MY_RF24_DATARATE LITERAL1
-MY_RF24_BASE_RADIO_ID LITERAL1
+MY_RF24_POWER_PIN LITERAL1
+MY_RF24_SPI_SPEED LITERAL1
# NRF5
-MY_RADIO_NRF5_ESB LITERAL1
MY_DEBUG_VERBOSE_NRF5_ESB LITERAL1
MY_NRF5_ESB_ADDR_WIDTH LITERAL1
MY_NRF5_ESB_BASE_RADIO_ID LITERAL1
@@ -130,84 +169,187 @@ MY_NRF5_ESB_ENABLE_ENCRYPTION LITERAL1
MY_NRF5_ESB_MODE LITERAL1
MY_NRF5_ESB_PA_LEVEL LITERAL1
MY_NRF5_ESB_RX_BUFFER_SIZE LITERAL1
+MY_NRF5_ESB_REVERSE_ACK_RX LITERAL1
+MY_NRF5_ESB_REVERSE_ACK_TX LITERAL1
+MY_RADIO_NRF5_ESB LITERAL1
# RFM95
-MY_RADIO_RFM95 LITERAL1
MY_DEBUG_VERBOSE_RFM95 LITERAL1
-MY_RFM95_MODEM_CONFIGRUATION LITERAL1
-MY_RFM95_FREQUENCY LITERAL1
-MY_RFM95_TX_POWER LITERAL1
-MY_RFM95_CS_PIN LITERAL1
-MY_RFM95_RST_PIN LITERAL1
-MY_RFM95_SPI_SPEED LITERAL1
-MY_RFM95_IRQ_PIN LITERAL1
-MY_RFM95_ATC_TARGET_RSSI LITERAL1
+MY_RADIO_RFM95 LITERAL1
MY_RFM95_ATC_MODE_DISABLED LITERAL1
+MY_RFM95_ATC_TARGET_RSSI LITERAL1
MY_RFM95_ATC_TARGET_RSSI_DBM LITERAL1
+MY_RFM95_CS_PIN LITERAL1
+MY_RFM95_FREQUENCY LITERAL1
+MY_RFM95_IRQ_NUM LITERAL1
+MY_RFM95_IRQ_PIN LITERAL1
MY_RFM95_MAX_POWER_LEVEL_DBM LITERAL1
+MY_RFM95_MODEM_CONFIGRUATION LITERAL1
+MY_RFM95_POWER_PIN LITERAL1
+MY_RFM95_RST_PIN LITERAL1
+MY_RFM95_SPI_SPEED LITERAL1
+MY_RFM95_TCXO LITERAL1
+MY_RFM95_TX_POWER LITERAL1
+MY_RFM95_TX_POWER_DBM LITERAL1
+MY_RFM95_TX_TIMEOUT_MS LITERAL1
+MY_RFM95_ENABLE_ENCRYPTION LITERAL1
# RFM69
-MY_RADIO_RFM69 LITERAL1
MY_DEBUG_VERBOSE_RFM69 LITERAL1
MY_DEBUG_VERBOSE_RFM69_REGISTERS LITERAL1
-MY_RFM69_FREQUENCY LITERAL1
MY_IS_RFM69HW LITERAL1
-MY_RFM69_NEW_DRIVER LITERAL1
-MY_RFM69_TX_POWER_DBM LITERAL1
-MY_RFM69_ATC_TARGET_RSSI_DBM LITERAL1
+MY_RADIO_RFM69 LITERAL1
MY_RFM69_ATC_MODE_DISABLED LITERAL1
-MY_RFM69_MAX_POWER_LEVEL_DBM LITERAL1
-MY_RFM69_NETWORKID LITERAL1
-MY_RFM69_RST_PIN LITERAL1
-MY_RFM69_IRQ_PIN LITERAL1
+MY_RFM69_ATC_TARGET_RSSI_DBM LITERAL1
+MY_RFM69_BITRATE_LSB LITERAL1
+MY_RFM69_BITRATE_MSB LITERAL1
MY_RFM69_CS_PIN LITERAL1
+MY_RFM69_CSMA_ADD_DELAY_BASE LITERAL1
+MY_RFM69_CSMA_ADD_DELAY_COUNT LITERAL1
+MY_RFM69_CSMA_LIMIT_DBM LITERAL1
+MY_RFM69_CSMA_TIMEOUT_MS LITERAL1
+MY_RFM69_DEFAULT_LISTEN_IDLE_US LITERAL1
+MY_RFM69_DEFAULT_LISTEN_RX_US LITERAL1
MY_RFM69_ENABLE_ENCRYPTION LITERAL1
MY_RFM69_ENABLE_LISTENMODE LITERAL1
-MY_RFM69_DEFAULT_LISTEN_RX_US LITERAL1
-MY_RFM69_DEFAULT_LISTEN_IDLE_US LITERAL1
+MY_RFM69_FREQUENCY LITERAL1
+MY_RFM69_IRQ_NUM LITERAL1
+MY_RFM69_IRQ_PIN LITERAL1
+MY_RFM69_MAX_POWER_LEVEL_DBM LITERAL1
+MY_RFM69_MODEM_CONFIGURATION LITERAL1
+MY_RFM69_NETWORKID LITERAL1
+MY_RFM69_NEW_DRIVER LITERAL1
+MY_RFM69_POWER_PIN LITERAL1
+MY_RFM69_RST_PIN LITERAL1
MY_RFM69_SPI_SPEED LITERAL1
-MY_RFM69_BITRATE_MSB LITERAL1
-MY_RFM69_BITRATE_LSB LITERAL1
-MY_RFM69_CSMA_ADD_DELAY_BASE LITERAL1
-MY_RFM69_CSMA_ADD_DELAY_COUNT LITERAL1
+MY_RFM69_TX_TIMEOUT_MS LITERAL1
+MY_RFM69_TX_POWER_DBM LITERAL1
# RS485
MY_RS485 LITERAL1
MY_RS485_BAUD_RATE LITERAL1
-MY_RS485_MAX_MESSAGE_LENGTH LITERAL1
-MY_RS485_HWSERIAL LITERAL1
MY_RS485_DE_PIN LITERAL1
+MY_RS485_HWSERIAL LITERAL1
+MY_RS485_MAX_MESSAGE_LENGTH LITERAL1
MY_RS485_SOH_COUNT LITERAL1
# Gateway / MQTT
-MY_GATEWAY_SERIAL LITERAL1
-MY_GATEWAY_W5100 LITERAL1
-MY_W5100_SPI_EN LITERAL1
+MY_GATEWAY_CLIENT_MODE LITERAL1
MY_GATEWAY_ENC28J60 LITERAL1
+MY_GATEWAY_ESP32 LITERAL1
MY_GATEWAY_ESP8266 LITERAL1
+MY_GATEWAY_MQTT_CLIENT LITERAL1
+MY_GATEWAY_SERIAL LITERAL1
+MY_GATEWAY_W5100 LITERAL1
+MY_HOSTNAME LITERAL1
MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1
-MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1
-MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1
MY_MQTT_CLIENT_ID LITERAL1
-MY_GATEWAY_MQTT_CLIENT LITERAL1
+MY_MQTT_CLIENT_PUBLISH_RETAIN LITERAL1
+MY_MQTT_PASSWORD LITERAL1
+MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1
+MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1
+MY_MQTT_USER LITERAL1
+MY_W5100_SPI_EN LITERAL1
+MY_WIFI_SSID LITERAL1
+MY_WIFI_BSSID LITERAL1
+MY_WIFI_PASSWORD LITERAL1
# Ethernet
-MY_PORT LITERAL1
-MY_IP_ADDRESS LITERAL1
-MY_USE_UDP LITERAL1
-MY_IP_RENEWAL_INTERVAL LITERAL1
-MY_MAC_ADDRESS LITERAL1
MY_CONTROLLER_IP_ADDRESS LITERAL1
MY_CONTROLLER_URL_ADDRESS LITERAL1
MY_GATEWAY_MAX_CLIENTS LITERAL1
-MY_GATEWAY_MAX_SEND_LENGTH LITERAL1
MY_GATEWAY_MAX_RECEIVE_LENGTH LITERAL1
+MY_GATEWAY_MAX_SEND_LENGTH LITERAL1
+MY_IP_ADDRESS LITERAL1
MY_IP_GATEWAY_ADDRESS LITERAL1
+MY_IP_RENEWAL_INTERVAL LITERAL1
+MY_IP_RENEWAL_INTERVAL_MS LITERAL1
MY_IP_SUBNET_ADDRESS LITERAL1
+MY_MAC_ADDRESS LITERAL1
+MY_PORT LITERAL1
+MY_USE_UDP LITERAL1
+
+# ESP32
# ESP8266
-MY_ESP8266_SSID LITERAL1
-MY_ESP8266_PASSWORD LITERAL1
-MY_ESP8266_BSSID LITERAL1
-MY_ESP8266_HOSTNAME LITERAL1
MY_ESP8266_SERIAL_MODE LITERAL1
+
+# Blacklist - autodefines that are used internally and should not be highlighted, hence commented.
+# MY_CAP_ARCH
+# MY_CAP_ENCR
+# MY_CAP_OTA_FW
+# MY_CAP_RADIO
+# MY_CAP_RESET
+# MY_CAP_RXBUF
+# MY_CAP_SIGN
+# MY_CAP_TYPE
+# MY_CAPABILITIES
+# MY_DEBUG_VERBOSE_CORE
+# MY_GATEWAY_FEATURE
+# MY_RAM_ROUTING_TABLE_ENABLED
+# MY_RF24_CONFIGURATION
+# MY_RFM69HW
+# MY_SENSOR_NETWORK
+
+# Blacklist - defined in ArduinoHwSAMD and therefore not responsibility of the MySensors library
+# MY_BAT_DETECT
+# MY_SWC1
+# MY_SWC2
+
+# Blacklist - used by the Security Personalizer, not meant to be used in any other sketch
+# MY_AES_KEY
+# MY_ENCRYPTION_FEATURE
+# MY_HMAC_KEY
+# MY_LOCK_DEVICE
+# MY_LOCK_MCU
+# MY_SIGNING_FEATURE
+# MY_SOFT_SERIAL
+
+# Blacklist - internal, not meant to be used by users
+# MY_EEPROM_SIZE
+# MY_EXT_EEPROM_I2C_ADDRESS
+# MY_EXT_EEPROM_PAGE_SIZE
+# MY_EXT_EEPROM_SIZE
+# MY_EXT_EEPROM_TWI_CLOCK
+# MY_HW_ERR_LED_PIN
+# MY_HW_RTC
+# MY_HW_RTC_IRQ_HANDLER
+# MY_HW_RTC_IRQN
+# MY_HW_TX_LED_PIN
+# MY_HWID_PADDING_BYTE
+# MY_INCLUSION_BUTTON_PRESSED
+# MY_IS_GATEWAY
+# MY_NODE_TYPE
+# MY_OTA_BOOTLOADER_MAJOR_VERSION
+# MY_OTA_BOOTLOADER_MINOR_VERSION
+# MY_OTA_BOOTLOADER_VERSION
+# MY_OTA_RETRY
+# MY_OTA_RETRY_DELAY
+# MY_SDCARD_CS
+
+# Blacklist - used by the Raspberry Pi gateway and not meant to be used by users
+# MY_GATEWAY_LINUX
+# MY_LINUX_CONFIG_FILE
+# MY_LINUX_IS_SERIAL_PTY
+# MY_LINUX_SERIAL_GROUPNAME
+# MY_LINUX_SERIAL_IS_PTY
+# MY_LINUX_SERIAL_PORT
+# MY_LINUX_SERIAL_PTY
+
+# Blacklist - deprecated and should therefore not be highlighted anymore
+# MY_LEDS_BLINKING_FEATURE
+# MY_RADIO_NRF24
+# MY_RF69_IRQ_NUM
+# MY_RF69_IRQ_PIN
+# MY_RF69_RESET
+# MY_RF69_SPI_CS
+# MY_TRANSPORT_DONT_CARE_MODE
+# MY_ESP8266_BSSID LITERAL1
+# MY_ESP8266_HOSTNAME LITERAL1
+# MY_ESP8266_PASSWORD LITERAL1
+# MY_ESP8266_SSID LITERAL1
+
+# Blacklist - descriptional only
+# MY_XYZ_POWER_PIN
+# MY_MQTT_TOPIC_PREFIX
+
diff --git a/library.json b/library.json
index 9ada90e6b..53b328622 100644
--- a/library.json
+++ b/library.json
@@ -7,7 +7,7 @@
"type": "git",
"url": "https://github.com/mysensors/MySensors.git"
},
- "version": "2.2.0",
+ "version": "2.3.0",
"frameworks": "arduino",
"platforms": [
"atmelavr",
diff --git a/library.properties b/library.properties
index 6a61a5b57..acc31d30a 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=MySensors
-version=2.2.0
+version=2.3.0
author=The MySensors Team
maintainer=The MySensors Team
sentence=Home Automation Framework
diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino
index 510c72c8e..67fc11e4c 100644
--- a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino
+++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino
@@ -33,6 +33,6 @@
#ifndef MY_SIGNING_ATSHA204_PIN
#define MY_SIGNING_ATSHA204_PIN 17
#endif
-#define MY_RFM69_ENABLE_ENCRYPTION
+#define MY_RFM95_ENABLE_ENCRYPTION
#include