diff --git a/esphome/components/ebyte_lora_e220/__init__.py b/esphome/components/ebyte_lora_e220/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ebyte_lora_e220/ebyte_lora_e220.h b/esphome/components/ebyte_lora_e220/ebyte_lora_e220.h new file mode 100644 index 0000000000..7ca6e9bcf5 --- /dev/null +++ b/esphome/components/ebyte_lora_e220/ebyte_lora_e220.h @@ -0,0 +1,41 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/components/text_sensor/text_sensor.h" +#include +#include "esphome/core/helpers.h" +#include "lora_e220.h" + +namespace esphome { +namespace ebyte_lora_e220 { + +// there are 3 UART ports, we are going to be using 0, which is D6 and D7 +HardwareSerial LoraSerial(0); +LoRa_E220 e220ttl(&LoraSerial, D2, D0, D1); // SERIAL AUX M0 M1 + +class LoRaSensors : public text_sensor::TextSensor, public PollingComponent { + public: + LoRaSensors() : PollingComponent(4000) {} + + void setup() override { e220ttl.begin(); } + + void update() override { + // This will be called by App.loop() + + if (e220ttl.available() > 1) { + // read the String message + ResponseContainer rc = e220ttl.receiveMessageRSSI(); + // Is something goes wrong print error + if (rc.status.code != 1) { + this->publish_state(rc.status.getResponseDescription()); + } else { + // Print the data received + this->publish_state(rc.status.getResponseDescription()); + this->publish_state(rc.data); + this->publish_state(rc.rssi + ""); + } + } + } +}; + +} // namespace ebyte_lora_e220 +} // namespace esphome diff --git a/esphome/components/ebyte_lora_e220/lora_e220.cpp b/esphome/components/ebyte_lora_e220/lora_e220.cpp new file mode 100644 index 0000000000..20cb722df1 --- /dev/null +++ b/esphome/components/ebyte_lora_e220/lora_e220.cpp @@ -0,0 +1,1022 @@ +#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!"); + digitalWrite(this->m0Pin, HIGH); + + } + if (this->m1Pin != -1) { + pinMode(this->m1Pin, OUTPUT); + DEBUG_PRINTLN("Init M1 pin!"); + digitalWrite(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==E220_SUCCESS; +} + +/* + +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 + digitalWrite(this->m0Pin, LOW); + digitalWrite(this->m1Pin, LOW); + DEBUG_PRINTLN("MODE NORMAL!"); + break; + case MODE_1_WOR_TRANSMITTER: + digitalWrite(this->m0Pin, HIGH); + digitalWrite(this->m1Pin, LOW); + DEBUG_PRINTLN("MODE WOR!"); + break; + case MODE_2_WOR_RECEIVER: +// case MODE_2_PROGRAM: + digitalWrite(this->m0Pin, LOW); + digitalWrite(this->m1Pin, HIGH); + DEBUG_PRINTLN("MODE RECEIVING!"); + break; + case MODE_3_CONFIGURATION: + // Mode 3 | Setting operation + digitalWrite(this->m0Pin, HIGH); + digitalWrite(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; +} + +bool 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 + + return size!=2; +} + +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; + std::string tmpData = this->serialDef.stream->readstd::string(); + + DEBUG_PRINTLN(tmpData); + + if (rssiEnabled){ + rc.rssi = tmpData.charAt(tmpData.length()-1); + rc.data = tmpData.substd::string(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->readstd::stringUntil(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 std::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 std::string message){ +// DEBUG_PRINT("std::string/size: "); +// DEBUG_PRINT(message); +// DEBUG_PRINT("/"); + byte size = message.length(); // sizeof(message.c_str())+1; +// DEBUG_PRINTLN(size); +// +// #pragma pack(push, 1) +// struct FixedStransmissionstd::string { +// 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 std::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 diff --git a/esphome/components/ebyte_lora_e220/lora_e220.h b/esphome/components/ebyte_lora_e220/lora_e220.h new file mode 100644 index 0000000000..b6683dd8d3 --- /dev/null +++ b/esphome/components/ebyte_lora_e220/lora_e220.h @@ -0,0 +1,361 @@ +#ifndef LoRa_E220_h +#define LoRa_E220_h + +#if !USE_ESP32 && !defined(__STM32F1__) && !defined(__STM32F4__) + #define ACTIVATE_SOFTWARE_SERIAL +#endif +#ifdef USE_ESP32 + #define HARDWARE_SERIAL_SELECTABLE_PIN +#endif + +#ifdef ACTIVATE_SOFTWARE_SERIAL + #include +#endif + +#include "state_naming.h" + +#include "Arduino.h" + + +#define MAX_SIZE_TX_PACKET 200 + +// Uncomment to enable printing out nice debug messages. +//#define LoRa_E220_DEBUG + +// Define where debug output will be printed. +#define DEBUG_PRINTER Serial + +// Setup debug printing macros. +#ifdef LoRa_E220_DEBUG + #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } + #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } +#else + #define DEBUG_PRINT(...) {} + #define DEBUG_PRINTLN(...) {} +#endif + +enum MODE_TYPE { + MODE_0_NORMAL = 0, + MODE_0_TRANSMISSION = 0, + MODE_1_WOR_TRANSMITTER = 1, + MODE_1_WOR = 1, + MODE_2_WOR_RECEIVER = 2, + MODE_2_POWER_SAVING = 2, + MODE_3_CONFIGURATION = 3, + MODE_3_PROGRAM = 3, + MODE_3_SLEEP = 3, + MODE_INIT = 0xFF +}; + +enum PROGRAM_COMMAND { + WRITE_CFG_PWR_DWN_SAVE = 0xC0, + READ_CONFIGURATION = 0xC1, + WRITE_CFG_PWR_DWN_LOSE = 0xC2, + WRONG_FORMAT = 0xFF, + RETURNED_COMMAND = 0xC1, + SPECIAL_WIFI_CONF_COMMAND = 0xCF +}; + +enum REGISTER_ADDRESS { + REG_ADDRESS_CFG = 0x00, + REG_ADDRESS_SPED = 0x02, + REG_ADDRESS_TRANS_MODE = 0x03, + REG_ADDRESS_CHANNEL = 0x04, + REG_ADDRESS_OPTION = 0x05, + REG_ADDRESS_CRYPT = 0x06, + REG_ADDRESS_PID = 0x08 +}; + +enum PACKET_LENGHT { + PL_CONFIGURATION = 0x08, + + PL_SPED = 0x01, + PL_OPTION = 0x01, + PL_TRANSMISSION_MODE= 0x01, + PL_CHANNEL = 0x01, + PL_CRYPT = 0x02, + PL_PID = 0x03 +}; + +#pragma pack(push, 1) +struct Speed { + uint8_t airDataRate :3; //bit 0-2 + std::string getAirDataRateDescription() { + return getAirDataRateDescriptionByParams(this->airDataRate); + } + + uint8_t uartParity :2; //bit 3-4 + std::string getUARTParityDescription() { + return getUARTParityDescriptionByParams(this->uartParity); + } + + uint8_t uartBaudRate :3; //bit 5-7 + std::string getUARTBaudRateDescription() { + return getUARTBaudRateDescriptionByParams(this->uartBaudRate); + } + +}; + +struct TransmissionMode { + byte WORPeriod :3; //bit 2,1,0 + std::string getWORPeriodByParamsDescription() { + return getWORPeriodByParams(this->WORPeriod); + } + byte reserved2 :1; //bit 3 + byte enableLBT :1; //bit 4 + std::string getLBTEnableByteDescription() { + return getLBTEnableByteByParams(this->enableLBT); + } + byte reserved :1; //bit 5 + + byte fixedTransmission :1; //bit 6 + std::string getFixedTransmissionDescription() { + return getFixedTransmissionDescriptionByParams(this->fixedTransmission); + } + + byte enableRSSI :1; //bit 7 + std::string getRSSIEnableByteDescription() { + return getRSSIEnableByteByParams(this->enableRSSI); + } +}; + +struct Option { + uint8_t transmissionPower :2; //bit 0-1 + std::string getTransmissionPowerDescription() { + return getTransmissionPowerDescriptionByParams(this->transmissionPower); + } + uint8_t reserved :3; //bit 2-4 + + uint8_t RSSIAmbientNoise :1; //bit 5 + std::string getRSSIAmbientNoiseEnable() { + return getRSSIAmbientNoiseEnableByParams(this->RSSIAmbientNoise); + } + + uint8_t subPacketSetting :2; //bit 6-7 + std::string getSubPacketSetting() { + return getSubPacketSettingByParams(this->subPacketSetting); + } + +}; + +struct Crypt { + byte CRYPT_H = 0; + byte CRYPT_L = 0; +}; + +struct Configuration { + byte COMMAND = 0; + byte STARTING_ADDRESS = 0; + byte LENGHT = 0; + + byte ADDH = 0; + byte ADDL = 0; + + struct Speed SPED; + struct Option OPTION; + + byte CHAN = 0; + std::string getChannelDescription() { + return std::string(this->CHAN + OPERATING_FREQUENCY) + F("MHz"); + } + + struct TransmissionMode TRANSMISSION_MODE; + + struct Crypt CRYPT; +}; + +struct ModuleInformation { + byte COMMAND = 0; + byte STARTING_ADDRESS = 0; + byte LENGHT = 0; + + byte model = 0; + byte version = 0; + byte features = 0; +}; + +struct ResponseStatus { + std::std::string code; + std::std::string getResponseDescription() { + return getResponseDescriptionByParams(this->code); + } +}; + +struct ResponseStructContainer { + void *data; + byte rssi; + ResponseStatus status; + void close() { + free(this->data); + } +}; +struct ResponseContainer { + std::string data; + byte rssi; + ResponseStatus status; +}; + +struct ConfigurationMessage +{ + byte specialCommand1 = 0xCF; + byte specialCommand2 = 0xCF; + + unsigned char message[]; +}; + +//struct FixedStransmission { +// byte ADDL = 0; +// byte ADDH = 0; +// byte CHAN = 0; +// void *message; +//}; +#pragma pack(pop) + +class LoRa_E220 { + public: +#ifdef ACTIVATE_SOFTWARE_SERIAL + LoRa_E220(byte txE220pin, byte rxE220pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(byte txE220pin, byte rxE220pin, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(byte txE220pin, byte rxE220pin, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); +#endif + + LoRa_E220(HardwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + +#ifdef HARDWARE_SERIAL_SELECTABLE_PIN + LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, UART_BPS_RATE bpsRate, uint32_t serialConfig = SERIAL_8N1); + LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate, uint32_t serialConfig = SERIAL_8N1); + LoRa_E220(byte txE220pin, byte rxE220pin, HardwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate, uint32_t serialConfig = SERIAL_8N1); +#endif + +#ifdef ACTIVATE_SOFTWARE_SERIAL + LoRa_E220(SoftwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(SoftwareSerial* serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); + LoRa_E220(SoftwareSerial* serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); +#endif + +// LoRa_E220(byte txE220pin, byte rxE220pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, MODE_TYPE mode = MODE_0_NORMAL); +// LoRa_E220(HardwareSerial* serial = &Serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, MODE_TYPE mode = MODE_0_NORMAL); +// LoRa_E220(SoftwareSerial* serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600, MODE_TYPE mode = MODE_0_NORMAL); + + bool begin(); + Status setMode(MODE_TYPE mode); + MODE_TYPE getMode(); + + ResponseStructContainer getConfiguration(); + ResponseStatus setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE); + + ResponseStructContainer getModuleInformation(); + ResponseStatus resetModule(); + + ResponseStatus sendMessage(const void *message, const uint8_t size); + + ResponseContainer receiveMessageUntil(char delimiter = '\0'); + ResponseStructContainer receiveMessage(const uint8_t size); + ResponseStructContainer receiveMessageRSSI(const uint8_t size); + + ResponseStructContainer receiveMessageComplete(const uint8_t size, bool enableRSSI); + ResponseContainer receiveMessageComplete(bool enableRSSI); + + ResponseStatus sendMessage(const std::string message); + ResponseContainer receiveMessage(); + ResponseContainer receiveMessageRSSI(); + + ResponseStatus sendFixedMessage(byte ADDH, byte ADDL, byte CHAN, const std::string message); + + ResponseStatus sendFixedMessage(byte ADDH,byte ADDL, byte CHAN, const void *message, const uint8_t size); + ResponseStatus sendBroadcastFixedMessage(byte CHAN, const void *message, const uint8_t size); + ResponseStatus sendBroadcastFixedMessage(byte CHAN, const std::string message); + + ResponseContainer receiveInitialMessage(const uint8_t size); + + ResponseStatus sendConfigurationMessage( byte ADDH,byte ADDL, byte CHAN, Configuration *configuration, PROGRAM_COMMAND programCommand = WRITE_CFG_PWR_DWN_SAVE); + + int available(); + private: + HardwareSerial* hs; + +#ifdef ACTIVATE_SOFTWARE_SERIAL + SoftwareSerial* ss; +#endif + + bool isSoftwareSerial = true; + + int8_t txE220pin = -1; + int8_t rxE220pin = -1; + int8_t auxPin = -1; + +#ifdef HARDWARE_SERIAL_SELECTABLE_PIN + uint32_t serialConfig = SERIAL_8N1; +#endif + + int8_t m0Pin = -1; + int8_t m1Pin = -1; + + unsigned long halfKeyloqKey = 0x06660708; + unsigned long encrypt(unsigned long data); + unsigned long decrypt(unsigned long data); + + UART_BPS_RATE bpsRate = UART_BPS_RATE_9600; + + struct NeedsStream { + template + void begin(T &t, uint32_t baud) { + DEBUG_PRINTLN("Begin "); + t.setTimeout(500); + t.begin(baud); + stream = &t; + } + +#ifdef HARDWARE_SERIAL_SELECTABLE_PIN +// template< typename T > +// void begin( T &t, uint32_t baud, SerialConfig config ){ +// DEBUG_PRINTLN("Begin "); +// t.setTimeout(500); +// t.begin(baud, config); +// stream = &t; +// } +// + template< typename T > + void begin( T &t, uint32_t baud, uint32_t config ) { + DEBUG_PRINTLN("Begin "); + t.setTimeout(500); + t.begin(baud, config); + stream = &t; + } + + template< typename T > + void begin( T &t, uint32_t baud, uint32_t config, int8_t txE220pin, int8_t rxE220pin ) { + DEBUG_PRINTLN("Begin "); + t.setTimeout(500); + t.begin(baud, config, txE220pin, rxE220pin); + stream = &t; + } +#endif + + void listen() {} + + Stream *stream; + }; + NeedsStream serialDef; + + MODE_TYPE mode = MODE_0_NORMAL; + + void managedDelay(unsigned long timeout); + Status waitCompleteResponse(unsigned long timeout = 1000, unsigned int waitNoAux = 100); + void flush(); + void cleanUARTBuffer(); + + Status sendStruct(void *structureManaged, uint16_t size_); + Status receiveStruct(void *structureManaged, uint16_t size_); + bool writeProgramCommand(PROGRAM_COMMAND cmd, REGISTER_ADDRESS addr, PACKET_LENGHT pl); + + RESPONSE_STATUS checkUARTConfiguration(MODE_TYPE mode); + +#ifdef LoRa_E220_DEBUG + void printParameters(struct Configuration *configuration); +#endif +}; + +#endif diff --git a/esphome/components/ebyte_lora_e220/state_naming.h b/esphome/components/ebyte_lora_e220/state_naming.h new file mode 100644 index 0000000000..ad8eb2120b --- /dev/null +++ b/esphome/components/ebyte_lora_e220/state_naming.h @@ -0,0 +1,463 @@ +#include "Arduino.h" + +#ifdef FREQUENCY_433 + #define OPERATING_FREQUENCY 410 +#elif defined(FREQUENCY_400) + #define OPERATING_FREQUENCY 410 +#elif defined(FREQUENCY_230) + #define OPERATING_FREQUENCY 220 +#elif defined(FREQUENCY_868) + #define OPERATING_FREQUENCY 850 +#elif defined(FREQUENCY_900) + #define OPERATING_FREQUENCY 850 +#elif defined(FREQUENCY_915) + #define OPERATING_FREQUENCY 900 +#else + #define OPERATING_FREQUENCY 410 +#endif + +#define BROADCAST_ADDRESS 255 + +typedef enum RESPONSE_STATUS { +#ifndef ARDUINO_ARCH_STM32 + SUCCESS = 1, +#endif + E220_SUCCESS = 1, + ERR_E220_UNKNOWN, /* something shouldn't happened */ + ERR_E220_NOT_SUPPORT, + ERR_E220_NOT_IMPLEMENT, + ERR_E220_NOT_INITIAL, + ERR_E220_INVALID_PARAM, + ERR_E220_DATA_SIZE_NOT_MATCH, + ERR_E220_BUF_TOO_SMALL, + ERR_E220_TIMEOUT, + ERR_E220_HARDWARE, + ERR_E220_HEAD_NOT_RECOGNIZED, + ERR_E220_NO_RESPONSE_FROM_DEVICE, + ERR_E220_WRONG_UART_CONFIG, + ERR_E220_WRONG_FORMAT, + ERR_E220_PACKET_TOO_BIG +} Status; + +static String getResponseDescriptionByParams(byte status){ + switch (status) + { + case E220_SUCCESS: + return F("Success"); + break; + case ERR_E220_UNKNOWN: + return F("Unknown"); + break; + case ERR_E220_NOT_SUPPORT: + return F("Not support!"); + break; + case ERR_E220_NOT_IMPLEMENT: + return F("Not implement"); + break; + case ERR_E220_NOT_INITIAL: + return F("Not initial!"); + break; + case ERR_E220_INVALID_PARAM: + return F("Invalid param!"); + break; + case ERR_E220_DATA_SIZE_NOT_MATCH: + return F("Data size not match!"); + break; + case ERR_E220_BUF_TOO_SMALL: + return F("Buff too small!"); + break; + case ERR_E220_TIMEOUT: + return F("Timeout!!"); + break; + case ERR_E220_HARDWARE: + return F("Hardware error!"); + break; + case ERR_E220_HEAD_NOT_RECOGNIZED: + return F("Save mode returned not recognized!"); + break; + case ERR_E220_NO_RESPONSE_FROM_DEVICE: + return F("No response from device! (Check wiring)"); + break; + case ERR_E220_WRONG_UART_CONFIG: + return F("Wrong UART configuration! (BPS must be 9600 for configuration)"); + break; + case ERR_E220_PACKET_TOO_BIG: + return F("The device support only 200byte of data transmission!"); + break; + default: + return F("Invalid status!"); + } +} + +enum E220_UART_PARITY +{ + MODE_00_8N1 = 0b00, + MODE_01_8O1 = 0b01, + MODE_10_8E1 = 0b10, + MODE_11_8N1 = 0b11 +}; + +static String getUARTParityDescriptionByParams(byte uartParity){ + switch (uartParity) + { + case MODE_00_8N1: + return F("8N1 (Default)"); + break; + case MODE_01_8O1: + return F("8O1"); + break; + case MODE_10_8E1: + return F("8E1"); + break; + case MODE_11_8N1: + return F("8N1 (equal to 00"); + break; + default: + return F("Invalid UART Parity!"); + } +} + +enum UART_BPS_TYPE +{ + UART_BPS_1200 = 0b000, + UART_BPS_2400 = 0b001, + UART_BPS_4800 = 0b010, + UART_BPS_9600 = 0b011, + UART_BPS_19200 = 0b100, + UART_BPS_38400 = 0b101, + UART_BPS_57600 = 0b110, + UART_BPS_115200 = 0b111 +}; + +enum UART_BPS_RATE +{ + UART_BPS_RATE_1200 = 1200, + UART_BPS_RATE_2400 = 2400, + UART_BPS_RATE_4800 = 4800, + UART_BPS_RATE_9600 = 9600, + UART_BPS_RATE_19200 = 19200, + UART_BPS_RATE_38400 = 38400, + UART_BPS_RATE_57600 = 57600, + UART_BPS_RATE_115200 = 115200 +}; + +static String getUARTBaudRateDescriptionByParams(byte uartBaudRate) +{ + switch (uartBaudRate) + { + case UART_BPS_1200: + return F("1200bps"); + break; + case UART_BPS_2400: + return F("2400bps"); + break; + case UART_BPS_4800: + return F("4800bps"); + break; + case UART_BPS_9600: + return F("9600bps (default)"); + break; + case UART_BPS_19200: + return F("19200bps"); + break; + case UART_BPS_38400: + return F("38400bps"); + break; + case UART_BPS_57600: + return F("57600bps"); + break; + case UART_BPS_115200: + return F("115200bps"); + break; + default: + return F("Invalid UART Baud Rate!"); + } +} + +enum AIR_DATA_RATE +{ + AIR_DATA_RATE_000_24 = 0b000, + AIR_DATA_RATE_001_24 = 0b001, + AIR_DATA_RATE_010_24 = 0b010, + AIR_DATA_RATE_011_48 = 0b011, + AIR_DATA_RATE_100_96 = 0b100, + AIR_DATA_RATE_101_192 = 0b101, + AIR_DATA_RATE_110_384 = 0b110, + AIR_DATA_RATE_111_625 = 0b111 +}; + + +static String getAirDataRateDescriptionByParams(byte airDataRate) +{ + switch (airDataRate) + { + case AIR_DATA_RATE_000_24: + return F("2.4kbps"); + break; + case AIR_DATA_RATE_001_24: + return F("2.4kbps"); + break; + case AIR_DATA_RATE_010_24: + return F("2.4kbps (default)"); + break; + case AIR_DATA_RATE_011_48: + return F("4.8kbps"); + break; + case AIR_DATA_RATE_100_96: + return F("9.6kbps"); + break; + case AIR_DATA_RATE_101_192: + return F("19.2kbps"); + break; + case AIR_DATA_RATE_110_384: + return F("38.4kbps"); + break; + case AIR_DATA_RATE_111_625: + return F("62.5kbps"); + break; + default: + return F("Invalid Air Data Rate!"); + } +} + +enum SUB_PACKET_SETTING { + SPS_200_00 = 0b00, + SPS_128_01 = 0b01, + SPS_064_10 = 0b10, + SPS_032_11 = 0b11 + +}; +static String getSubPacketSettingByParams(byte subPacketSetting) +{ + switch (subPacketSetting) + { + case SPS_200_00: + return F("200bytes (default)"); + break; + case SPS_128_01: + return F("128bytes"); + break; + case SPS_064_10: + return F("64bytes"); + break; + case SPS_032_11: + return F("32bytes"); + break; + default: + return F("Invalid Sub Packet Setting!"); + } +} + +enum RSSI_AMBIENT_NOISE_ENABLE { + RSSI_AMBIENT_NOISE_ENABLED = 0b1, + RSSI_AMBIENT_NOISE_DISABLED = 0b0 +}; +static String getRSSIAmbientNoiseEnableByParams(byte rssiAmbientNoiseEnabled) +{ + switch (rssiAmbientNoiseEnabled) + { + case RSSI_AMBIENT_NOISE_ENABLED: + return F("Enabled"); + break; + case RSSI_AMBIENT_NOISE_DISABLED: + return F("Disabled (default)"); + break; + default: + return F("Invalid RSSI Ambient Noise enabled!"); + } +} + +enum WOR_PERIOD { + WOR_500_000 = 0b000, + WOR_1000_001 = 0b001, + WOR_1500_010 = 0b010, + WOR_2000_011 = 0b011, + WOR_2500_100 = 0b100, + WOR_3000_101 = 0b101, + WOR_3500_110 = 0b110, + WOR_4000_111 = 0b111 + +}; +static String getWORPeriodByParams(byte WORPeriod) +{ + switch (WORPeriod) + { + case WOR_500_000: + return F("500ms"); + break; + case WOR_1000_001: + return F("1000ms"); + break; + case WOR_1500_010: + return F("1500ms"); + break; + case WOR_2000_011: + return F("2000ms (default)"); + break; + case WOR_2500_100: + return F("2500ms"); + break; + case WOR_3000_101: + return F("3000ms"); + break; + case WOR_3500_110: + return F("3500ms"); + break; + case WOR_4000_111: + return F("4000ms"); + break; + default: + return F("Invalid WOR period!"); + } +} +enum LBT_ENABLE_BYTE { + LBT_ENABLED = 0b1, + LBT_DISABLED = 0b0 +}; +static String getLBTEnableByteByParams(byte LBTEnableByte) +{ + switch (LBTEnableByte) + { + case LBT_ENABLED: + return F("Enabled"); + break; + case LBT_DISABLED: + return F("Disabled (default)"); + break; + default: + return F("Invalid LBT enable byte!"); + } +} + +enum RSSI_ENABLE_BYTE { + RSSI_ENABLED = 0b1, + RSSI_DISABLED = 0b0 +}; +static String getRSSIEnableByteByParams(byte RSSIEnableByte) +{ + switch (RSSIEnableByte) + { + case RSSI_ENABLED: + return F("Enabled"); + break; + case RSSI_DISABLED: + return F("Disabled (default)"); + break; + default: + return F("Invalid RSSI enable byte!"); + } +} + +enum FIDEX_TRANSMISSION +{ + FT_TRANSPARENT_TRANSMISSION = 0b0, + FT_FIXED_TRANSMISSION = 0b1 +}; + + +static String getFixedTransmissionDescriptionByParams(byte fixedTransmission) +{ + switch (fixedTransmission) + { + case FT_TRANSPARENT_TRANSMISSION: + return F("Transparent transmission (default)"); + break; + case FT_FIXED_TRANSMISSION: + return F("Fixed transmission (first three bytes can be used as high/low address and channel)"); + break; + default: + return F("Invalid fixed transmission param!"); + } +} + +#ifdef E220_22 + enum TRANSMISSION_POWER + { + POWER_22 = 0b00, + POWER_17 = 0b01, + POWER_13 = 0b10, + POWER_10 = 0b11 + + }; + + static String getTransmissionPowerDescriptionByParams(byte transmissionPower) + { + switch (transmissionPower) + { + case POWER_22: + return F("22dBm (Default)"); + break; + case POWER_17: + return F("17dBm"); + break; + case POWER_13: + return F("13dBm"); + break; + case POWER_10: + return F("10dBm"); + break; + default: + return F("Invalid transmission power param"); + } + } +#elif defined(E220_30) + enum TRANSMISSION_POWER + { + POWER_30 = 0b00, + POWER_27 = 0b01, + POWER_24 = 0b10, + POWER_21 = 0b11 + + }; + + static String getTransmissionPowerDescriptionByParams(byte transmissionPower) + { + switch (transmissionPower) + { + case POWER_30: + return F("30dBm (Default)"); + break; + case POWER_27: + return F("27dBm"); + break; + case POWER_24: + return F("24dBm"); + break; + case POWER_21: + return F("21dBm"); + break; + default: + return F("Invalid transmission power param"); + } + } +#else + enum TRANSMISSION_POWER + { + POWER_22 = 0b00, + POWER_17 = 0b01, + POWER_13 = 0b10, + POWER_10 = 0b11 + + }; + + static String getTransmissionPowerDescriptionByParams(byte transmissionPower) + { + switch (transmissionPower) + { + case POWER_22: + return F("22dBm (Default)"); + break; + case POWER_17: + return F("17dBm"); + break; + case POWER_13: + return F("13dBm"); + break; + case POWER_10: + return F("10dBm"); + break; + default: + return F("Invalid transmission power param"); + } + } +#endif