Initial commit
This commit is contained in:
0
extra_post.py
Normal file
0
extra_post.py
Normal file
0
extra_pre.py
Normal file
0
extra_pre.py
Normal file
34
include/hardware.h
Normal file
34
include/hardware.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// General hardware definitions
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Keys
|
||||||
|
#define KEY_1 1 // Key or touchpad
|
||||||
|
#define KEY_2 2 // Key or touchpad
|
||||||
|
|
||||||
|
// I2S audio output -> PCM5102 DAC
|
||||||
|
#define I2S_DOUT 4 // data out
|
||||||
|
#define I2S_BCLK 5 // bit clock
|
||||||
|
#define I2S_LRC 6 // left right channel select
|
||||||
|
#define I2S_XSMT 7 // PCM5102 soft mute
|
||||||
|
|
||||||
|
// SPI for SD-Card; VSPI pins for higher performance
|
||||||
|
#define SD_CS 10
|
||||||
|
#define SD_MOSI 11
|
||||||
|
#define SD_MISO 13
|
||||||
|
#define SD_SCK 12
|
||||||
|
|
||||||
|
// I2C for control interface
|
||||||
|
#define I2C_SDA 8
|
||||||
|
#define I2C_CLK 9
|
||||||
|
|
||||||
|
// CAN bus for NMEA2000 connection
|
||||||
|
#define CAN_RX 47
|
||||||
|
#define CAN_TX 48
|
||||||
|
|
||||||
|
// RS485 for NMEA0183 connection / UART1
|
||||||
|
#define SER_RX 18
|
||||||
|
#define SER_TX 17
|
||||||
|
|
||||||
|
// I2C Addresses
|
||||||
|
// Address of DAC module
|
||||||
|
// Address of switchbank
|
||||||
38
include/main.h
Normal file
38
include/main.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma
|
||||||
|
|
||||||
|
// WIFI AP
|
||||||
|
#define WIFI_CHANNEL 9
|
||||||
|
#define WIFI_MAX_STA 2
|
||||||
|
|
||||||
|
// Keys
|
||||||
|
#define KEY_1 GPIO_NUM_5 // D2
|
||||||
|
#define KEY_2 GPIO_NUM_6 // D3
|
||||||
|
#define KEY_3 GPIO_NUM_7 // D4
|
||||||
|
#define KEY_4 GPIO_NUM_8 // D5
|
||||||
|
#define KEY_5 GPIO_NUM_9 // D6
|
||||||
|
#define KEY_6 GPIO_NUM_10 // D7
|
||||||
|
#define KEY_DST GPIO_NUM_17
|
||||||
|
|
||||||
|
// LEDS
|
||||||
|
#define LED_A GPIO_NUM_1
|
||||||
|
#define LED_B GPIO_NUM_2
|
||||||
|
#define LED_C GPIO_NUM_3
|
||||||
|
#define LED_RGBA GPIO_NUM_4
|
||||||
|
#define LED_RGBB GPIO_NUM_13
|
||||||
|
#define LED_RGBC GPIO_NUM_14
|
||||||
|
#define LED_USER GPIO_NUM_48
|
||||||
|
|
||||||
|
// CAN bus for NMEA2000 connection
|
||||||
|
#define CAN_RX GPIO_NUM_18 // D9
|
||||||
|
#define CAN_TX GPIO_NUM_21 // D10
|
||||||
|
#define CAN_RECOVERY_PERIOD 3000
|
||||||
|
|
||||||
|
// NMEA2000 defaults
|
||||||
|
#define N2K_DEFAULT_NODEID 124
|
||||||
|
|
||||||
|
// I2C temp. sensor
|
||||||
|
#define I2C_SDA GPIO_NUM_11 // A4
|
||||||
|
#define I2C_SCL GPIO_NUM_12 // A5
|
||||||
|
|
||||||
|
// I2C addresses
|
||||||
|
#define SHT31_ADDRESS 0x44
|
||||||
224
lib/Nmea2kTwai/Nmea2kTwai.cpp
Normal file
224
lib/Nmea2kTwai/Nmea2kTwai.cpp
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include "Nmea2kTwai.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/twai.h"
|
||||||
|
|
||||||
|
#define LOGID(id) ((id >> 8) & 0x1ffff)
|
||||||
|
|
||||||
|
static const int TIMEOUT_OFFLINE = 256; // number of timeouts to consider offline
|
||||||
|
|
||||||
|
Nmea2kTwai::Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin, unsigned long recP, unsigned long logP):
|
||||||
|
tNMEA2000(), RxPin(_RxPin), TxPin(_TxPin)
|
||||||
|
{
|
||||||
|
if (RxPin < 0 || TxPin < 0){
|
||||||
|
disabled = true;
|
||||||
|
} else {
|
||||||
|
// timers.addAction(logP,[this](){ logStatus(); });
|
||||||
|
// timers.addAction(recP,[this](){ checkRecovery(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nmea2kTwai::CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool wait_sent)
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
twai_message_t message;
|
||||||
|
memset(&message, 0, sizeof(message));
|
||||||
|
message.identifier = id;
|
||||||
|
message.extd = 1;
|
||||||
|
message.data_length_code = len;
|
||||||
|
memcpy(message.data, buf,len);
|
||||||
|
esp_err_t rt = twai_transmit(&message, 0);
|
||||||
|
if (rt != ESP_OK){
|
||||||
|
if (rt == ESP_ERR_TIMEOUT) {
|
||||||
|
if (txTimeouts < TIMEOUT_OFFLINE) txTimeouts++;
|
||||||
|
}
|
||||||
|
// logDebug(LOG_MSG,"twai transmit for %ld failed: %x",LOGID(id),(int)rt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
txTimeouts = 0;
|
||||||
|
// logDebug(LOG_MSG,"twai transmit id %ld, len %d",LOGID(id),(int)len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nmea2kTwai::CANOpen()
|
||||||
|
{
|
||||||
|
if (disabled){
|
||||||
|
// logDebug(LOG_INFO,"CAN disabled");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
esp_err_t rt = twai_start();
|
||||||
|
if (rt != ESP_OK){
|
||||||
|
// logDebug(LOG_ERR,"CANOpen failed: %x",(int)rt);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// logDebug(LOG_INFO, "CANOpen ok");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nmea2kTwai::CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf)
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
twai_message_t message;
|
||||||
|
esp_err_t rt = twai_receive(&message, 0);
|
||||||
|
if (rt != ESP_OK){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (! message.extd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
id = message.identifier;
|
||||||
|
len = message.data_length_code;
|
||||||
|
if (len > 8) {
|
||||||
|
// logDebug(LOG_DEBUG,"twai: received invalid message %lld, len %d",LOGID(id),len);
|
||||||
|
len = 8;
|
||||||
|
}
|
||||||
|
// logDebug(LOG_MSG,"twai rcv id=%ld,len=%d, ext=%d",LOGID(message.identifier),message.data_length_code,message.extd);
|
||||||
|
if (! message.rtr) {
|
||||||
|
memcpy(buf, message.data, message.data_length_code);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nmea2kTwai::initDriver()
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TxPin,RxPin, TWAI_MODE_NORMAL);
|
||||||
|
g_config.tx_queue_len = 20;
|
||||||
|
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
|
||||||
|
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||||
|
esp_err_t rt = twai_driver_install(&g_config, &t_config, &f_config);
|
||||||
|
if (rt == ESP_OK) {
|
||||||
|
// logDebug(LOG_INFO,"twai driver initialzed, rx=%d,tx=%d",(int)RxPin,(int)TxPin);
|
||||||
|
} else {
|
||||||
|
// logDebug(LOG_ERR,"twai driver init failed: %x",(int)rt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will be called on Open() before any other initialization.
|
||||||
|
* Inherit this, if buffers can be set for the driver and you want to
|
||||||
|
* change size of library send frame buffer size.
|
||||||
|
* See e.g. NMEA2000_teensy.cpp.
|
||||||
|
*/
|
||||||
|
void Nmea2kTwai::InitCANFrameBuffers()
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
// logDebug(LOG_INFO,"twai init - disabled");
|
||||||
|
} else{
|
||||||
|
initDriver();
|
||||||
|
}
|
||||||
|
tNMEA2000::InitCANFrameBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
Nmea2kTwai::Status Nmea2kTwai::getStatus()
|
||||||
|
{
|
||||||
|
twai_status_info_t state;
|
||||||
|
Status rt;
|
||||||
|
if (disabled) {
|
||||||
|
rt.state = ST_DISABLED;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
if (twai_get_status_info(&state) != ESP_OK) {
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
switch (state.state) {
|
||||||
|
case TWAI_STATE_STOPPED:
|
||||||
|
rt.state = ST_STOPPED;
|
||||||
|
break;
|
||||||
|
case TWAI_STATE_RUNNING:
|
||||||
|
rt.state = ST_RUNNING;
|
||||||
|
break;
|
||||||
|
case TWAI_STATE_BUS_OFF:
|
||||||
|
rt.state = ST_BUS_OFF;
|
||||||
|
break;
|
||||||
|
case TWAI_STATE_RECOVERING:
|
||||||
|
rt.state = ST_RECOVERING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rt.rx_errors = state.rx_error_counter;
|
||||||
|
rt.tx_errors = state.tx_error_counter;
|
||||||
|
rt.tx_failed = state.tx_failed_count;
|
||||||
|
rt.rx_missed = state.rx_missed_count;
|
||||||
|
rt.rx_overrun = state.rx_overrun_count;
|
||||||
|
rt.tx_timeouts = txTimeouts;
|
||||||
|
if (rt.tx_timeouts >= TIMEOUT_OFFLINE && rt.state == ST_RUNNING) {
|
||||||
|
rt.state = ST_OFFLINE;
|
||||||
|
}
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nmea2kTwai::checkRecovery()
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Status canState = getStatus();
|
||||||
|
bool strt = false;
|
||||||
|
if (canState.state != Nmea2kTwai::ST_RUNNING) {
|
||||||
|
if (canState.state == Nmea2kTwai::ST_BUS_OFF) {
|
||||||
|
strt = true;
|
||||||
|
bool rt = startRecovery();
|
||||||
|
// logDebug(LOG_INFO, "twai BUS_OFF: start can recovery - result %d", (int)rt);
|
||||||
|
}
|
||||||
|
if (canState.state == Nmea2kTwai::ST_STOPPED) {
|
||||||
|
bool rt = CANOpen();
|
||||||
|
// logDebug(LOG_INFO, "twai STOPPED: restart can driver - result %d", (int)rt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nmea2kTwai::loop()
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// timers.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Nmea2kTwai::Status Nmea2kTwai::logStatus()
|
||||||
|
{
|
||||||
|
Status canState = getStatus();
|
||||||
|
/* logDebug(LOG_INFO, "twai state %s, rxerr %d, txerr %d, txfail %d, txtimeout %d, rxmiss %d, rxoverrun %d",
|
||||||
|
stateStr(canState.state),
|
||||||
|
canState.rx_errors,
|
||||||
|
canState.tx_errors,
|
||||||
|
canState.tx_failed,
|
||||||
|
canState.tx_timeouts,
|
||||||
|
canState.rx_missed,
|
||||||
|
canState.rx_overrun); */
|
||||||
|
return canState;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nmea2kTwai::startRecovery()
|
||||||
|
{
|
||||||
|
if (disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lastRecoveryStart = millis();
|
||||||
|
esp_err_t rt = twai_driver_uninstall();
|
||||||
|
if (rt != ESP_OK) {
|
||||||
|
// logDebug(LOG_ERR,"twai: deinit for recovery failed with %x",(int)rt);
|
||||||
|
}
|
||||||
|
initDriver();
|
||||||
|
bool frt = CANOpen();
|
||||||
|
return frt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * Nmea2kTwai::stateStr(const Nmea2kTwai::STATE &st)
|
||||||
|
{
|
||||||
|
switch (st) {
|
||||||
|
case ST_BUS_OFF: return "BUS_OFF";
|
||||||
|
case ST_RECOVERING: return "RECOVERING";
|
||||||
|
case ST_RUNNING: return "RUNNING";
|
||||||
|
case ST_STOPPED: return "STOPPED";
|
||||||
|
case ST_OFFLINE: return "OFFLINE";
|
||||||
|
case ST_DISABLED: return "DISABLED";
|
||||||
|
}
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
62
lib/Nmea2kTwai/Nmea2kTwai.h
Normal file
62
lib/Nmea2kTwai/Nmea2kTwai.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef _NMEA2KTWAI_H
|
||||||
|
#define _NMEA2KTWAI_H
|
||||||
|
#include "NMEA2000.h"
|
||||||
|
// #include "GwTimer.h"
|
||||||
|
|
||||||
|
class Nmea2kTwai : public tNMEA2000 {
|
||||||
|
public:
|
||||||
|
Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin, unsigned long recP=0, unsigned long logPeriod=0);
|
||||||
|
typedef enum {
|
||||||
|
ST_STOPPED,
|
||||||
|
ST_RUNNING,
|
||||||
|
ST_BUS_OFF,
|
||||||
|
ST_RECOVERING,
|
||||||
|
ST_OFFLINE,
|
||||||
|
ST_DISABLED,
|
||||||
|
ST_ERROR
|
||||||
|
} STATE;
|
||||||
|
typedef struct{
|
||||||
|
//see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html#_CPPv418twai_status_info_t
|
||||||
|
uint32_t rx_errors = 0;
|
||||||
|
uint32_t tx_errors = 0;
|
||||||
|
uint32_t tx_failed = 0;
|
||||||
|
uint32_t rx_missed = 0;
|
||||||
|
uint32_t rx_overrun = 0;
|
||||||
|
uint32_t tx_timeouts = 0;
|
||||||
|
STATE state = ST_ERROR;
|
||||||
|
} Status;
|
||||||
|
Status getStatus();
|
||||||
|
unsigned long getLastRecoveryStart() { return lastRecoveryStart; }
|
||||||
|
void loop();
|
||||||
|
static const char *stateStr(const STATE &st);
|
||||||
|
virtual bool CANOpen();
|
||||||
|
virtual ~Nmea2kTwai(){};
|
||||||
|
static const int LOG_ERR = 0;
|
||||||
|
static const int LOG_INFO = 1;
|
||||||
|
static const int LOG_DEBUG = 2;
|
||||||
|
static const int LOG_MSG = 3;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool wait_sent=true);
|
||||||
|
virtual bool CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf);
|
||||||
|
/* This will be called on Open() before any other initialization.
|
||||||
|
Inherit this, if buffers can be set for the driver and you want
|
||||||
|
to change size of library send frame buffer size.
|
||||||
|
See e.g. NMEA2000_teensy.cpp. */
|
||||||
|
virtual void InitCANFrameBuffers();
|
||||||
|
virtual void logDebug(int level,const char *fmt,...){}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initDriver();
|
||||||
|
bool startRecovery();
|
||||||
|
bool checkRecovery();
|
||||||
|
Status logStatus();
|
||||||
|
gpio_num_t TxPin;
|
||||||
|
gpio_num_t RxPin;
|
||||||
|
uint32_t txTimeouts = 0;
|
||||||
|
// GwIntervalRunner timers;
|
||||||
|
bool disabled = false;
|
||||||
|
unsigned long lastRecoveryStart=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
35
platformio.ini
Normal file
35
platformio.ini
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
[platformio]
|
||||||
|
default_envs=
|
||||||
|
esp32-s3-nano
|
||||||
|
|
||||||
|
[env]
|
||||||
|
platform = espressif32
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
||||||
|
Preferences
|
||||||
|
Wifi
|
||||||
|
Wire
|
||||||
|
ESP32Async/AsyncTCP@3.4.9
|
||||||
|
ESP32Async/ESPAsyncWebServer@3.9.1
|
||||||
|
ttlappalainen/NMEA2000-library@4.24
|
||||||
|
robtillaart/SHT31@^0.5.2
|
||||||
|
# adafruit/Adafruit NeoPixel
|
||||||
|
|
||||||
|
extra_scripts =
|
||||||
|
pre:extra_pre.py
|
||||||
|
post:extra_post.py
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
monitor_speed = 115200
|
||||||
|
build_flags =
|
||||||
|
-D PIO_ENV_BUILD=$PIOENV
|
||||||
|
-DBOARD_HAS_PSRAM
|
||||||
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
|
||||||
|
[env:esp32-s3-nano]
|
||||||
|
build_type = release # debug | release
|
||||||
|
#board = esp32-s3-devkitc-1
|
||||||
|
board = arduino_nano_esp32
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default.csv
|
||||||
|
upload_port = /dev/ttyACM0
|
||||||
|
upload_protocol = esptool
|
||||||
295
src/main.cpp
Normal file
295
src/main.cpp
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <Preferences.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <SHT31.h> // temp. sensor
|
||||||
|
#include <NMEA2000.h>
|
||||||
|
#include <N2kMsg.h>
|
||||||
|
#include <N2kMessages.h>
|
||||||
|
#include "main.h"
|
||||||
|
#include "Nmea2kTwai.h"
|
||||||
|
|
||||||
|
Preferences preferences; // persistent storage for configuration
|
||||||
|
|
||||||
|
const char* wifi_ssid = "OBPKP61";
|
||||||
|
const char* wifi_pass = "keypad61";
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
const char index_html[] PROGMEM = R"rawliteral(
|
||||||
|
<!DOCTYPE HTML><html>
|
||||||
|
<head>
|
||||||
|
<title>ESP Web Server</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="data:,">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>ESP Web Server</h2>
|
||||||
|
<p>Work in progress</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)rawliteral";
|
||||||
|
|
||||||
|
unsigned long lastPrint = 0;
|
||||||
|
unsigned long counter = 0;
|
||||||
|
|
||||||
|
bool rgb_r = false;
|
||||||
|
bool rgb_g = false;
|
||||||
|
bool rgb_b = false;
|
||||||
|
|
||||||
|
char destination = 'A'; // A | B | C
|
||||||
|
|
||||||
|
SHT31 sht(SHT31_ADDRESS);
|
||||||
|
|
||||||
|
int nodeid; // NMEA2000 id on bus
|
||||||
|
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
|
||||||
|
|
||||||
|
|
||||||
|
String processor(const String& var) {
|
||||||
|
// dummy for now
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Low level wifi setup (alternative)
|
||||||
|
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
|
||||||
|
int32_t event_id, void* event_data)
|
||||||
|
{
|
||||||
|
// printf("Event nr: %ld!\n", event_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_init_softap()
|
||||||
|
{
|
||||||
|
esp_netif_init();
|
||||||
|
esp_event_loop_create_default();
|
||||||
|
esp_netif_create_default_wifi_ap();
|
||||||
|
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL);
|
||||||
|
esp_wifi_init(&cfg);
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
.ap = {
|
||||||
|
.ssid = wifi_ssid,
|
||||||
|
.ssid_len = strlen(wifi_ssid),
|
||||||
|
.channel = WIFI_CHANNEL,
|
||||||
|
.password = wifi_pass,
|
||||||
|
.max_connection = WIFI_MAX_STA,
|
||||||
|
.authmode = WIFI_AUTH_WPA2_PSK,
|
||||||
|
.pmf_cfg = {
|
||||||
|
.required = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
esp_wifi_set_mode(WIFI_MODE_AP);
|
||||||
|
esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
|
||||||
|
esp_wifi_start();
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
|
||||||
|
ESP_WIFI_SSID, ESP_WIFI_PASS, ESP_WIFI_CHANNEL);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
nodeid = N2K_DEFAULT_NODEID;
|
||||||
|
Serial.print("N2K default node id=");
|
||||||
|
Serial.println(nodeid);
|
||||||
|
|
||||||
|
preferences.begin("nvs", false);
|
||||||
|
nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID);
|
||||||
|
preferences.end();
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Connect as client to existing network
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("Connecting to WiFi..");
|
||||||
|
}
|
||||||
|
Serial.println(WiFi.localIP()); */
|
||||||
|
|
||||||
|
WiFi.persistent(false);
|
||||||
|
WiFi.mode(WIFI_MODE_AP);
|
||||||
|
|
||||||
|
IPAddress ap_addr(192, 168, 15, 1);
|
||||||
|
IPAddress ap_subnet(255, 255, 255, 0);
|
||||||
|
IPAddress ap_gateway(ap_addr);
|
||||||
|
|
||||||
|
int channel = WIFI_CHANNEL;
|
||||||
|
bool hidden = false;
|
||||||
|
WiFi.softAP(wifi_ssid, wifi_pass, channel, hidden, WIFI_MAX_STA);
|
||||||
|
|
||||||
|
// Route for root / web page
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
request->send(200, "text/html", index_html, processor);
|
||||||
|
});
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
NMEA2000.SetProductInformation("00000001", // Manufacturer's Model serial code
|
||||||
|
74, // Manufacturer's product code
|
||||||
|
"OBPkeypad6/1", // Manufacturer's Model ID
|
||||||
|
"1.0.0 (2025-11-28)", // Manufacturer's Software version code
|
||||||
|
"0.1" // Manufacturer's Model version
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO Device unique id stored in preferences
|
||||||
|
NMEA2000.SetDeviceInformation(1, // Unique number. Use e.g. Serial number.
|
||||||
|
130, // Device function=Atmospheric
|
||||||
|
85, // Device class=External Environment
|
||||||
|
2046
|
||||||
|
);
|
||||||
|
|
||||||
|
// Buttons active-low, internal resistor
|
||||||
|
pinMode(KEY_1, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_2, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_3, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_4, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_5, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_6, INPUT_PULLUP);
|
||||||
|
pinMode(KEY_DST, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// internal user led (red)
|
||||||
|
pinMode(LED_USER, OUTPUT);
|
||||||
|
digitalWrite(LED_USER, HIGH);
|
||||||
|
delay(1000);
|
||||||
|
digitalWrite(LED_USER, LOW);
|
||||||
|
|
||||||
|
// destination leds
|
||||||
|
pinMode(LED_A, OUTPUT);
|
||||||
|
digitalWrite(LED_A, HIGH);
|
||||||
|
pinMode(LED_B, OUTPUT);
|
||||||
|
digitalWrite(LED_B, LOW);
|
||||||
|
pinMode(LED_C, OUTPUT);
|
||||||
|
digitalWrite(LED_C, LOW);
|
||||||
|
|
||||||
|
// Init onbard RGB LED
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// enclosure rgb led (common anode)
|
||||||
|
pinMode(LED_RGBA, OUTPUT);
|
||||||
|
digitalWrite(LED_RGBA, HIGH);
|
||||||
|
pinMode(LED_RGBB, OUTPUT);
|
||||||
|
digitalWrite(LED_RGBB, HIGH);
|
||||||
|
pinMode(LED_RGBC, OUTPUT);
|
||||||
|
digitalWrite(LED_RGBC, HIGH);
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(500);
|
||||||
|
Serial.println("Starting...");
|
||||||
|
|
||||||
|
// I²C
|
||||||
|
Serial.print("SHT31_LIB_VERSION: ");
|
||||||
|
Serial.println(SHT31_LIB_VERSION);
|
||||||
|
Wire.begin(I2C_SDA, I2C_SCL);
|
||||||
|
Wire.setClock(100000);
|
||||||
|
uint16_t stat = sht.readStatus();
|
||||||
|
Serial.print(stat, HEX);
|
||||||
|
// stat = ffff anscheinend Fehler
|
||||||
|
// = 8010 läuft anscheinend
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Button pressed? (active low)
|
||||||
|
uint8_t button = 0;
|
||||||
|
if (digitalRead(KEY_1) == LOW) {
|
||||||
|
Serial.println("Button detected: 1");
|
||||||
|
button = 1;
|
||||||
|
if (rgb_r) {
|
||||||
|
rgb_r = false;
|
||||||
|
digitalWrite(LED_RGBA, HIGH);
|
||||||
|
} else {
|
||||||
|
rgb_r = true;
|
||||||
|
digitalWrite(LED_RGBA, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (digitalRead(KEY_2) == LOW) {
|
||||||
|
Serial.println("Button detected: 2");
|
||||||
|
button += 2;
|
||||||
|
if (rgb_g) {
|
||||||
|
rgb_g = false;
|
||||||
|
digitalWrite(LED_RGBB, HIGH);
|
||||||
|
} else {
|
||||||
|
rgb_g = true;
|
||||||
|
digitalWrite(LED_RGBB, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (digitalRead(KEY_3) == LOW) {
|
||||||
|
Serial.println("Button detected: 3");
|
||||||
|
button += 4;
|
||||||
|
if (rgb_b) {
|
||||||
|
rgb_b = false;
|
||||||
|
digitalWrite(LED_RGBC, HIGH);
|
||||||
|
} else {
|
||||||
|
rgb_b = true;
|
||||||
|
digitalWrite(LED_RGBC, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(KEY_4) == LOW) {
|
||||||
|
Serial.println("Button detected: 4");
|
||||||
|
button += 8;
|
||||||
|
digitalWrite(LED_USER, HIGH); // Turn LED on
|
||||||
|
delay(500); // Keep it on 0.5s
|
||||||
|
digitalWrite(LED_USER, LOW); // Turn LED off
|
||||||
|
}
|
||||||
|
if (digitalRead(KEY_5) == LOW) {
|
||||||
|
Serial.println("Button detected: 5");
|
||||||
|
button += 16;
|
||||||
|
digitalWrite(LED_USER, HIGH); // Turn LED on
|
||||||
|
delay(500); // Keep it on 0.5s
|
||||||
|
digitalWrite(LED_USER, LOW); // Turn LED off
|
||||||
|
}
|
||||||
|
if (digitalRead(KEY_6) == LOW) {
|
||||||
|
Serial.println("Button detected: 6");
|
||||||
|
button += 32;
|
||||||
|
digitalWrite(LED_USER, HIGH); // Turn LED on
|
||||||
|
delay(500); // Keep it on 0.5s
|
||||||
|
digitalWrite(LED_USER, LOW); // Turn LED off
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(KEY_DST) == LOW) {
|
||||||
|
Serial.println("Button detected: DST");
|
||||||
|
button += 64;
|
||||||
|
|
||||||
|
if (destination == 'A') {
|
||||||
|
destination = 'B';
|
||||||
|
digitalWrite(LED_A, LOW);
|
||||||
|
digitalWrite(LED_B, HIGH);
|
||||||
|
} else if (destination == 'B') {
|
||||||
|
destination = 'C';
|
||||||
|
digitalWrite(LED_B, LOW);
|
||||||
|
digitalWrite(LED_C, HIGH);
|
||||||
|
} else {
|
||||||
|
destination = 'A';
|
||||||
|
digitalWrite(LED_C, LOW);
|
||||||
|
digitalWrite(LED_A, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
digitalWrite(LED_USER, HIGH); // Turn LED on
|
||||||
|
delay(500); // Keep it on 0.5s
|
||||||
|
digitalWrite(LED_USER, LOW); // Turn LED off
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button > 0) {
|
||||||
|
sht.read();
|
||||||
|
Serial.print(sht.getTemperature(), 1);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.println(sht.getHumidity(), 1);
|
||||||
|
// Debounce delay to avoid multiple triggers
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---- PRINT NUMBER EVERY SECOND ----
|
||||||
|
if (millis() - lastPrint >= 1000) {
|
||||||
|
lastPrint = millis();
|
||||||
|
counter++;
|
||||||
|
Serial.printf("Loop counter: %lu\n", counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user