handle and configure a serial device

This commit is contained in:
andreas 2021-11-02 21:18:11 +01:00
parent 64dd637d9d
commit 301783ae40
6 changed files with 209 additions and 81 deletions

View File

@ -31,8 +31,9 @@ String GwConfigHandler::toString() const{
String GwConfigHandler::toJson() const{ String GwConfigHandler::toJson() const{
String rt; String rt;
DynamicJsonDocument jdoc(400); int num=getNumConfig();
for (int i=0;i<getNumConfig();i++){ DynamicJsonDocument jdoc(JSON_OBJECT_SIZE(num*2));
for (int i=0;i<num;i++){
jdoc[configs[i]->getName()]=configs[i]->asCString(); jdoc[configs[i]->getName()]=configs[i]->asCString();
} }
serializeJson(jdoc,rt); serializeJson(jdoc,rt);
@ -98,18 +99,18 @@ bool GwConfigHandler::reset(bool save){
if (!save) return true; if (!save) return true;
return saveConfig(); return saveConfig();
} }
String GwConfigHandler::getString(const String name) const{ String GwConfigHandler::getString(const String name, String defaultv) const{
GwConfigInterface *i=getConfigItem(name,false); GwConfigInterface *i=getConfigItem(name,false);
if (!i) return String(); if (!i) return defaultv;
return i->asString(); return i->asString();
} }
bool GwConfigHandler::getBool(const String name) const{ bool GwConfigHandler::getBool(const String name, bool defaultv) const{
GwConfigInterface *i=getConfigItem(name,false); GwConfigInterface *i=getConfigItem(name,false);
if (!i) return false; if (!i) return defaultv;
return i->asBoolean(); return i->asBoolean();
} }
int GwConfigHandler::getInt(const String name) const{ int GwConfigHandler::getInt(const String name,int defaultv) const{
GwConfigInterface *i=getConfigItem(name,false); GwConfigInterface *i=getConfigItem(name,false);
if (!i) return 0; if (!i) return defaultv;
return i->asInt(); return i->asInt();
} }

View File

@ -21,9 +21,9 @@ class GwConfigHandler: public GwConfigDefinitions{
bool reset(bool save); bool reset(bool save);
String toString() const; String toString() const;
String toJson() const; String toJson() const;
String getString(const String name) const; String getString(const String name,const String defaultv="") const;
bool getBool(const String name) const ; bool getBool(const String name,bool defaultv=false) const ;
int getInt(const String name) const; int getInt(const String name,int defaultv=0) const;
GwConfigItem * findConfig(const String name, bool dummy=false); GwConfigItem * findConfig(const String name, bool dummy=false);
GwConfigInterface * getConfigItem(const String name, bool dummy=false) const; GwConfigInterface * getConfigItem(const String name, bool dummy=false) const;
private: private:

View File

@ -13,10 +13,16 @@
*/ */
#ifndef _GWHARDWARE_H #ifndef _GWHARDWARE_H
#define _GWHARDWARE_H #define _GWHARDWARE_H
//SERIAL_MODE can be: UNI (RX or TX only), BI (both), RX, TX
//board specific pins //board specific pins
#ifdef BOARD_M5ATOM #ifdef BOARD_M5ATOM
#define ESP32_CAN_TX_PIN GPIO_NUM_22 #define ESP32_CAN_TX_PIN GPIO_NUM_22
#define ESP32_CAN_RX_PIN GPIO_NUM_19 #define ESP32_CAN_RX_PIN GPIO_NUM_19
//if using tail485
#define GWSERIAL_TX 26
#define GWSERIAL_RX 32
#define GWSERIAL_MODE "UNI"
#elif BOARD_M5ATOM_CANUNIT #elif BOARD_M5ATOM_CANUNIT
#define ESP32_CAN_TX_PIN GPIO_NUM_26 #define ESP32_CAN_TX_PIN GPIO_NUM_26
#define ESP32_CAN_RX_PIN GPIO_NUM_32 #define ESP32_CAN_RX_PIN GPIO_NUM_32
@ -26,6 +32,8 @@
#else #else
#define ESP32_CAN_TX_PIN GPIO_NUM_5 // Set CAN TX port to 5 (Caution!!! Pin 2 before) #define ESP32_CAN_TX_PIN GPIO_NUM_5 // Set CAN TX port to 5 (Caution!!! Pin 2 before)
#define ESP32_CAN_RX_PIN GPIO_NUM_4 // Set CAN RX port to 4 #define ESP32_CAN_RX_PIN GPIO_NUM_4 // Set CAN RX port to 4
#define GWSERIAL_RX GPIO_NUM_16
#define GWSERIAL_MODE "RX"
#endif #endif
#endif #endif

View File

@ -12,7 +12,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define VERSION "0.3.1" #define VERSION "0.4.0"
// #define GW_MESSAGE_DEBUG_ENABLED // #define GW_MESSAGE_DEBUG_ENABLED
// #define FALLBACK_SERIAL // #define FALLBACK_SERIAL
@ -81,19 +81,26 @@ GwRequestQueue mainQueue(&logger,20);
GwWebServer webserver(&logger,&mainQueue,80); GwWebServer webserver(&logger,&mainQueue,80);
//configs that we need in main //configs that we need in main
GwConfigInterface *sendUsb=NULL;
GwConfigInterface *sendTCP=NULL;
GwConfigInterface *sendSeasmart=NULL;
GwConfigInterface *systemName=NULL;
GwConfigInterface *n2kFromUSB=NULL;
GwConfigInterface *n2kFromTCP=NULL;
GwSerial usbSerial(NULL, UART_NUM_0, USB_CHANNEL_ID); GwConfigInterface *sendUsb=config.getConfigItem(config.sendUsb,true);
GwConfigInterface *sendTCP=config.getConfigItem(config.sendTCP,true);
GwConfigInterface *sendSeasmart=config.getConfigItem(config.sendSeasmart,true);
GwConfigInterface *systemName=config.getConfigItem(config.systemName,true);
GwConfigInterface *n2kFromTCP=config.getConfigItem(config.tcpToN2k,true);
GwConfigInterface *n2kFromUSB=config.getConfigItem(config.usbToN2k,true);
GwConfigInterface *receiveSerial=config.getConfigItem(config.receiveSerial,true);
GwConfigInterface *sendSerial=config.getConfigItem(config.sendSerial,true);
GwConfigInterface *n2kFromSerial=config.getConfigItem(config.serialToN2k,true);
GwSerial *usbSerial = new GwSerial(NULL, UART_NUM_0, USB_CHANNEL_ID);
GwSerial *serial1=NULL;
class GwSerialLog : public GwLogWriter{ class GwSerialLog : public GwLogWriter{
public: public:
virtual ~GwSerialLog(){} virtual ~GwSerialLog(){}
virtual void write(const char *data){ virtual void write(const char *data){
usbSerial.sendToClients(data,-1); //ignore any errors usbSerial->sendToClients(data,-1); //ignore any errors
} }
}; };
@ -145,6 +152,22 @@ protected:
serializeJson(status, result); serializeJson(status, result);
} }
}; };
class CapabilitiesRequest : public GwRequestMessage{
public:
CapabilitiesRequest() : GwRequestMessage(F("application/json"),F("capabilities")){};
protected:
virtual void processRequest(){
DynamicJsonDocument json(JSON_OBJECT_SIZE(2));
#ifdef GWSERIAL_MODE
String serial(F(GWSERIAL_MODE));
#else
String serial(F("NONE"));
#endif
json["serialmode"]=serial;
serializeJson(json,result);
}
};
class ConfigRequest : public GwRequestMessage class ConfigRequest : public GwRequestMessage
{ {
public: public:
@ -236,7 +259,7 @@ void setup() {
#ifdef FALLBACK_SERIAL #ifdef FALLBACK_SERIAL
int st=-1; int st=-1;
#else #else
int st=usbSerial.setup(baud,3,1); //TODO: PIN defines int st=usbSerial->setup(baud,3,1); //TODO: PIN defines
#endif #endif
if (st < 0){ if (st < 0){
//falling back to old style serial for logging //falling back to old style serial for logging
@ -251,21 +274,48 @@ void setup() {
logger.logDebug(GwLog::LOG,"created GwSerial for USB port"); logger.logDebug(GwLog::LOG,"created GwSerial for USB port");
} }
logger.logDebug(GwLog::LOG,"config: %s", config.toString().c_str()); logger.logDebug(GwLog::LOG,"config: %s", config.toString().c_str());
sendUsb=config.getConfigItem(config.sendUsb,true); #ifdef GWSERIAL_MODE
sendTCP=config.getConfigItem(config.sendTCP,true); int serialrx=UART_PIN_NO_CHANGE;
sendSeasmart=config.getConfigItem(config.sendSeasmart,true); int serialtx=UART_PIN_NO_CHANGE;
systemName=config.getConfigItem(config.systemName,true); #ifdef GWSERIAL_TX
n2kFromTCP=config.getConfigItem(config.tcpToN2k,true); serialtx=GWSERIAL_TX;
n2kFromUSB=config.getConfigItem(config.usbToN2k,true); #endif
#ifdef GWSERIAL_RX
serialrx=GWSERIAL_RX;
#endif
String serialDirection=config.getString(config.serialDirection);
//we only consider the direction if mode is UNI
String serialMode(F(GWSERIAL_MODE));
if (serialMode != String("UNI")){
serialDirection=String("");
}
if (serialDirection == "receive" || serialDirection == "off") serialtx=UART_PIN_NO_CHANGE;
if (serialDirection == "send" || serialDirection == "off") serialrx=UART_PIN_NO_CHANGE;
logger.logDebug(GwLog::DEBUG,"serial set up: mode=%s,direction=%s,rx=%d,tx=%d",
serialMode.c_str(),serialDirection.c_str(),serialrx,serialtx
);
if (serialtx != UART_PIN_NO_CHANGE || serialrx != UART_PIN_NO_CHANGE){
logger.logDebug(GwLog::LOG,"creating serial interface rx=%d, tx=%d",serialrx,serialtx);
serial1=new GwSerial(&logger,UART_NUM_1,SERIAL1_CHANNEL_ID,true);
}
if (serial1){
serial1->setup(config.getInt(config.serialBaud,115200),serialrx,serialtx);
}
#endif
MDNS.begin(config.getConfigItem(config.systemName)->asCString()); MDNS.begin(config.getConfigItem(config.systemName)->asCString());
gwWifi.setup(); gwWifi.setup();
// Start TCP server // Start TCP server
socketServer.begin(); socketServer.begin();
usbSerial->flush();
webserver.registerMainHandler("/api/reset", [](AsyncWebServerRequest *request)->GwRequestMessage *{ webserver.registerMainHandler("/api/reset", [](AsyncWebServerRequest *request)->GwRequestMessage *{
return new ResetRequest(); return new ResetRequest();
}); });
webserver.registerMainHandler("/api/capabilities", [](AsyncWebServerRequest *request)->GwRequestMessage *{
return new CapabilitiesRequest();
});
webserver.registerMainHandler("/api/status", [](AsyncWebServerRequest *request)->GwRequestMessage * webserver.registerMainHandler("/api/status", [](AsyncWebServerRequest *request)->GwRequestMessage *
{ return new StatusRequest(); }); { return new StatusRequest(); });
webserver.registerMainHandler("/api/config", [](AsyncWebServerRequest *request)->GwRequestMessage * webserver.registerMainHandler("/api/config", [](AsyncWebServerRequest *request)->GwRequestMessage *
@ -328,7 +378,7 @@ void setup() {
preferences.end(); preferences.end();
logger.logDebug(GwLog::LOG,"NodeAddress=%d", NodeAddress); logger.logDebug(GwLog::LOG,"NodeAddress=%d", NodeAddress);
usbSerial.flush(); usbSerial->flush();
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress); NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
NMEA2000.SetForwardOwnMessages(false); NMEA2000.SetForwardOwnMessages(false);
// Set the information for other bus devices, which messages we support // Set the information for other bus devices, which messages we support
@ -337,7 +387,7 @@ void setup() {
unsigned long *op=pgns; unsigned long *op=pgns;
while (*op != 0){ while (*op != 0){
logger.logDebug(GwLog::DEBUG,"add transmit pgn %ld",(long)(*op)); logger.logDebug(GwLog::DEBUG,"add transmit pgn %ld",(long)(*op));
usbSerial.flush(); usbSerial->flush();
op++; op++;
} }
} }
@ -368,7 +418,10 @@ void sendBufferToChannels(const char * buffer, int sourceId){
socketServer.sendToClients(buffer,sourceId); socketServer.sendToClients(buffer,sourceId);
} }
if (sendUsb->asBoolean()){ if (sendUsb->asBoolean()){
usbSerial.sendToClients(buffer,sourceId); usbSerial->sendToClients(buffer,sourceId);
}
if (sendSerial->asBoolean() && serial1){
serial1->sendToClients(buffer,sourceId);
} }
} }
@ -388,7 +441,8 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) {
void handleReceivedNmeaMessage(const char *buf, int sourceId){ void handleReceivedNmeaMessage(const char *buf, int sourceId){
if ((sourceId == USB_CHANNEL_ID && n2kFromUSB->asBoolean())|| if ((sourceId == USB_CHANNEL_ID && n2kFromUSB->asBoolean())||
(sourceId >= MIN_TCP_CHANNEL_ID && n2kFromTCP->asBoolean()) (sourceId >= MIN_TCP_CHANNEL_ID && n2kFromTCP->asBoolean())||
(sourceId == SERIAL1_CHANNEL_ID && n2kFromSerial)
) )
toN2KConverter->parseAndSend(buf,sourceId); toN2KConverter->parseAndSend(buf,sourceId);
sendBufferToChannels(buf,sourceId); sendBufferToChannels(buf,sourceId);
@ -396,7 +450,8 @@ void handleReceivedNmeaMessage(const char *buf, int sourceId){
void handleSendAndRead(bool handleRead){ void handleSendAndRead(bool handleRead){
socketServer.loop(handleRead); socketServer.loop(handleRead);
usbSerial.loop(handleRead); usbSerial->loop(handleRead);
if (serial1) serial1->loop(handleRead);
} }
class NMEAMessageReceiver : public GwBufferWriter{ class NMEAMessageReceiver : public GwBufferWriter{
uint8_t buffer[GwBuffer::RX_BUFFER_SIZE+4]; uint8_t buffer[GwBuffer::RX_BUFFER_SIZE+4];
@ -468,7 +523,9 @@ void loop() {
//read channels //read channels
socketServer.readMessages(&receiver); socketServer.readMessages(&receiver);
receiver.id=USB_CHANNEL_ID; receiver.id=USB_CHANNEL_ID;
usbSerial.readMessages(&receiver); usbSerial->readMessages(&receiver);
receiver.id=SERIAL1_CHANNEL_ID;
if (serial1) serial1->readMessages(&receiver);
//handle message requests //handle message requests
GwMessage *msg=mainQueue.fetchMessage(0); GwMessage *msg=mainQueue.fetchMessage(0);

View File

@ -36,6 +36,48 @@
"default": "true", "default": "true",
"description": "convert NMEA0183 from the USB port to NMEA2000" "description": "convert NMEA0183 from the USB port to NMEA2000"
}, },
{
"name": "serialDirection",
"label": "serial direction",
"type": "list",
"default": "receive",
"list": ["send","receive","off"],
"description": "use the serial port to send or receive data",
"capabilities":{"serialmode":["UNI"]}
},
{
"name": "serialBaud",
"label": "serial baud rate",
"type": "list",
"default": "115200",
"description": "baud rate for the serial port",
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
"capabilities":{"serialmode":["RX","TX","UNI","BI"]}
},
{
"name": "sendSerial",
"label": "NMEA to Serial",
"type": "boolean",
"default": "true",
"description": "send out NMEA data on the serial port",
"capabilities":{"serialmode":["TX","BI"]}
},
{
"name": "receiveSerial",
"label": "NMEA from Serial",
"type": "boolean",
"default": "true",
"description": "receive NMEA data on the serial port",
"capabilities":{"serialmode":["RX","BI"]}
},
{
"name": "serialToN2k",
"label": "serial to NMEA2000",
"type": "boolean",
"default": "true",
"description": "convert NMEA0183 from the serial port to NMEA2000",
"capabilities":{"serialmode":["RX","BI","UNI"]}
},
{ {
"name": "serverPort", "name": "serverPort",
"label": "TCP port", "label": "TCP port",
@ -60,14 +102,14 @@
}, },
{ {
"name": "readTCP", "name": "readTCP",
"label": "TCP to NMEA2000", "label": "NMEA from TCP",
"type": "boolean", "type": "boolean",
"default": "true", "default": "true",
"description": "receive NMEA data from connected TCP clients" "description": "receive NMEA data from connected TCP clients"
}, },
{ {
"name": "tcpToN2k", "name": "tcpToN2k",
"label": "NMEA from TCP", "label": "TCP to NMEA2000",
"type": "boolean", "type": "boolean",
"default": "true", "default": "true",
"description": "convert NMEA0183 from TCP clients to NMEA2000" "description": "convert NMEA0183 from TCP clients to NMEA2000"

View File

@ -7,7 +7,9 @@
<script type="text/javascript"> <script type="text/javascript">
let self=this; let self=this;
let lastUpdate=(new Date()).getTime(); let lastUpdate=(new Date()).getTime();
let reloadConfig=false;
function alertRestart(){ function alertRestart(){
reloadConfig=true;
alert("Board reset triggered, reconnect WLAN if necessary"); alert("Board reset triggered, reconnect WLAN if necessary");
} }
function getJson(url){ function getJson(url){
@ -41,6 +43,10 @@
} }
} }
lastUpdate=(new Date()).getTime(); lastUpdate=(new Date()).getTime();
if (reloadConfig){
reloadConfig=false;
resetForm();
}
}) })
} }
function resetForm(ev){ function resetForm(ev){
@ -181,6 +187,8 @@
} }
let configDefinitions; let configDefinitions;
function loadConfigDefinitions() { function loadConfigDefinitions() {
getJson("api/capabilities")
.then(function (capabilities) {
getJson("config.json") getJson("config.json")
.then(function (defs) { .then(function (defs) {
let frame = document.querySelector('.configFormRows'); let frame = document.querySelector('.configFormRows');
@ -189,6 +197,17 @@
configDefinitions = defs; configDefinitions = defs;
defs.forEach(function (item) { defs.forEach(function (item) {
if (!item.type) return; if (!item.type) return;
if (item.capabilities !== undefined){
for (let capability in item.capabilities){
let values=item.capabilities[capability];
if ( !capabilities[capability]) return;
let found =false;
values.forEach(function(v){
if (capabilities[capability] == v) found=true;
});
if (! found) return;
}
}
let row = document.createElement('div'); let row = document.createElement('div');
row.classList.add('row'); row.classList.add('row');
let label = item.label || item.name; let label = item.label || item.name;
@ -225,6 +244,7 @@
}) })
resetForm(); resetForm();
}) })
})
.catch(function (err) { alert("unable to load config: " + err) }) .catch(function (err) { alert("unable to load config: " + err) })
} }
window.setInterval(update,1000); window.setInterval(update,1000);