Some more improvements
This commit is contained in:
199
src/main.cpp
199
src/main.cpp
@@ -45,6 +45,7 @@ bool ap_enabled = true;
|
||||
unsigned long firstStart = 0;
|
||||
unsigned long lastSensor = 0;
|
||||
unsigned long lastPrint = 0;
|
||||
unsigned long lastRefresh = 0;
|
||||
|
||||
unsigned long env_interval = 2000;
|
||||
|
||||
@@ -74,13 +75,79 @@ float hum = 0.0;
|
||||
uint8_t nodeid; // NMEA2000 id on bus
|
||||
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
|
||||
tN2kDeviceList *pN2kDeviceList;
|
||||
uint8_t n2k_id[3] = { 254, 254, 254 }; // aktuelle IDs für dest A, B, C
|
||||
uint8_t n2k_id[3] = { 254, 254, 254 }; // destination ids; 254 = undef.
|
||||
uint64_t n2k_name[3] = { 0, 0, 0 }; // destination names
|
||||
uint8_t switchbank[3] = { 0, 0, 0 }; // switch bank of destionation
|
||||
|
||||
String processor(const String& var) {
|
||||
// dummy for now
|
||||
return "";
|
||||
}
|
||||
|
||||
uint64_t config_to_n2kname(const String &cfgval) {
|
||||
if (cfgval == "all") {
|
||||
LOGD(TAG, "n2kname: Broadcast");
|
||||
return NAME_BROADCAST;
|
||||
}
|
||||
if (cfgval == "none") {
|
||||
LOGD(TAG, "n2kname: None");
|
||||
return NAME_NONE;
|
||||
}
|
||||
// parse as hex string
|
||||
LOGD(TAG, "n2kname: %s", cfgval.c_str());
|
||||
return strtoull(cfgval.c_str(), nullptr, 16);
|
||||
}
|
||||
|
||||
void refresh_n2k_ids() {
|
||||
|
||||
// Debug
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
char hex_name[17];
|
||||
snprintf(hex_name, sizeof(hex_name), "%08X%08X",
|
||||
(uint32_t)(n2k_name[i] >> 32), (uint32_t)(n2k_name[i] & 0xFFFFFFFF));
|
||||
LOGD(TAG, "Dest %d: name=%s", i, hex_name);
|
||||
}
|
||||
|
||||
if (!pN2kDeviceList->ReadResetIsListUpdated()) {
|
||||
// no changes, nothing to do
|
||||
return;
|
||||
}
|
||||
LOGD(TAG, "refreshing NMEA2000 device ids");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (n2k_name[i] == NAME_BROADCAST) {
|
||||
n2k_id[i] = 255;
|
||||
} else {
|
||||
n2k_id[i] = 254;
|
||||
}
|
||||
}
|
||||
uint8_t hits = 0;
|
||||
for (int i = 0; i <= 252; i++) {
|
||||
const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i);
|
||||
if (d == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (d->GetName() == n2k_name[j] && n2k_id[j] == 254) {
|
||||
n2k_id[j] = i;
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
if (hits == 3) {
|
||||
// all found no need to look further
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Debug
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
char hex_name[17];
|
||||
snprintf(hex_name, sizeof(hex_name), "%08X%08X",
|
||||
(uint32_t)(n2k_name[i] >> 32), (uint32_t)(n2k_name[i] & 0xFFFFFFFF));
|
||||
LOGD(TAG, "Dest %d: name=%s, id=%d", i, hex_name, n2k_id[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TaskHandle_t ledTaskHandle = NULL;
|
||||
TaskHandle_t sensorTaskHandle = NULL;
|
||||
TaskHandle_t keyTaskHandle = NULL;
|
||||
@@ -178,8 +245,10 @@ void cpuFreqTimerCallback(TimerHandle_t xTimer) {
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10); // verhindert Booten ohne USB-Verbindung
|
||||
delay(500);
|
||||
unsigned long start = millis();
|
||||
while (!Serial && millis() - start < 3000) {
|
||||
delay(10);
|
||||
}
|
||||
|
||||
// Configure I/O pins
|
||||
|
||||
@@ -213,6 +282,9 @@ void setup() {
|
||||
pinMode(KEY_6, INPUT_PULLUP);
|
||||
pinMode(KEY_DST, INPUT_PULLUP);
|
||||
|
||||
// Light sensor input
|
||||
pinMode(LDR, INPUT);
|
||||
|
||||
// Early signal system activity, red while booting
|
||||
digitalWrite(RGBLED_R, HIGH);
|
||||
digitalWrite(RGBLED_G, LOW);
|
||||
@@ -247,6 +319,10 @@ void setup() {
|
||||
longcode[4] = config.getByte("key5long");
|
||||
longcode[5] = config.getByte("key6long");
|
||||
|
||||
switchbank[0] = config.getByte("switchBankA");
|
||||
switchbank[1] = config.getByte("switchBankB");
|
||||
switchbank[2] = config.getByte("switchBankC");
|
||||
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
|
||||
LOGI(TAG, "Wake up by key");
|
||||
@@ -300,13 +376,9 @@ void setup() {
|
||||
// NMEA2000 configuration
|
||||
|
||||
// Destinations setup, refresh in loop later
|
||||
if (config.getString("n2kDestA") == "all") {
|
||||
// broadcast
|
||||
} else if (config.getString("n2kDestA") == "none") {
|
||||
// disabled
|
||||
} else {
|
||||
// NAME
|
||||
}
|
||||
n2k_name[0] = config_to_n2kname(config.getString("n2kDestA"));
|
||||
n2k_name[1] = config_to_n2kname(config.getString("n2kDestB"));
|
||||
n2k_name[2] = config_to_n2kname(config.getString("n2kDestC"));
|
||||
|
||||
NMEA2000.SetN2kCANMsgBufSize(8);
|
||||
NMEA2000.SetN2kCANReceiveFrameBufSize(250);
|
||||
@@ -330,14 +402,15 @@ void setup() {
|
||||
|
||||
uint32_t uid; // ISO 21bit identity number devived from chipid (MAC)
|
||||
uid = ((chipid >> 32) ^ (chipid & 0xFFFFFFFF)) & 0x1FFFFF;
|
||||
// TODO Device unique id stored in preferences
|
||||
NMEA2000.SetDeviceInformation(uid, // Unique number. Use e.g. Serial number.
|
||||
130, // Device function=Button Interface (or 190?)
|
||||
110, // Device class=Human Interface? (or 140?)
|
||||
2046, // Manufacturer code (custom OBP)
|
||||
4 // Industrygoup=Marine
|
||||
NMEA2000.SetDeviceInformation(uid, // Unique number. Use e.g. Serial number.
|
||||
N2K_DEVFUNCT,
|
||||
N2K_DEVCLASS,
|
||||
N2K_MANUFACTURERCODE,
|
||||
N2K_INDUSTRYGROUP
|
||||
);
|
||||
|
||||
uint8_t devinst = config.getByte("n2kDevInst");
|
||||
// devinst lower, devinst upper, sysinst
|
||||
NMEA2000.SetDeviceInformationInstances(devinst & 0x07, devinst & 0xf8 >> 3, config.getByte("n2kSysInst"));
|
||||
|
||||
// Debug Start
|
||||
// NMEA2000.SetForwardStream(&Serial);
|
||||
@@ -349,7 +422,7 @@ void setup() {
|
||||
//TODO: N2km_NodeOnly N2km_ListenAndNode?
|
||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, nodeid);
|
||||
NMEA2000.SetForwardOwnMessages(false);
|
||||
NMEA2000.SetHeartbeatIntervalAndOffset(NMEA2000_HEARTBEAT_INTERVAL);
|
||||
NMEA2000.SetHeartbeatIntervalAndOffset(N2K_HEARTBEAT_INTERVAL);
|
||||
|
||||
// Features?
|
||||
// 130311 environment
|
||||
@@ -454,22 +527,29 @@ void setup() {
|
||||
xTimerStart(stopApTimer, 0);
|
||||
}
|
||||
|
||||
refresh_n2k_ids(); // hopefully some devices already detected
|
||||
}
|
||||
|
||||
void shortBeep() {
|
||||
ledcWriteTone(LEDC_BUZZER, 2500);
|
||||
delay(15);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
if (audiomode == 'D') {
|
||||
return;
|
||||
}
|
||||
ledcWriteTone(LEDC_BUZZER, 2500);
|
||||
delay(30);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
}
|
||||
|
||||
void atariKeyclick() {
|
||||
ledcWriteTone(LEDC_BUZZER, 3200);
|
||||
delayMicroseconds(3000);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
delayMicroseconds(800);
|
||||
ledcWriteTone(LEDC_BUZZER, 3200);
|
||||
delayMicroseconds(2000);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
if (audiomode == 'D') {
|
||||
return;
|
||||
}
|
||||
ledcWriteTone(LEDC_BUZZER, 3200);
|
||||
delayMicroseconds(3000);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
delayMicroseconds(800);
|
||||
ledcWriteTone(LEDC_BUZZER, 3200);
|
||||
delayMicroseconds(2000);
|
||||
ledcWriteTone(LEDC_BUZZER, 0);
|
||||
}
|
||||
|
||||
void print_n2k_devicelist() {
|
||||
@@ -506,22 +586,23 @@ void print_n2k_devicelist() {
|
||||
Serial.println("------------------------------");
|
||||
}
|
||||
|
||||
// rename to: void sendSwitchBank()
|
||||
// later: void send_switchbank(uint8_t keycode, uint8_t dest_id) {
|
||||
void send_switchbank(uint8_t keycode) {
|
||||
void send_switchbank(uint8_t keycode, uint8_t bank_id, uint8_t dest_id) {
|
||||
// Seems there is no destination possible for 127502?
|
||||
//
|
||||
if (dest_id == 254) {
|
||||
LOGW(TAG, "nothing sent: destination undefined (254)");
|
||||
return;
|
||||
}
|
||||
tN2kMsg N2kMsg;
|
||||
tN2kBinaryStatus bankstatus;
|
||||
N2kResetBinaryStatus(bankstatus);
|
||||
N2kSetStatusBinaryOnStatus(bankstatus, N2kOnOff_On, keycode);
|
||||
|
||||
// TODO
|
||||
// Needs filled N2K device list to map NAME to current address
|
||||
// N2kMsg.Destination = deviceAddress;
|
||||
//
|
||||
SetN2kPGN127502(N2kMsg, 0, bankstatus);
|
||||
SetN2kPGN127502(N2kMsg, bank_id, bankstatus);
|
||||
if (dest_id != 255) {
|
||||
N2kMsg.Destination = dest_id;
|
||||
}
|
||||
NMEA2000.SendMsg(N2kMsg);
|
||||
|
||||
LOGI(TAG, "PGN127502 sent: Switch=%d", keycode);
|
||||
LOGI(TAG, "PGN127502 sent: switch #%d to device #%d", keycode, dest_id);
|
||||
}
|
||||
|
||||
void send_sensor_temphum(float temp_k, float hum_perc) {
|
||||
@@ -538,6 +619,25 @@ void send_sensor_temphum(float temp_k, float hum_perc) {
|
||||
SID = (SID + 1) % 256;
|
||||
}
|
||||
|
||||
void send_sensor_brightness(uint16_t value) {
|
||||
// value range 0..4095 from LDR
|
||||
// proprietary PGN 65280
|
||||
// device instance 8bits
|
||||
// brightness 0-100%, resolution 0.1% 16bits
|
||||
// 3 bytes reserved
|
||||
tN2kMsg N2kMsg;
|
||||
N2kMsg.SetPGN(65280); // proprietary PGN
|
||||
N2kMsg.Priority = 6;
|
||||
// 11bits manuf.-code, 2bits reserved (1), 3bits industry group
|
||||
N2kMsg.Add2ByteUInt((N2K_MANUFACTURERCODE & 0x7FF) | (0x03 << 11) | ((N2K_INDUSTRYGROUP & 0x7) << 13));
|
||||
N2kMsg.AddByte(0); // instance not yet used now
|
||||
N2kMsg.Add2ByteUInt(value * 1000UL / 4095); // resolution 0.1
|
||||
N2kMsg.AddByte(0xFF); //reserved bytes
|
||||
N2kMsg.AddByte(0xFF);
|
||||
N2kMsg.AddByte(0xFF);
|
||||
NMEA2000.SendMsg(N2kMsg);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
ButtonEvent event;
|
||||
@@ -545,6 +645,7 @@ void loop() {
|
||||
if (event.buttonId == BUTTON_DST) {
|
||||
// destination / mode button
|
||||
if (event.pressType == ButtonPressType::SHORT) {
|
||||
atariKeyclick();
|
||||
if (mode == 'N') {
|
||||
// switch destination only in normal mode
|
||||
if (destination == 'A') {
|
||||
@@ -581,10 +682,12 @@ void loop() {
|
||||
if (mode == 'N') {
|
||||
// Send key code to destination
|
||||
atariKeyclick();
|
||||
uint8_t index = destination - 'A';
|
||||
if ((event.pressType == ButtonPressType::SHORT)) {
|
||||
send_switchbank(keycode[event.buttonId]);
|
||||
LOGI(TAG, "Send key %d: dst index = %d", keycode[event.buttonId], index);
|
||||
send_switchbank(keycode[event.buttonId], switchbank[index], n2k_id[index]);
|
||||
} else if ((event.pressType == ButtonPressType::MEDIUM)) {
|
||||
send_switchbank(longcode[event.buttonId]);
|
||||
send_switchbank(longcode[event.buttonId], switchbank[index], n2k_id[index]);
|
||||
}
|
||||
// Debug:
|
||||
if ((event.buttonId == BUTTON_1)
|
||||
@@ -654,6 +757,12 @@ void loop() {
|
||||
// NMEA2000.loop(); // not implemented yet
|
||||
NMEA2000.ParseMessages();
|
||||
|
||||
if (millis() - lastRefresh >= 30000) {
|
||||
// look every 30 seconds for changed devices
|
||||
lastRefresh = millis();
|
||||
refresh_n2k_ids();
|
||||
}
|
||||
|
||||
if ((millis() - lastSensor >= env_interval) and sht_available) {
|
||||
lastSensor = millis();
|
||||
sht.read();
|
||||
@@ -662,6 +771,14 @@ void loop() {
|
||||
|
||||
// Send environment data to NMEA2000
|
||||
send_sensor_temphum(temp + 273.15, hum);
|
||||
|
||||
#ifdef HARDWARE_V2
|
||||
int ldrval = analogRead(LDR);
|
||||
LOGI(TAG, "LDR value =%d", ldrval);
|
||||
// TODO send brightness to NMEA2000
|
||||
//send_sensor_brightness(ldrval);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
delay(1); // 1ms for FreeRTOS
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
static const char* TAG = "WEB";
|
||||
|
||||
AsyncWebServer server(80);
|
||||
bool updateSuccess = false;
|
||||
String updateError = "";
|
||||
|
||||
class EmbeddedFile;
|
||||
static std::map<String, EmbeddedFile*> embeddedFiles;
|
||||
@@ -96,7 +98,9 @@ void webserver_init() {
|
||||
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
LOGD(TAG, "checkpass called");
|
||||
StaticJsonDocument<100> doc;
|
||||
doc["status"] = "FAILED";
|
||||
// TODO _hash überprüfen!
|
||||
// LOGD(TAG, "check hash: %s", hash);
|
||||
doc["status"] = "OK";
|
||||
String out;
|
||||
serializeJson(doc, out);
|
||||
request->send(200, "application/json", out);
|
||||
@@ -112,7 +116,6 @@ void webserver_init() {
|
||||
doc["instDesc2"] = config.getString("instDesc2");
|
||||
doc["logLevel"] = loglevel;
|
||||
doc["version"] = VERSION;
|
||||
doc["fwtype"] = "unknown"; // TODO ?
|
||||
doc["salt"] = "secret";
|
||||
doc["AdminPassword"] = "********";
|
||||
doc["useAdminPass"] = config.getBool("useAdminPass") ? "true" : "false";
|
||||
@@ -128,7 +131,6 @@ void webserver_init() {
|
||||
doc["rgbBrightness"] = config.getShort("rgbBrightness");
|
||||
doc["buzEnable"] = config.getBool("buzEnable") ? "true" : "false";
|
||||
doc["buzPower"] = config.getByte("buzPower");
|
||||
doc["switchBank"] = config.getByte("switchBank");
|
||||
doc["key1"] = keycode[BUTTON_1];
|
||||
doc["key2"] = keycode[BUTTON_2];
|
||||
doc["key3"] = keycode[BUTTON_3];
|
||||
@@ -144,8 +146,11 @@ void webserver_init() {
|
||||
doc["n2kSysInst"] = config.getByte("n2kSysInst");
|
||||
doc["n2kDevInst"] = config.getByte("n2kDevInst");
|
||||
doc["n2kDestA"] = config.getString("n2kDestA");
|
||||
doc["switchBankA"] = config.getByte("switchBankA");
|
||||
doc["n2kDestB"] = config.getString("n2kDestB");
|
||||
doc["switchBankB"] = config.getByte("switchBankB");
|
||||
doc["n2kDestC"] = config.getString("n2kDestC");
|
||||
doc["switchBankC"] = config.getByte("switchBankC");
|
||||
doc["envInterval"] = config.getShort("envInterval");
|
||||
String out;
|
||||
serializeJson(doc, out);
|
||||
@@ -180,7 +185,9 @@ void webserver_init() {
|
||||
doc["cpuspeed"] = String(cpu_freq) + "MHz";
|
||||
char ssid[13];
|
||||
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
||||
doc["chipid"] = String(ssid);
|
||||
doc["ssid"] = ssid;
|
||||
doc["fwtype"] = FIRMWARE_TYPE; // TODO ?
|
||||
doc["chipid"] = CONFIG_IDF_FIRMWARE_CHIP_ID; // IDF chipid NOT device!
|
||||
doc["uptime"] = uptime_with_unit();
|
||||
doc["heap"]=(long)xPortGetFreeHeapSize();
|
||||
doc["temp"] = String(temp, 1);
|
||||
@@ -260,10 +267,20 @@ void webserver_init() {
|
||||
// create the response, add header, and send response
|
||||
LOGD(TAG, "update called");
|
||||
StaticJsonDocument<100> doc;
|
||||
doc["status"] = "FAILED";
|
||||
if (updateSuccess) {
|
||||
doc["status"] = "OK";
|
||||
doc["message"] = "Update sucessfull, rebooting...";
|
||||
} else {
|
||||
doc["status"] = "FAILED";
|
||||
doc["message"] = updateError;
|
||||
}
|
||||
String out;
|
||||
serializeJson(doc, out);
|
||||
request->send(200, "application/json", out);
|
||||
if (updateSuccess) {
|
||||
delay(100); // Ensure response is sent
|
||||
ESP.restart();
|
||||
}
|
||||
}, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
// this is the new image upload part
|
||||
Serial.print("Retrieving firmware image named: ");
|
||||
@@ -272,14 +289,19 @@ void webserver_init() {
|
||||
if (index == 0) {
|
||||
if (! Update.begin(UPDATE_SIZE_UNKNOWN)) {
|
||||
Update.printError(Serial);
|
||||
updateError = "Update.begin() failed";
|
||||
}
|
||||
}
|
||||
if (Update.write(data, len) != len) {
|
||||
Update.printError(Serial);
|
||||
updateError = "Update.write() failed";
|
||||
}
|
||||
if (final) {
|
||||
if (!Update.end(true)) {
|
||||
if (Update.end(true)) {
|
||||
updateSuccess = true;
|
||||
} else {
|
||||
Update.printError(Serial);
|
||||
updateError = "Update.end() failed";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user