#ifdef BOARD_OBP60S3 #include #include // Driver for WS2812 RGB LED #include // Driver for PCF8574 output modul from Horter #include // I2C #include // Driver for DS1388 RTC #include "SunRise.h" // Lib for sunrise and sunset calculation #include "Pagedata.h" #include "OBP60Hardware.h" #include "OBP60Extensions.h" // Please dont forget to declarate the fonts in OBP60ExtensionPort.h #include "Ubuntu_Bold8pt7b.h" #include "Ubuntu_Bold12pt7b.h" #include "Ubuntu_Bold16pt7b.h" #include "Ubuntu_Bold20pt7b.h" #include "Ubuntu_Bold32pt7b.h" #include "DSEG7Classic-BoldItalic16pt7b.h" #include "DSEG7Classic-BoldItalic20pt7b.h" #include "DSEG7Classic-BoldItalic30pt7b.h" #include "DSEG7Classic-BoldItalic42pt7b.h" #include "DSEG7Classic-BoldItalic60pt7b.h" // SPI pin definitions for E-Ink display GxIO_Class io(SPI, OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST); // SPI, CS, DC, RST GxEPD_Class display(io, OBP_SPI_RST, OBP_SPI_BUSY); // io, RST, BUSY // Horter I2C moduls PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter // RTC DS1388 RTC_DS1388 ds1388; // Define the array of leds CRGB fled[NUM_FLASH_LED]; // Flash LED CRGB backlight[NUM_BACKLIGHT_LED]; // Backlight // Global vars bool blinkingLED = false; // Enable / disable blinking flash LED bool statusLED = false; // Actual status of flash LED on/off bool statusBacklightLED = false;// Actual status of flash LED on/off int uvDuration = 0; // Under voltage duration in n x 100ms void hardwareInit() { // Init power rail 5.0V setPortPin(OBP_POWER_50, true); // Init RGB LEDs FastLED.addLeds(fled, NUM_FLASH_LED); FastLED.addLeds(backlight, NUM_BACKLIGHT_LED); // Init PCF8574 digital outputs Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz if(pcf8574_Out.begin()){ // Initialize PCF8574 pcf8574_Out.write8(255); // Clear all outputs } // Init DS1388 RTC if(ds1388.begin()){ uint year = ds1388.now().year(); if(year < 2023){ ds1388.adjust(DateTime(__DATE__, __TIME__)); // Set date and time from PC file time } } } void setPortPin(uint pin, bool value){ pinMode(pin, OUTPUT); digitalWrite(pin, value); } void togglePortPin(uint pin){ pinMode(pin, OUTPUT); digitalWrite(pin, !digitalRead(pin)); } CRGB colorMapping(String colorString){ CRGB color = CRGB::Red; if(colorString == "Red"){color = CRGB::Red;} if(colorString == "Orange"){color = CRGB::Orange;} if(colorString == "Yellow"){color = CRGB::Yellow;} if(colorString == "Green"){color = CRGB::Green;} if(colorString == "Blue"){color = CRGB::Blue;} if(colorString == "Aqua"){color = CRGB::Aqua;} if(colorString == "Violet"){color = CRGB::Violet;} if(colorString == "White"){color = CRGB::White;} return color; } // All defined colors see pixeltypes.h in FastLED lib void setBacklightLED(uint brightness, CRGB color){ FastLED.setBrightness(brightness); // Brightness for flash LED backlight[0] = color; // Backlight LEDs on with color backlight[1] = color; backlight[2] = color; backlight[3] = color; backlight[4] = color; backlight[5] = color; FastLED.show(); } void toggleBacklightLED(uint brightness, CRGB color){ statusBacklightLED = !statusBacklightLED; FastLED.setBrightness(brightness); // Brightness for flash LED if(statusBacklightLED == true){ backlight[0] = color; // Backlight LEDs on backlight[1] = color; backlight[2] = color; backlight[3] = color; backlight[4] = color; backlight[5] = color; } else{ backlight[0] = CRGB::Black; // Backlight LEDs off backlight[1] = CRGB::Black; backlight[2] = CRGB::Black; backlight[3] = CRGB::Black; backlight[4] = CRGB::Black; backlight[5] = CRGB::Black; } FastLED.show(); } void setFlashLED(bool status){ statusLED = status; FastLED.setBrightness(255); // Brightness for flash LED if(statusLED == true){ fled[0] = CRGB::Red; // Flash LED on in red } else{ fled[0] = CRGB::Black; // Flash LED off } FastLED.show(); } void blinkingFlashLED(){ if(blinkingLED == true){ statusLED = !statusLED; FastLED.setBrightness(255); // Brightness for flash LED if(statusLED == true){ fled[0] = CRGB::Red; // Flash LED on in red } else{ fled[0] = CRGB::Black; // Flash LED off } FastLED.show(); } } void setBlinkingLED(bool on){ blinkingLED = on; } uint buzzerpower = 50; void buzzer(uint frequency, uint duration){ if(frequency > 8000){ // Max 8000Hz frequency = 8000; } if(buzzerpower > 100){ // Max 100% buzzerpower = 100; } if(duration > 1000){ // Max 1000ms duration = 1000; } // Using LED PWM function for sound generation pinMode(OBP_BUZZER, OUTPUT); ledcSetup(0, frequency, 8); // Ch 0, ferquency in Hz, 8 Bit resolution of PWM ledcAttachPin(OBP_BUZZER, 0); ledcWrite(0, uint(buzzerpower * 1.28)); // 50% duty cycle are 100% delay(duration); ledcWrite(0, 0); // 0% duty cycle are 0% } void setBuzzerPower(uint power){ buzzerpower = power; } // Delete xdr prefix from string String xdrDelete(String input){ if(input.substring(0,3) == "xdr"){ input = input.substring(3, input.length()); } return input; } // Show a triangle for trend direction high (x, y is the left edge) void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ display.fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); } // Show a triangle for trend direction low (x, y is the left edge) void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color){ display.fillTriangle(x, y, x+size*2, y, x+size, y+size*2, color); } // Show header informations void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time){ static bool heartbeat = false; static unsigned long usbRxOld = 0; static unsigned long usbTxOld = 0; static unsigned long serRxOld = 0; static unsigned long serTxOld = 0; static unsigned long tcpSerRxOld = 0; static unsigned long tcpSerTxOld = 0; static unsigned long tcpClRxOld = 0; static unsigned long tcpClTxOld = 0; static unsigned long n2kRxOld = 0; static unsigned long n2kTxOld = 0; int textcolor = GxEPD_BLACK; if(commonData.config->getBool(commonData.config->statusLine) == true){ if(commonData.config->getString(commonData.config->displaycolor) == "Normal"){ textcolor = GxEPD_BLACK; } else{ textcolor = GxEPD_WHITE; } // Show status info display.setTextColor(textcolor); display.setFont(&Ubuntu_Bold8pt7b); display.setCursor(0, 15); if(commonData.status.wifiApOn){ display.print(" AP "); } // If receive new telegram data then display bus name if(commonData.status.tcpClRx != tcpClRxOld || commonData.status.tcpClTx != tcpClTxOld || commonData.status.tcpSerRx != tcpSerRxOld || commonData.status.tcpSerTx != tcpSerTxOld){ display.print("TCP "); } if(commonData.status.n2kRx != n2kRxOld || commonData.status.n2kTx != n2kTxOld){ display.print("N2K "); } if(commonData.status.serRx != serRxOld || commonData.status.serTx != serTxOld){ display.print("183 "); } if(commonData.status.usbRx != usbRxOld || commonData.status.usbTx != usbTxOld){ display.print("USB "); } if(commonData.config->getBool(commonData.config->useGPS) == true && date->valid == true){ display.print("GPS"); } // Save old telegram counter tcpClRxOld = commonData.status.tcpClRx; tcpClTxOld = commonData.status.tcpClTx; tcpSerRxOld = commonData.status.tcpSerRx; tcpSerTxOld = commonData.status.tcpSerTx; n2kRxOld = commonData.status.n2kRx; n2kTxOld = commonData.status.n2kTx; serRxOld = commonData.status.serRx; serTxOld = commonData.status.serTx; usbRxOld = commonData.status.usbRx; usbTxOld = commonData.status.usbTx; // Heartbeat as dot display.setTextColor(textcolor); display.setFont(&Ubuntu_Bold32pt7b); display.setCursor(205, 14); if(heartbeat == true){ display.print("."); } else{ display.print(" "); } heartbeat = !heartbeat; // Date and time display.setTextColor(textcolor); display.setFont(&Ubuntu_Bold8pt7b); display.setCursor(230, 15); if(date->valid == true){ String acttime = formatValue(time, commonData).svalue; acttime = acttime.substring(0, 5); String actdate = formatValue(date, commonData).svalue; display.print(acttime); display.print(" "); display.print(actdate); display.print(" "); if(commonData.config->getInt(commonData.config->timeZone) == 0){ display.print("UTC"); } else{ display.print("LOT"); } } else{ display.print("No GPS data"); } } } // Sunset und sunrise calculation SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){ GwLog *logger=api->getLogger(); SunData returnset; SunRise sr; int secPerHour = 3600; int secPerYear = 86400; sr.hasRise = false; sr.hasSet = false; time_t t = 0; time_t sunR = 0; time_t sunS = 0; if (!isnan(time) && !isnan(date) && !isnan(latitude) && !isnan(longitude) && !isnan(timezone)) { // Calculate local epoch t = (date * secPerYear) + time; // api->getLogger()->logDebug(GwLog::DEBUG,"... calcSun: Lat %f, Lon %f, at: %d ", latitude, longitude, t); sr.calculate(latitude, longitude, t); // LAT, LON, EPOCH // Sunrise if (sr.hasRise) { sunR = (sr.riseTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes returnset.sunriseHour = int (sunR / secPerHour); returnset.sunriseMinute = int((sunR - returnset.sunriseHour * secPerHour)/60); } // Sunset if (sr.hasSet) { sunS = (sr.setTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes returnset.sunsetHour = int (sunS / secPerHour); returnset.sunsetMinute = int((sunS - returnset.sunsetHour * secPerHour)/60); } // Sun control (return value by sun on sky = false, sun down = true) if ((t >= sr.riseTime) && (t <= sr.setTime)) returnset.sunDown = false; else returnset.sunDown = true; } // Return values return returnset; } // Battery graphic with fill level void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor){ // Show battery int xb = x; // X position int yb = y; // Y position int t = 4; // Line thickness // Percent limits if(percent < 0){ percent = 0; } if(percent > 99){ percent = 99; } // Battery corpus 100x80 with fill level int level = int((100.0 - percent) * (80-(2*t)) / 100.0); display.fillRect(xb, yb, 100, 80, pcolor); if(percent < 99){ display.fillRect(xb+t, yb+t, 100-(2*t), level, bcolor); } // Plus pol 20x15 int xp = xb + 20; int yp = yb - 15 + t; display.fillRect(xp, yp, 20, 15, pcolor); display.fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor); // Minus pol 20x15 int xm = xb + 60; int ym = yb -15 + t; display.fillRect(xm, ym, 20, 15, pcolor); display.fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor); } #endif