From 515acb426f46b68f9da9d48fc8df46d4adb32493 Mon Sep 17 00:00:00 2001 From: feeling Date: Thu, 4 Mar 2021 17:27:47 +0100 Subject: [PATCH] SoftSerialVersion --- .../ArduinoPilotNano433WindNGSoftSerial.ino | 403 ++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 AP-Remote-Software/ArduinoPilotNano433WindNGSoftSerial/ArduinoPilotNano433WindNGSoftSerial.ino diff --git a/AP-Remote-Software/ArduinoPilotNano433WindNGSoftSerial/ArduinoPilotNano433WindNGSoftSerial.ino b/AP-Remote-Software/ArduinoPilotNano433WindNGSoftSerial/ArduinoPilotNano433WindNGSoftSerial.ino new file mode 100644 index 0000000..cc2de53 --- /dev/null +++ b/AP-Remote-Software/ArduinoPilotNano433WindNGSoftSerial/ArduinoPilotNano433WindNGSoftSerial.ino @@ -0,0 +1,403 @@ +/* + This code is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Version 1.5, 16.12.2020, AK-Homberger + +#include +#include +#include +#include "SSD1306Ascii.h" +#include "SSD1306AsciiWire.h" +#include // May impact the display .... +#include + +#define PIN_SOFTSERIAL_RX 3 +#define PIN_SOFTSERIAL_TX 4 +#define PIN_RF_433 0 // THIS IS THE INTERUPT. 0 = pin2 +#define PIN_LED 6 +#define PIN_BUZZ 7 + +#define I2C_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels + +// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) +#define RST_PIN -1 // Reset pin # (or -1 if sharing Arduino reset pin) + +#define Auto_Standby_Support 1 // Set this to 1 to support Standby and Auto for Key 5 and 6 + +#define KEY_DELAY 300 // 300 ms break between keys +#define BEEP_DURATION 150 // 150 ms beep time + +#define DEBUG + + +String inputString = ""; // a String to hold incoming data +bool stringComplete = false; // whether the string is complete + +const unsigned long Key_Minus_1 PROGMEM = 1111001; // Change values to individual values programmed to remote control +const unsigned long Key_Plus_1 PROGMEM = 1111002; +const unsigned long Key_Minus_10 PROGMEM = 1111003; +const unsigned long Key_Plus_10 PROGMEM = 1111004; +const unsigned long Key_Auto PROGMEM = 1111005; +const unsigned long Key_Standby PROGMEM = 1111006; + + +// Seatalk datagrams + +const PROGMEM uint16_t ST_NMEA_BridgeID[] = { 0x190, 0x00, 0xA3 }; +const PROGMEM uint16_t ST_Minus_1[] = { 0x186, 0x21, 0x05, 0xFA }; +const PROGMEM uint16_t ST_Minus_10[] = { 0x186, 0x21, 0x06, 0xF9 }; +const PROGMEM uint16_t ST_Plus_1[] = { 0x186, 0x21, 0x07, 0xF8 }; +const PROGMEM uint16_t ST_Plus_10[] = { 0x186, 0x21, 0x08, 0xF7 }; +const PROGMEM uint16_t ST_Auto[] = { 0x186, 0x21, 0x01, 0xFE }; +const PROGMEM uint16_t ST_Standby[] = { 0x186, 0x21, 0x02, 0xFD }; +const PROGMEM uint16_t ST_BeepOn[] = { 0x1A8, 0x53, 0x80, 0x00, 0x00, 0xD3 }; +const PROGMEM uint16_t ST_BeepOff[] = { 0x1A8, 0x43, 0x80, 0x00, 0x00, 0xC3 }; + +const PROGMEM uint16_t ST_Lamp0[] = { 0x130, 0x00, 0x00 }; +const PROGMEM uint16_t ST_Lamp1[] = { 0x130, 0x00, 0x04 }; +const PROGMEM uint16_t ST_Lamp2[] = { 0x130, 0x00, 0x08 }; +const PROGMEM uint16_t ST_Lamp3[] = { 0x130, 0x00, 0x0C }; + + +boolean blink = true; +unsigned long wind_timer = 0; // timer for AWS display +unsigned long beep_timer2 = 0; // timer to stop alarm sound +unsigned long bridge_timer = 0; // timer to send ST Bridge ID every 10 seconds + +unsigned long key_time = 0; // time of last key detected +unsigned long beep_time = 0; // timer for beep duration +bool beep_status = false; + + +RCSwitch mySwitch = RCSwitch(); +SSD1306AsciiWire oled; +SoftwareSerial SerialSoft(PIN_SOFTSERIAL_RX, PIN_SOFTSERIAL_TX); // RX, TX + + +boolean sendDatagram(const uint16_t data[]) { + int i = 0; int j = 0; + boolean ok = true; + int bytes; + unsigned int inbyte; + unsigned int outbyte; + + bytes = (pgm_read_byte_near(data + 1) & 0x0f) + 3; // Messege length is minimum 3, additional bytes in nibble 4 + + while (j < 5 ) { // CDMA/CD 5 tries + while (Serial.available ()) { // Wait for silence on the bus + inbyte = (Serial.read()); + delay(3); + } + + ok = true; + for (i = 0; (i < bytes) & (ok == true); i++) { // Write and listen to detect collisions + outbyte = pgm_read_word_near(data + i); + Serial.write(outbyte); + delay(3); + + if (Serial.available ()) { + inbyte = Serial.read(); // Not what we sent, collision! + + if (inbyte != outbyte) { + ok = false; + // SerialSoft.println("ST - I<>O"); + } + } + else { + ok = false; // Nothing received + // SerialSoft.println("ST - Nothing in"); + } + } + + if ( ok )return ok; + + j++; // Collision detected + #ifdef DEBUG + SerialSoft.println("Collision"); + // Display("Collision"); + #endif + delay(random(2, 50)); // Random wait for next try + } + Display("Send Error"); + return false; +} + +void Display(char *s) { + oled.clear(); + oled.println(s); + wind_timer = millis(); +} + +void printByte(unsigned int data) { + SerialSoft.print("byte : "); + SerialSoft.print("0x"); + uint8_t MSB=byte(data>>8); + uint8_t LSB=byte(data); + if (MSB<0x10) {SerialSoft.print("0");} SerialSoft.print(MSB,HEX); SerialSoft.print(" "); + if (LSB<0x10) {SerialSoft.print("0");} SerialSoft.print(LSB,HEX); SerialSoft.print(" "); + SerialSoft.println(""); +} + +// Receive apparent wind speed from bus +int checkWind(char * AWS) { + unsigned int xx; + unsigned int y; + unsigned int inbyte; + int wind = -1; + + if (Serial.available ()) { + inbyte = Serial.read(); + #ifdef DEBUG + printByte(inbyte); + #endif + if (inbyte == 0x111) { // AWS Seatalk command - See reference from Thomas Knauf + delay(3); + inbyte = Serial.read(); + #ifdef DEBUG + printByte(inbyte); + #endif + if (inbyte == 0x01) { // AWS Setalk command + delay(3); + xx = Serial.read(); + #ifdef DEBUG + printByte(inbyte); + #endif + delay(3); + y = Serial.read(); + #ifdef DEBUG + printByte(inbyte); + #endif + wind = (xx & 0x7f) + (y / 10); // Wind speed + if (wind < 100) itoa (wind , AWS, 10); // Greater 100 must be a receive error + } + } + } + return wind; +} + + +void setup() { + SerialSoft.begin( 9600 ); // Serial out put for function checks with PC + Serial.begin( 4800, SERIAL_9N1 ); // Set the Seatalk modus - 9 bit + Serial.setTimeout(5); + + #ifdef DEBUG + SerialSoft.println(F("Setup Begin")); + #endif + + // reserve 20 bytes for the inputString: + inputString.reserve(20); + + pinMode(PIN_LED, OUTPUT); // LED to show if keys are received + digitalWrite(PIN_LED, HIGH); + + pinMode(PIN_BUZZ, OUTPUT); // Buzzer to show if keys are received + digitalWrite(PIN_BUZZ, LOW); + + Wire.begin(); + Wire.setClock(400000L); + #if RST_PIN >= 0 + oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN); + #else // RST_PIN >= 0 + oled.begin(&Adafruit128x64, I2C_ADDRESS); + #endif // RST_PIN >= 0 + oled.setFont(Cooper19); + oled.clear(); + oled.println("Starting"); + + mySwitch.enableReceive(0); // RF Receiver on inerrupt 4 => that is pin 7 on Micro + sendDatagram(ST_NMEA_BridgeID); // Send NMEA Seatakl BridgeID to make Seatalk to Seatalk NG converter happy + #ifdef DEBUG + SerialSoft.println(F("Setup Complete")); + #endif + Display("Started"); +} + + +// Beep on if key received +void BeepOn(void) { + if (beep_status == true) return; // Already On + sendDatagram(ST_BeepOn); + digitalWrite(PIN_BUZZ, HIGH); + //SerialSoft.println("On"); + beep_time = millis(); + beep_status = true; +} + + +// Beep off after BEEP_TIME +void BeepOff(void) { + + if (beep_status == true && millis() > beep_time + BEEP_DURATION) { + sendDatagram(ST_BeepOff); + digitalWrite(PIN_BUZZ, LOW); + //SerialSoft.println("Off"); + beep_status = false; + } +} + + +/* + SerialEvent occurs whenever a new data comes in the hardware serial RX. This + routine is run between each time loop() runs, so using delay inside loop can + delay response. Multiple bytes of data may be available. +*/ +void serialEvent() { + while (SerialSoft.available()) { + // get the new byte: + char inChar = (char)SerialSoft.read(); + // add it to the inputString: + if ((inChar != '\n') && (inChar != '\r')) inputString += inChar; + // if the incoming character is a newline or CR, set a flag so the main loop can react + if ((inChar == '\n') || (inChar == '\r')) { + stringComplete = true; + } + } +} + + +void loop() { + + char AWS[4] = ""; + unsigned long value = 0; + + if (millis() > wind_timer + 2000 ) { + // Display("No Wdata"); // Show --- after about two seconds when no wind data is received + wind_timer = millis(); + } + + if (millis() > beep_timer2 + 3000 ) { + sendDatagram(ST_BeepOff); // Additional Beep off after three seconds to avoid constant alarm + beep_timer2 = millis(); + } + + if (millis() > bridge_timer + 10000 ) { + #ifdef DEBUG + SerialSoft.println("Send Bridge ID"); + #endif + sendDatagram(ST_NMEA_BridgeID); // Send NMEA Seatakl BridgeID every 10 seconds to make Seatalk to Seatalk NG converter happy + bridge_timer = millis(); + } + + if (checkWind(AWS) > -1) { + Display(AWS); + wind_timer = millis(); + } + + if (mySwitch.available()) { + value = mySwitch.getReceivedValue(); + mySwitch.resetAvailable(); + } + + + serialEvent(); // Read serial to detect command from USB (until Newline or CR) + + if (stringComplete) { + // Compare string received from SerialSoft + if(inputString == "-1" ) value = Key_Minus_1; + if(inputString == "+1" ) value = Key_Plus_1; + if(inputString == "-10") value = Key_Minus_10; + if(inputString == "+10") value = Key_Plus_10; + if(inputString == "A" ) value = Key_Auto; + if(inputString == "S" ) value = Key_Standby; + // clear the string and reset status + inputString = ""; + stringComplete = false; + } + + if (value > 0 && millis() > key_time + KEY_DELAY) { + + #ifdef DEBUG + oled.clear(); + oled.println("Value : "); + oled.println(value); + SerialSoft.print(F("rf_code ")); SerialSoft.println(value); + #endif + + key_time = millis(); // Remember time of last key received + digitalWrite(PIN_LED, blink); // LED on/off + blink = !blink; // Toggle LED to show received key + + switch(value) { + case Key_Minus_1: + Display("min1"); + sendDatagram(ST_Minus_1); + BeepOn(); + break; + case Key_Plus_1: + Display("plus1"); + sendDatagram(ST_Plus_1); + BeepOn(); + break; + case Key_Minus_10: + Display("min10"); + sendDatagram(ST_Minus_10); + BeepOn(); + break; + case Key_Plus_10: + Display("plus10"); + sendDatagram(ST_Plus_10); + BeepOn(); + break; + case Key_Auto: + if(Auto_Standby_Support == 1) { + Display("Auto"); + sendDatagram(ST_Auto); + BeepOn(); + } + break; + case Key_Standby: + if(Auto_Standby_Support == 1) { + Display("Stby"); + sendDatagram(ST_Standby); + BeepOn(); + } + break; + case 97: + Display("Lamp 0"); + sendDatagram(ST_Lamp0); + BeepOn(); + break; + case 98: + Display("Lamp 1"); + sendDatagram(ST_Lamp1); + BeepOn(); + break; + case 99: + Display("Lamp 2"); + sendDatagram(ST_Lamp2); + BeepOn(); + break; + case 100: + Display("Lamp 3"); + sendDatagram(ST_Lamp3); + BeepOn(); + break; + case 101: + Display("Beep ON"); + sendDatagram(ST_BeepOn); + BeepOn(); + break; + case 102: + Display("Beep OFF"); + sendDatagram(ST_BeepOff); + BeepOn(); + break; + } + + } + BeepOff(); +} \ No newline at end of file