1052 lines
30 KiB
C++
1052 lines
30 KiB
C++
/*
|
|
* EBYTE LoRa E2200 Series
|
|
* https://www.mischianti.org/category/my-libraries/lora-e220-devices/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019 Renzo Mischianti www.mischianti.org All right reserved.
|
|
*
|
|
* You may copy, alter and reuse this code in any way you like, but please leave
|
|
* reference to www.mischianti.org in your comments if you redistribute this code.
|
|
*
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include "LoRa_E220.h"
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
SoftwareSerial* mySerial = new SoftwareSerial((uint8_t)this->txE220pin, (uint8_t)this->rxE220pin); // "RX TX" // @suppress("Abstract class cannot be instantiated")
|
|
this->ss = mySerial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, byte auxPin, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
this->auxPin = auxPin;
|
|
SoftwareSerial* mySerial = new SoftwareSerial((uint8_t)this->txE220pin, (uint8_t)this->rxE220pin); // "RX TX" // @suppress("Abstract class cannot be instantiated")
|
|
this->ss = mySerial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
this->auxPin = auxPin;
|
|
|
|
this->m0Pin = m0Pin;
|
|
this->m1Pin = m1Pin;
|
|
|
|
SoftwareSerial* mySerial = new SoftwareSerial((uint8_t)this->txE220pin, (uint8_t)this->rxE220pin); // "RX TX" // @suppress("Abstract class cannot be instantiated")
|
|
this->ss = mySerial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
#endif
|
|
|
|
LoRa_E220::LoRa_E220(HardwareSerial* serial, UART_BPS_RATE bpsRate){ //, uint32_t serialConfig
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->hs = serial;
|
|
|
|
// this->serialConfig = serialConfig;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate){ // , uint32_t serialConfig
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
this->auxPin = auxPin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->hs = serial;
|
|
|
|
// this->serialConfig = serialConfig;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate){ //, uint32_t serialConfig
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
this->auxPin = auxPin;
|
|
|
|
this->m0Pin = m0Pin;
|
|
this->m1Pin = m1Pin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->hs = serial;
|
|
// this->serialConfig = serialConfig;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
|
|
#ifdef HARDWARE_SERIAL_SELECTABLE_PIN
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, UART_BPS_RATE bpsRate, uint32_t serialConfig){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->serialConfig = serialConfig;
|
|
|
|
this->hs = serial;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate, uint32_t serialConfig){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
this->auxPin = auxPin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->serialConfig = serialConfig;
|
|
|
|
this->hs = serial;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate, uint32_t serialConfig){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
this->auxPin = auxPin;
|
|
|
|
this->m0Pin = m0Pin;
|
|
this->m1Pin = m1Pin;
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
this->ss = NULL;
|
|
#endif
|
|
|
|
this->serialConfig = serialConfig;
|
|
|
|
this->hs = serial;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
|
|
LoRa_E220::LoRa_E220(SoftwareSerial* serial, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
this->ss = serial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(SoftwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
this->auxPin = auxPin;
|
|
|
|
this->ss = serial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
LoRa_E220::LoRa_E220(SoftwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate){
|
|
this->txE220pin = txE220pin;
|
|
this->rxE220pin = rxE220pin;
|
|
|
|
this->auxPin = auxPin;
|
|
|
|
this->m0Pin = m0Pin;
|
|
this->m1Pin = m1Pin;
|
|
|
|
this->ss = serial;
|
|
this->hs = NULL;
|
|
|
|
this->bpsRate = bpsRate;
|
|
}
|
|
#endif
|
|
|
|
bool LoRa_E220::begin(){
|
|
DEBUG_PRINT("RX MIC ---> ");
|
|
DEBUG_PRINTLN(this->txE220pin);
|
|
DEBUG_PRINT("TX MIC ---> ");
|
|
DEBUG_PRINTLN(this->rxE220pin);
|
|
DEBUG_PRINT("AUX ---> ");
|
|
DEBUG_PRINTLN(this->auxPin);
|
|
DEBUG_PRINT("M0 ---> ");
|
|
DEBUG_PRINTLN(this->m0Pin);
|
|
DEBUG_PRINT("M1 ---> ");
|
|
DEBUG_PRINTLN(this->m1Pin);
|
|
|
|
if (this->auxPin != -1) {
|
|
pinMode(this->auxPin, INPUT);
|
|
DEBUG_PRINTLN("Init AUX pin!");
|
|
}
|
|
if (this->m0Pin != -1) {
|
|
// pinMode(this->m0Pin, OUTPUT);
|
|
DEBUG_PRINTLN("Init M0 pin!");
|
|
setMPins(this->m0Pin, HIGH);
|
|
|
|
}
|
|
if (this->m1Pin != -1) {
|
|
pinMode(this->m1Pin, OUTPUT);
|
|
DEBUG_PRINTLN("Init M1 pin!");
|
|
setMPins(this->m1Pin, HIGH);
|
|
|
|
}
|
|
|
|
DEBUG_PRINTLN("Begin ex");
|
|
if (this->hs){
|
|
DEBUG_PRINTLN("Begin Hardware Serial");
|
|
|
|
#ifdef HARDWARE_SERIAL_SELECTABLE_PIN
|
|
if(this->txE220pin != -1 && this->rxE220pin != -1) {
|
|
DEBUG_PRINTLN("PIN SELECTED!!");
|
|
this->serialDef.begin(*this->hs, this->bpsRate, this->serialConfig, this->txE220pin, this->rxE220pin);
|
|
}else{
|
|
this->serialDef.begin(*this->hs, this->bpsRate, this->serialConfig);
|
|
}
|
|
#endif
|
|
#ifndef HARDWARE_SERIAL_SELECTABLE_PIN
|
|
this->serialDef.begin(*this->hs, this->bpsRate);
|
|
#endif
|
|
while (!this->hs) {
|
|
; // wait for serial port to connect. Needed for native USB
|
|
}
|
|
|
|
#ifdef ACTIVATE_SOFTWARE_SERIAL
|
|
}else if (this->ss){
|
|
DEBUG_PRINTLN("Begin Software Serial");
|
|
|
|
this->serialDef.begin(*this->ss, this->bpsRate);
|
|
} else{
|
|
DEBUG_PRINTLN("Begin Software Serial Pin");
|
|
SoftwareSerial* mySerial = new SoftwareSerial((int)this->txE220pin, (int)this->rxE220pin); // "RX TX" // @suppress("Abstract class cannot be instantiated")
|
|
this->ss = mySerial;
|
|
|
|
// SoftwareSerial mySerial(this->txE220pin, this->rxE220pin);
|
|
DEBUG_PRINT("RX Pin: ");
|
|
DEBUG_PRINT((int)this->txE220pin);
|
|
DEBUG_PRINT("TX Pin: ");
|
|
DEBUG_PRINTLN((int)this->rxE220pin);
|
|
|
|
this->serialDef.begin(*this->ss, this->bpsRate);
|
|
#endif
|
|
}
|
|
|
|
this->serialDef.stream->setTimeout(100);
|
|
Status status = setMode(MODE_0_NORMAL);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
|
|
Utility method to wait until module is doen tranmitting
|
|
a timeout is provided to avoid an infinite loop
|
|
|
|
*/
|
|
|
|
Status LoRa_E220::waitCompleteResponse(unsigned long timeout, unsigned int waitNoAux) {
|
|
|
|
Status result = E220_SUCCESS;
|
|
|
|
unsigned long t = millis();
|
|
|
|
// make darn sure millis() is not about to reach max data type limit and start over
|
|
if (((unsigned long) (t + timeout)) == 0){
|
|
t = 0;
|
|
}
|
|
|
|
// if AUX pin was supplied and look for HIGH state
|
|
// note you can omit using AUX if no pins are available, but you will have to use delay() to let module finish
|
|
if (this->auxPin != -1) {
|
|
while (digitalRead(this->auxPin) == LOW) {
|
|
if ((millis() - t) > timeout){
|
|
result = ERR_E220_TIMEOUT;
|
|
DEBUG_PRINTLN("Timeout error!");
|
|
return result;
|
|
}
|
|
}
|
|
DEBUG_PRINTLN("AUX HIGH!");
|
|
}
|
|
else {
|
|
// if you can't use aux pin, use 4K7 pullup with Arduino
|
|
// you may need to adjust this value if transmissions fail
|
|
this->managedDelay(waitNoAux);
|
|
DEBUG_PRINTLN(F("Wait no AUX pin!"));
|
|
}
|
|
|
|
|
|
// per data sheet control after aux goes high is 2ms so delay for at least that long)
|
|
this->managedDelay(20);
|
|
DEBUG_PRINTLN(F("Complete!"));
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
|
|
delay() in a library is not a good idea as it can stop interrupts
|
|
just poll internal time until timeout is reached
|
|
|
|
*/
|
|
|
|
|
|
void LoRa_E220::managedDelay(unsigned long timeout) {
|
|
|
|
unsigned long t = millis();
|
|
|
|
// make darn sure millis() is not about to reach max data type limit and start over
|
|
if (((unsigned long) (t + timeout)) == 0){
|
|
t = 0;
|
|
}
|
|
|
|
while ((millis() - t) < timeout) { }
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Method to indicate availability
|
|
|
|
*/
|
|
|
|
//int LoRa_E220::available(unsigned long timeout) {
|
|
int LoRa_E220::available() {
|
|
// unsigned long t = millis();
|
|
//
|
|
// // make darn sure millis() is not about to reach max data type limit and start over
|
|
// if (((unsigned long) (t + timeout)) == 0){
|
|
// t = 0;
|
|
// }
|
|
//
|
|
// if (this->auxPin != -1) {
|
|
// if (digitalRead(this->auxPin) == HIGH){
|
|
// return 0;
|
|
// }else{
|
|
// while (digitalRead(this->auxPin) == LOW) {
|
|
// if ((millis() - t) > timeout){
|
|
// DEBUG_PRINTLN("Timeout error!");
|
|
// return 0;
|
|
// }
|
|
// }
|
|
// DEBUG_PRINTLN("AUX HIGH!");
|
|
// return 2;
|
|
// }
|
|
// }else{
|
|
return this->serialDef.stream->available();
|
|
// }
|
|
}
|
|
|
|
/*
|
|
|
|
Method to indicate availability
|
|
|
|
*/
|
|
|
|
void LoRa_E220::flush() {
|
|
this->serialDef.stream->flush();
|
|
}
|
|
|
|
|
|
void LoRa_E220::cleanUARTBuffer()
|
|
{
|
|
// bool IsNull = true;
|
|
|
|
while (this->available())
|
|
{
|
|
// IsNull = false;
|
|
|
|
this->serialDef.stream->read();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
Method to send a chunk of data provided data is in a struct--my personal favorite as you
|
|
need not parse or worry about sprintf() inability to handle floats
|
|
|
|
TTP: put your structure definition into a .h file and include in both the sender and reciever
|
|
sketches
|
|
|
|
NOTE: of your sender and receiver MCU's are different (Teensy and Arduino) caution on the data
|
|
types each handle ints floats differently
|
|
|
|
*/
|
|
|
|
Status LoRa_E220::sendStruct(void *structureManaged, uint16_t size_) {
|
|
if (size_ > MAX_SIZE_TX_PACKET + 2){
|
|
return ERR_E220_PACKET_TOO_BIG;
|
|
}
|
|
|
|
Status result = E220_SUCCESS;
|
|
|
|
uint8_t len = this->serialDef.stream->write((uint8_t *) structureManaged, size_);
|
|
if (len!=size_){
|
|
DEBUG_PRINT(F("Send... len:"))
|
|
DEBUG_PRINT(len);
|
|
DEBUG_PRINT(F(" size:"))
|
|
DEBUG_PRINT(size_);
|
|
if (len==0){
|
|
result = ERR_E220_NO_RESPONSE_FROM_DEVICE;
|
|
}else{
|
|
result = ERR_E220_DATA_SIZE_NOT_MATCH;
|
|
}
|
|
}
|
|
if (result != E220_SUCCESS) return result;
|
|
|
|
result = this->waitCompleteResponse(5000, 5000);
|
|
if (result != E220_SUCCESS) return result;
|
|
DEBUG_PRINT(F("Clear buffer..."))
|
|
this->cleanUARTBuffer();
|
|
|
|
DEBUG_PRINTLN(F("ok!"))
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
Method to get a chunk of data provided data is in a struct--my personal favorite as you
|
|
need not parse or worry about sprintf() inability to handle floats
|
|
|
|
TTP: put your structure definition into a .h file and include in both the sender and reciever
|
|
sketches
|
|
|
|
NOTE: of your sender and receiver MCU's are different (Teensy and Arduino) caution on the data
|
|
types each handle ints floats differently
|
|
|
|
*/
|
|
|
|
|
|
Status LoRa_E220::receiveStruct(void *structureManaged, uint16_t size_) {
|
|
Status result = E220_SUCCESS;
|
|
|
|
uint8_t len = this->serialDef.stream->readBytes((uint8_t *) structureManaged, size_);
|
|
|
|
DEBUG_PRINT("Available buffer: ");
|
|
DEBUG_PRINT(len);
|
|
DEBUG_PRINT(" structure size: ");
|
|
DEBUG_PRINTLN(size_);
|
|
|
|
if (len!=size_){
|
|
if (len==0){
|
|
result = ERR_E220_NO_RESPONSE_FROM_DEVICE;
|
|
}else{
|
|
result = ERR_E220_DATA_SIZE_NOT_MATCH;
|
|
}
|
|
}
|
|
if (result != E220_SUCCESS) return result;
|
|
|
|
result = this->waitCompleteResponse(1000);
|
|
if (result != E220_SUCCESS) return result;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
|
|
method to set the mode (program, normal, etc.)
|
|
|
|
*/
|
|
|
|
Status LoRa_E220::setMode(MODE_TYPE mode) {
|
|
|
|
// data sheet claims module needs some extra time after mode setting (2ms)
|
|
// most of my projects uses 10 ms, but 40ms is safer
|
|
|
|
this->managedDelay(40);
|
|
|
|
if (this->m0Pin == -1 && this->m1Pin == -1) {
|
|
DEBUG_PRINTLN(F("The M0 and M1 pins is not set, this mean that you are connect directly the pins as you need!"))
|
|
}else{
|
|
switch (mode)
|
|
{
|
|
case MODE_0_NORMAL:
|
|
// Mode 0 | normal operation
|
|
setMPins(this->m0Pin, LOW);
|
|
setMPins(this->m1Pin, LOW);
|
|
DEBUG_PRINTLN("MODE NORMAL!");
|
|
break;
|
|
case MODE_1_WOR_TRANSMITTER:
|
|
setMPins(this->m0Pin, HIGH);
|
|
setMPins(this->m1Pin, LOW);
|
|
DEBUG_PRINTLN("MODE WOR!");
|
|
break;
|
|
case MODE_2_WOR_RECEIVER:
|
|
// case MODE_2_PROGRAM:
|
|
setMPins(this->m0Pin, LOW);
|
|
setMPins(this->m1Pin, HIGH);
|
|
DEBUG_PRINTLN("MODE RECEIVING!");
|
|
break;
|
|
case MODE_3_CONFIGURATION:
|
|
// Mode 3 | Setting operation
|
|
setMPins(this->m0Pin, HIGH);
|
|
setMPins(this->m1Pin, HIGH);
|
|
DEBUG_PRINTLN("MODE SLEEP CONFIG!");
|
|
break;
|
|
|
|
default:
|
|
return ERR_E220_INVALID_PARAM;
|
|
}
|
|
}
|
|
// data sheet says 2ms later control is returned, let's give just a bit more time
|
|
// these modules can take time to activate pins
|
|
this->managedDelay(40);
|
|
|
|
// wait until aux pin goes back low
|
|
Status res = this->waitCompleteResponse(1000);
|
|
|
|
if (res == E220_SUCCESS){
|
|
this->mode = mode;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
MODE_TYPE LoRa_E220::getMode(){
|
|
return this->mode;
|
|
}
|
|
|
|
void LoRa_E220::writeProgramCommand(PROGRAM_COMMAND cmd, REGISTER_ADDRESS addr, PACKET_LENGHT pl){
|
|
uint8_t CMD[3] = {cmd, addr, pl};
|
|
uint8_t size = this->serialDef.stream->write(CMD, 3);
|
|
|
|
DEBUG_PRINTLN(size);
|
|
|
|
this->managedDelay(50); //need ti check
|
|
}
|
|
|
|
ResponseStructContainer LoRa_E220::getConfiguration(){
|
|
ResponseStructContainer rc;
|
|
|
|
rc.status.code = checkUARTConfiguration(MODE_3_PROGRAM);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
MODE_TYPE prevMode = this->mode;
|
|
|
|
rc.status.code = this->setMode(MODE_3_PROGRAM);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
this->writeProgramCommand(READ_CONFIGURATION, REG_ADDRESS_CFG, PL_CONFIGURATION);
|
|
|
|
rc.data = malloc(sizeof(Configuration));
|
|
rc.status.code = this->receiveStruct((uint8_t *)rc.data, sizeof(Configuration));
|
|
|
|
#ifdef LoRa_E220_DEBUG
|
|
this->printParameters((Configuration *)rc.data);
|
|
#endif
|
|
|
|
if (rc.status.code!=E220_SUCCESS) {
|
|
this->setMode(prevMode);
|
|
return rc;
|
|
}
|
|
|
|
rc.status.code = this->setMode(prevMode);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
if (WRONG_FORMAT == ((Configuration *)rc.data)->COMMAND){
|
|
rc.status.code = ERR_E220_WRONG_FORMAT;
|
|
}
|
|
if (RETURNED_COMMAND != ((Configuration *)rc.data)->COMMAND || REG_ADDRESS_CFG!= ((Configuration *)rc.data)->STARTING_ADDRESS || PL_CONFIGURATION!= ((Configuration *)rc.data)->LENGHT){
|
|
rc.status.code = ERR_E220_HEAD_NOT_RECOGNIZED;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
RESPONSE_STATUS LoRa_E220::checkUARTConfiguration(MODE_TYPE mode){
|
|
if (mode==MODE_3_PROGRAM && this->bpsRate!=UART_BPS_RATE_9600){
|
|
return ERR_E220_WRONG_UART_CONFIG;
|
|
}
|
|
return E220_SUCCESS;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType){
|
|
ResponseStatus rc;
|
|
|
|
rc.code = checkUARTConfiguration(MODE_3_PROGRAM);
|
|
if (rc.code!=E220_SUCCESS) return rc;
|
|
|
|
MODE_TYPE prevMode = this->mode;
|
|
|
|
rc.code = this->setMode(MODE_3_PROGRAM);
|
|
if (rc.code!=E220_SUCCESS) return rc;
|
|
|
|
// this->writeProgramCommand(saveType, REG_ADDRESS_CFG);
|
|
|
|
// configuration.HEAD = saveType;
|
|
configuration.COMMAND = saveType;
|
|
configuration.STARTING_ADDRESS = REG_ADDRESS_CFG;
|
|
configuration.LENGHT = PL_CONFIGURATION;
|
|
|
|
rc.code = this->sendStruct((uint8_t *)&configuration, sizeof(Configuration));
|
|
if (rc.code!=E220_SUCCESS) {
|
|
this->setMode(prevMode);
|
|
return rc;
|
|
}
|
|
|
|
rc.code = this->receiveStruct((uint8_t *)&configuration, sizeof(Configuration));
|
|
|
|
#ifdef LoRa_E220_DEBUG
|
|
this->printParameters((Configuration *)&configuration);
|
|
#endif
|
|
|
|
|
|
rc.code = this->setMode(prevMode);
|
|
if (rc.code!=E220_SUCCESS) return rc;
|
|
|
|
if (WRONG_FORMAT == ((Configuration *)&configuration)->COMMAND){
|
|
rc.code = ERR_E220_WRONG_FORMAT;
|
|
}
|
|
if (RETURNED_COMMAND != ((Configuration *)&configuration)->COMMAND || REG_ADDRESS_CFG!= ((Configuration *)&configuration)->STARTING_ADDRESS || PL_CONFIGURATION!= ((Configuration *)&configuration)->LENGHT){
|
|
rc.code = ERR_E220_HEAD_NOT_RECOGNIZED;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
ResponseStructContainer LoRa_E220::getModuleInformation(){
|
|
ResponseStructContainer rc;
|
|
|
|
rc.status.code = checkUARTConfiguration(MODE_3_PROGRAM);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
MODE_TYPE prevMode = this->mode;
|
|
|
|
rc.status.code = this->setMode(MODE_3_PROGRAM);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
this->writeProgramCommand(READ_CONFIGURATION, REG_ADDRESS_PID, PL_PID);
|
|
|
|
rc.data = malloc(sizeof(ModuleInformation));
|
|
|
|
// struct ModuleInformation *moduleInformation = (ModuleInformation *)malloc(sizeof(ModuleInformation));
|
|
rc.status.code = this->receiveStruct((uint8_t *)rc.data, sizeof(ModuleInformation));
|
|
if (rc.status.code!=E220_SUCCESS) {
|
|
this->setMode(prevMode);
|
|
return rc;
|
|
}
|
|
|
|
rc.status.code = this->setMode(prevMode);
|
|
if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
// this->printParameters(*configuration);
|
|
|
|
if (WRONG_FORMAT == ((ModuleInformation *)rc.data)->COMMAND){
|
|
rc.status.code = ERR_E220_WRONG_FORMAT;
|
|
}
|
|
if (RETURNED_COMMAND != ((ModuleInformation *)rc.data)->COMMAND || REG_ADDRESS_PID!= ((ModuleInformation *)rc.data)->STARTING_ADDRESS || PL_PID!= ((ModuleInformation *)rc.data)->LENGHT){
|
|
rc.status.code = ERR_E220_HEAD_NOT_RECOGNIZED;
|
|
}
|
|
|
|
DEBUG_PRINTLN("----------------------------------------");
|
|
DEBUG_PRINT(F("HEAD: ")); DEBUG_PRINT(((ModuleInformation *)rc.data)->COMMAND, BIN);DEBUG_PRINT(" ");DEBUG_PRINT(((ModuleInformation *)rc.data)->STARTING_ADDRESS, DEC);DEBUG_PRINT(" ");DEBUG_PRINTLN(((ModuleInformation *)rc.data)->LENGHT, HEX);
|
|
|
|
DEBUG_PRINT(F("Model no.: ")); DEBUG_PRINTLN(((ModuleInformation *)rc.data)->model, HEX);
|
|
DEBUG_PRINT(F("Version : ")); DEBUG_PRINTLN(((ModuleInformation *)rc.data)->version, HEX);
|
|
DEBUG_PRINT(F("Features : ")); DEBUG_PRINTLN(((ModuleInformation *)rc.data)->features, HEX);
|
|
DEBUG_PRINT(F("Status : ")); DEBUG_PRINTLN(rc.status.getResponseDescription());
|
|
DEBUG_PRINTLN("----------------------------------------");
|
|
|
|
// if (rc.status.code!=E220_SUCCESS) return rc;
|
|
|
|
// rc.data = moduleInformation; // malloc(sizeof (moduleInformation));
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
ResponseStatus LoRa_E220::resetModule(){
|
|
// ResponseStatus status;
|
|
//
|
|
// status.code = checkUARTConfiguration(MODE_2_PROGRAM);
|
|
// if (status.code!=E220_SUCCESS) return status;
|
|
//
|
|
// MODE_TYPE prevMode = this->mode;
|
|
//
|
|
// status.code = this->setMode(MODE_2_PROGRAM);
|
|
// if (status.code!=E220_SUCCESS) return status;
|
|
//
|
|
// this->writeProgramCommand(WRITE_RESET_MODULE);
|
|
//
|
|
// status.code = this->waitCompleteResponse(1000);
|
|
// if (status.code!=E220_SUCCESS) {
|
|
// this->setMode(prevMode);
|
|
// return status;
|
|
// }
|
|
//
|
|
//
|
|
// status.code = this->setMode(prevMode);
|
|
// if (status.code!=E220_SUCCESS) return status;
|
|
//
|
|
// return status;
|
|
DEBUG_PRINT(F("No information to reset module!"));
|
|
ResponseStatus status;
|
|
status.code = ERR_E220_NOT_IMPLEMENT;
|
|
return status;
|
|
}
|
|
|
|
ResponseContainer LoRa_E220::receiveMessage(){
|
|
return LoRa_E220::receiveMessageComplete(false);
|
|
}
|
|
ResponseContainer LoRa_E220::receiveMessageRSSI(){
|
|
return LoRa_E220::receiveMessageComplete(true);
|
|
}
|
|
|
|
ResponseContainer LoRa_E220::receiveMessageComplete(bool rssiEnabled){
|
|
ResponseContainer rc;
|
|
rc.status.code = E220_SUCCESS;
|
|
String tmpData = this->serialDef.stream->readString();
|
|
|
|
DEBUG_PRINTLN(tmpData);
|
|
|
|
if (rssiEnabled){
|
|
rc.rssi = tmpData.charAt(tmpData.length()-1);
|
|
rc.data = tmpData.substring(0, tmpData.length()-1);
|
|
}else{
|
|
rc.data = tmpData;
|
|
}
|
|
this->cleanUARTBuffer();
|
|
if (rc.status.code!=E220_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
// rc.data = message; // malloc(sizeof (moduleInformation));
|
|
|
|
return rc;
|
|
}
|
|
|
|
ResponseContainer LoRa_E220::receiveMessageUntil(char delimiter){
|
|
ResponseContainer rc;
|
|
rc.status.code = E220_SUCCESS;
|
|
rc.data = this->serialDef.stream->readStringUntil(delimiter);
|
|
// this->cleanUARTBuffer();
|
|
if (rc.status.code!=E220_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
// rc.data = message; // malloc(sizeof (moduleInformation));
|
|
|
|
return rc;
|
|
}
|
|
ResponseContainer LoRa_E220::receiveInitialMessage(uint8_t size){
|
|
ResponseContainer rc;
|
|
rc.status.code = E220_SUCCESS;
|
|
char buff[size];
|
|
uint8_t len = this->serialDef.stream->readBytes(buff, size);
|
|
if (len!=size) {
|
|
if (len==0){
|
|
rc.status.code = ERR_E220_NO_RESPONSE_FROM_DEVICE;
|
|
}else{
|
|
rc.status.code = ERR_E220_DATA_SIZE_NOT_MATCH;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc.data = buff; // malloc(sizeof (moduleInformation));
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
ResponseStructContainer LoRa_E220::receiveMessage(const uint8_t size){
|
|
return LoRa_E220::receiveMessageComplete(size, false);
|
|
}
|
|
ResponseStructContainer LoRa_E220::receiveMessageRSSI(const uint8_t size){
|
|
return LoRa_E220::receiveMessageComplete(size, true);
|
|
}
|
|
|
|
ResponseStructContainer LoRa_E220::receiveMessageComplete(const uint8_t size, bool rssiEnabled){
|
|
ResponseStructContainer rc;
|
|
|
|
rc.data = malloc(size);
|
|
rc.status.code = this->receiveStruct((uint8_t *)rc.data, size);
|
|
if (rc.status.code!=E220_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
if (rssiEnabled){
|
|
|
|
char rssi[1];
|
|
this->serialDef.stream->readBytes(rssi, 1);
|
|
rc.rssi = rssi[0];
|
|
}
|
|
this->cleanUARTBuffer();
|
|
|
|
return rc;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::sendMessage(const void *message, const uint8_t size){
|
|
ResponseStatus status;
|
|
status.code = this->sendStruct((uint8_t *)message, size);
|
|
if (status.code!=E220_SUCCESS) return status;
|
|
|
|
return status;
|
|
}
|
|
ResponseStatus LoRa_E220::sendMessage(const String message){
|
|
DEBUG_PRINT(F("Send message: "));
|
|
DEBUG_PRINT(message);
|
|
byte size = message.length(); // sizeof(message.c_str())+1;
|
|
DEBUG_PRINT(F(" size: "));
|
|
DEBUG_PRINTLN(size);
|
|
char messageFixed[size];
|
|
memcpy(messageFixed,message.c_str(),size);
|
|
DEBUG_PRINTLN(F(" memcpy "));
|
|
|
|
ResponseStatus status;
|
|
status.code = this->sendStruct((uint8_t *)&messageFixed, size);
|
|
if (status.code!=E220_SUCCESS) return status;
|
|
|
|
// free(messageFixed);
|
|
return status;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::sendFixedMessage(byte ADDH, byte ADDL, byte CHAN, const String message){
|
|
// DEBUG_PRINT("String/size: ");
|
|
// DEBUG_PRINT(message);
|
|
// DEBUG_PRINT("/");
|
|
byte size = message.length(); // sizeof(message.c_str())+1;
|
|
// DEBUG_PRINTLN(size);
|
|
//
|
|
// #pragma pack(push, 1)
|
|
// struct FixedStransmissionString {
|
|
// byte ADDH = 0;
|
|
// byte ADDL = 0;
|
|
// byte CHAN = 0;
|
|
// char message[];
|
|
// } fixedStransmission;
|
|
// #pragma pack(pop)
|
|
//
|
|
// fixedStransmission.ADDH = ADDH;
|
|
// fixedStransmission.ADDL = ADDL;
|
|
// fixedStransmission.CHAN = CHAN;
|
|
// char* msg = (char*)message.c_str();
|
|
// memcpy(fixedStransmission.message, (char*)msg, size);
|
|
//// fixedStransmission.message = message;
|
|
//
|
|
// DEBUG_PRINT("Message: ");
|
|
// DEBUG_PRINTLN(fixedStransmission.message);
|
|
//
|
|
// ResponseStatus status;
|
|
// status.code = this->sendStruct((uint8_t *)&fixedStransmission, sizeof(fixedStransmission));
|
|
// if (status.code!=E220_SUCCESS) return status;
|
|
//
|
|
// return status;
|
|
char messageFixed[size];
|
|
memcpy(messageFixed,message.c_str(),size);
|
|
return this->sendFixedMessage(ADDH, ADDL, CHAN, (uint8_t *)messageFixed, size);
|
|
}
|
|
ResponseStatus LoRa_E220::sendBroadcastFixedMessage(byte CHAN, const String message){
|
|
return this->sendFixedMessage(BROADCAST_ADDRESS, BROADCAST_ADDRESS, CHAN, message);
|
|
}
|
|
|
|
typedef struct fixedStransmission
|
|
{
|
|
byte ADDH = 0;
|
|
byte ADDL = 0;
|
|
byte CHAN = 0;
|
|
unsigned char message[];
|
|
}FixedStransmission;
|
|
|
|
FixedStransmission *init_stack(int m){
|
|
FixedStransmission *st = (FixedStransmission *)malloc(sizeof(FixedStransmission)+m*sizeof(int));
|
|
return st;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::sendFixedMessage( byte ADDH,byte ADDL, byte CHAN, const void *message, const uint8_t size){
|
|
// #pragma pack(push, 1)
|
|
// struct FixedStransmission {
|
|
// byte ADDH = 0;
|
|
// byte ADDL = 0;
|
|
// byte CHAN = 0;
|
|
// unsigned char message[];
|
|
// } fixedStransmission;
|
|
// #pragma pack(pop)
|
|
|
|
|
|
DEBUG_PRINT(ADDH);
|
|
|
|
|
|
FixedStransmission *fixedStransmission = init_stack(size);
|
|
|
|
// STACK *resize_stack(STACK *st, int m){
|
|
// if (m<=st->max){
|
|
// return st; /* Take sure do not kill old values */
|
|
// }
|
|
// STACK *st = (STACK *)realloc(sizeof(STACK)+m*sizeof(int));
|
|
// st->max = m;
|
|
// return st;
|
|
// }
|
|
|
|
fixedStransmission->ADDH = ADDH;
|
|
fixedStransmission->ADDL = ADDL;
|
|
fixedStransmission->CHAN = CHAN;
|
|
// fixedStransmission.message = &message;
|
|
|
|
memcpy(fixedStransmission->message,(unsigned char*)message,size);
|
|
|
|
ResponseStatus status;
|
|
status.code = this->sendStruct((uint8_t *)fixedStransmission, size+3);
|
|
|
|
free(fixedStransmission);
|
|
|
|
if (status.code!=E220_SUCCESS) return status;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
ConfigurationMessage *init_stack_conf(int m){
|
|
ConfigurationMessage *st = (ConfigurationMessage *)malloc(sizeof(ConfigurationMessage)+m*sizeof(int));
|
|
return st;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::sendConfigurationMessage( byte ADDH,byte ADDL, byte CHAN, Configuration *configuration, PROGRAM_COMMAND programCommand){
|
|
ResponseStatus rc;
|
|
|
|
// rc.code = this->setMode(MODE_2_PROGRAM);
|
|
// if (rc.code!=E220_SUCCESS) return rc;
|
|
|
|
configuration->COMMAND = programCommand;
|
|
configuration->STARTING_ADDRESS = REG_ADDRESS_CFG;
|
|
configuration->LENGHT = PL_CONFIGURATION;
|
|
|
|
ConfigurationMessage *fixedStransmission = init_stack_conf(sizeof(Configuration));
|
|
|
|
// fixedStransmission.message = &message;
|
|
|
|
|
|
memcpy(fixedStransmission->message,(unsigned char*)configuration,sizeof(Configuration));
|
|
|
|
fixedStransmission->specialCommand1 = SPECIAL_WIFI_CONF_COMMAND;
|
|
fixedStransmission->specialCommand2 = SPECIAL_WIFI_CONF_COMMAND;
|
|
|
|
DEBUG_PRINTLN(sizeof(Configuration)+2);
|
|
|
|
rc = sendFixedMessage(ADDH, ADDL, CHAN, fixedStransmission, sizeof(Configuration)+2);
|
|
//
|
|
// ResponseStatus status;
|
|
// status.code = this->sendStruct((uint8_t *)fixedStransmission, sizeof(Configuration)+5);
|
|
// if (status.code!=E220_SUCCESS) return status;
|
|
|
|
// free(fixedStransmission);
|
|
|
|
return rc;
|
|
}
|
|
|
|
ResponseStatus LoRa_E220::sendBroadcastFixedMessage(byte CHAN, const void *message, const uint8_t size){
|
|
return this->sendFixedMessage(0xFF, 0xFF, CHAN, message, size);
|
|
}
|
|
|
|
#define KeeLoq_NLF 0x3A5C742E
|
|
|
|
unsigned long LoRa_E220::encrypt(unsigned long data)
|
|
{
|
|
unsigned long x = data;
|
|
unsigned long r;
|
|
int keyBitNo, index;
|
|
unsigned long keyBitVal,bitVal;
|
|
|
|
for (r = 0; r < 528; r++)
|
|
{
|
|
keyBitNo = r & 63;
|
|
if(keyBitNo < 32)
|
|
keyBitVal = bitRead(this->halfKeyloqKey,keyBitNo); // key low
|
|
else
|
|
keyBitVal = bitRead(this->halfKeyloqKey, keyBitNo - 32);// key hight
|
|
index = 1 * bitRead(x,1) + 2 * bitRead(x,9) + 4 * bitRead(x,20) + 8 * bitRead(x,26) + 16 * bitRead(x,31);
|
|
bitVal = bitRead(x,0) ^ bitRead(x, 16) ^ bitRead(KeeLoq_NLF,index) ^ keyBitVal;
|
|
x = (x>>1) ^ bitVal<<31;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
unsigned long LoRa_E220::decrypt(unsigned long data)
|
|
{
|
|
unsigned long x = data;
|
|
unsigned long r;
|
|
int keyBitNo, index;
|
|
unsigned long keyBitVal,bitVal;
|
|
|
|
for (r = 0; r < 528; r++)
|
|
{
|
|
keyBitNo = (15-r) & 63;
|
|
if(keyBitNo < 32)
|
|
keyBitVal = bitRead(this->halfKeyloqKey,keyBitNo); // key low
|
|
else
|
|
keyBitVal = bitRead(this->halfKeyloqKey, keyBitNo - 32); // key hight
|
|
index = 1 * bitRead(x,0) + 2 * bitRead(x,8) + 4 * bitRead(x,19) + 8 * bitRead(x,25) + 16 * bitRead(x,30);
|
|
bitVal = bitRead(x,31) ^ bitRead(x, 15) ^ bitRead(KeeLoq_NLF,index) ^ keyBitVal;
|
|
x = (x<<1) ^ bitVal;
|
|
}
|
|
return x;
|
|
}
|
|
#ifdef LoRa_E220_DEBUG
|
|
void LoRa_E220::printParameters(struct Configuration *configuration) {
|
|
DEBUG_PRINTLN("----------------------------------------");
|
|
|
|
DEBUG_PRINT(F("HEAD : ")); DEBUG_PRINT(configuration->COMMAND, HEX);DEBUG_PRINT(" ");DEBUG_PRINT(configuration->STARTING_ADDRESS, HEX);DEBUG_PRINT(" ");DEBUG_PRINTLN(configuration->LENGHT, HEX);
|
|
DEBUG_PRINTLN(F(" "));
|
|
DEBUG_PRINT(F("AddH : ")); DEBUG_PRINTLN(configuration->ADDH, HEX);
|
|
DEBUG_PRINT(F("AddL : ")); DEBUG_PRINTLN(configuration->ADDL, HEX);
|
|
DEBUG_PRINTLN(F(" "));
|
|
DEBUG_PRINT(F("Chan : ")); DEBUG_PRINT(configuration->CHAN, DEC); DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->getChannelDescription());
|
|
DEBUG_PRINTLN(F(" "));
|
|
DEBUG_PRINT(F("SpeedParityBit : ")); DEBUG_PRINT(configuration->SPED.uartParity, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->SPED.getUARTParityDescription());
|
|
DEBUG_PRINT(F("SpeedUARTDatte : ")); DEBUG_PRINT(configuration->SPED.uartBaudRate, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->SPED.getUARTBaudRateDescription());
|
|
DEBUG_PRINT(F("SpeedAirDataRate : ")); DEBUG_PRINT(configuration->SPED.airDataRate, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->SPED.getAirDataRateDescription());
|
|
DEBUG_PRINTLN(F(" "));
|
|
DEBUG_PRINT(F("OptionSubPacketSett: ")); DEBUG_PRINT(configuration->OPTION.subPacketSetting, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->OPTION.getSubPacketSetting());
|
|
DEBUG_PRINT(F("OptionTranPower : ")); DEBUG_PRINT(configuration->OPTION.transmissionPower, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->OPTION.getTransmissionPowerDescription());
|
|
DEBUG_PRINT(F("OptionRSSIAmbientNo: ")); DEBUG_PRINT(configuration->OPTION.RSSIAmbientNoise, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->OPTION.getRSSIAmbientNoiseEnable());
|
|
DEBUG_PRINTLN(F(" "));
|
|
DEBUG_PRINT(F("TransModeWORPeriod : ")); DEBUG_PRINT(configuration->TRANSMISSION_MODE.WORPeriod, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->TRANSMISSION_MODE.getWORPeriodByParamsDescription());
|
|
DEBUG_PRINT(F("TransModeEnableLBT : ")); DEBUG_PRINT(configuration->TRANSMISSION_MODE.enableLBT, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->TRANSMISSION_MODE.getLBTEnableByteDescription());
|
|
DEBUG_PRINT(F("TransModeEnableRSSI: ")); DEBUG_PRINT(configuration->TRANSMISSION_MODE.enableRSSI, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->TRANSMISSION_MODE.getRSSIEnableByteDescription());
|
|
DEBUG_PRINT(F("TransModeFixedTrans: ")); DEBUG_PRINT(configuration->TRANSMISSION_MODE.fixedTransmission, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration->TRANSMISSION_MODE.getFixedTransmissionDescription());
|
|
|
|
|
|
DEBUG_PRINTLN("----------------------------------------");
|
|
}
|
|
#endif
|