esp32-nmea2000-obp60/lib/obp60task/OBP60Extensions.cpp

273 lines
9.3 KiB
C++

#ifdef BOARD_NODEMCU32S_OBP60
#include <Arduino.h>
#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"
MCP23017 mcp = MCP23017(MCP23017_I2C_ADDR);
// 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
// Global vars
int outA = 0; // Outport Byte A
int outB = 0; // Outport Byte B
bool blinkingLED = false; // Enable / disable blinking flash LED
int uvDuration = 0; // Under voltage duration in n x 100ms
void MCP23017Init()
{
mcp.init();
mcp.portMode(MCP23017Port::A, 0b00110000); // Port A, 0 = out, 1 = in
mcp.portMode(MCP23017Port::B, 0b11110000); // Port B, 0 = out, 1 = in
// Extension Port A set defaults
setPortPin(OBP_DIGITAL_OUT1, false); // PA0
setPortPin(OBP_DIGITAL_OUT2, false); // PA1
setPortPin(OBP_FLASH_LED, false); // PA2
setPortPin(OBP_BACKLIGHT_LED, false); // PA3
setPortPin(OBP_POWER_50, true); // PA6
setPortPin(OBP_POWER_33, true); // PA7
// Extension Port B set defaults
setPortPin(PB0, false); // PB0
setPortPin(PB1, false); // PB1
setPortPin(PB2, false); // PB2
setPortPin(PB3, false); // PB3
}
void setPortPin(uint pin, bool value){
if(pin <=7){
outA &= ~(1 << pin); // Clear bit
outA |= (value << pin); // Set bit
mcp.writeRegister(MCP23017Register::GPIO_A, outA);
}
else{
pin = pin - 8;
outB &= ~(1 << pin); // Clear bit
outB |= (value << pin); // Set bit
mcp.writeRegister(MCP23017Register::GPIO_B, outB);
}
}
void togglePortPin(uint pin){
if(pin <=7){
outA ^= (1 << pin); // Set bit
mcp.writeRegister(MCP23017Register::GPIO_A, outA);
}
else{
pin = pin - 8;
outB ^= (1 << pin); // Set bit
mcp.writeRegister(MCP23017Register::GPIO_B, outB);
}
}
void blinkingFlashLED(){
if(blinkingLED == true){
togglePortPin(OBP_FLASH_LED);
}
}
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;
}
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;
}
// 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
SensorData calcSunsetSunrise(double time, double date, double latitude, double longitude, double timezone){
SensorData returnset;
SunRise sr;
int secPerHour = 3600;
int secPerYear = 86400;
sr.hasRise = false;
sr.hasSet = false;
time_t sunR = 0;
time_t sunS = 0;
int inthrSR = 0;
int intminSR = 0;
int inthrSS = 0;
int intminSS = 0;
bool sunDown = true;
// api->getLogger()->logDebug(GwLog::DEBUG,"... calcSun: Lat %f, Lon %f, at: %d, next SR: %d (%s), next SS: %d (%s)", latitude, longitude, t, sunR, sSunR, sunS, sSunS);
if (!isnan(time) && !isnan(date) && !isnan(latitude) && !isnan(longitude) && !isnan(timezone)) {
// Calculate local time
time_t t = (date * secPerYear) + (time + int(timezone * secPerHour));
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
inthrSR = int (sunR / secPerHour);
intminSR = int((sunR - inthrSR * secPerHour)/60);
}
// Sunset
if (sr.hasSet) {
sunS = (sr.setTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes
inthrSS = int (sunS / secPerHour);
intminSS = int((sunS - inthrSS * secPerHour)/60);
}
// Sun control (return value by sun on sky = false, sun down = true)
if ((t >= (sr.riseTime + int(timezone * secPerHour))) && (t <= (sr.setTime + int(timezone * secPerHour))))
sunDown = false;
else sunDown = true;
}
// Return values
returnset.sunsetHour = inthrSS;
returnset.sunsetMinute = intminSS;
returnset.sunriseHour = inthrSR;
returnset.sunriseMinute = intminSR;
returnset.sunDown = sunDown;
// api->getLogger()->logDebug(GwLog::DEBUG,"... calcSun: at t: %d, hasRise: %d, next SR: %d '%s', hasSet: %d, next SS: %d '%s'\n", t, sr.hasRise, sr.riseTime, sSunR, sr.hasSet, sr.setTime, sSunS);
return returnset;
}
#endif