diff --git a/ax25_payload.cpp b/ax25_payload.cpp index 79c50bc..b18d42d 100644 --- a/ax25_payload.cpp +++ b/ax25_payload.cpp @@ -16,16 +16,14 @@ Payload::Payload(const String &textPayload) void Payload::Dump() { - Serial.println(); - Serial.print("valid: "); Serial.println(isValid_); - Serial.println("src: " + srcCall_.ToString()); - Serial.println("dst: " + dstCall_.ToString()); - Serial.print("rpt: "); + LOG_INFO("valid: ", isValid_); + LOG_INFO("src: ", srcCall_.ToString()); + LOG_INFO("dst: ", dstCall_.ToString()); + LOG_INFO("rpt: "); for (int i = 0; i < rptCallsCount_; i++) { - Serial.print(rptCalls_[i].ToString() + " "); + LOG_INFO(rptCalls_[i].ToString()); } - Serial.println(); - Serial.println("info: " + info_); + LOG_INFO("info: ", info_); } int Payload::ToBinary(byte *txPayload, int bufferLength) const diff --git a/ax25_payload.h b/ax25_payload.h index 0b90bd8..80659bf 100644 --- a/ax25_payload.h +++ b/ax25_payload.h @@ -2,6 +2,7 @@ #define AX25_PAYLOAD_H #include +#include #include "ax25_callsign.h" diff --git a/ble_serial.cpp b/ble_serial.cpp index 404efc9..7dc9f94 100644 --- a/ble_serial.cpp +++ b/ble_serial.cpp @@ -25,7 +25,7 @@ class BLESerialServerCallbacks: public BLEServerCallbacks { void onDisconnect(BLEServer* pServer) { pServer->startAdvertising(); // restart advertising - Serial.println("Started advertising"); + LOG_INFO("Started advertising"); } }; @@ -98,12 +98,12 @@ bool BLESerial::begin(const char* localName) // Start the service pService->start(); - Serial.println("starting service"); + LOG_INFO("starting service"); // Start advertising pServer->getAdvertising()->addServiceUUID(pService->getUUID()); pServer->getAdvertising()->start(); - Serial.println("Waiting a client connection to notify..."); + LOG_INFO("Waiting a client connection to notify..."); return true; } diff --git a/ble_serial.h b/ble_serial.h index 3e65135..beee672 100644 --- a/ble_serial.h +++ b/ble_serial.h @@ -21,6 +21,7 @@ #include #include #include +#include #define SERVICE_UUID "00000001-ba2a-46c9-ae49-01b0961f68bb" // KISS service UUID #define CHARACTERISTIC_UUID_TX "00000003-ba2a-46c9-ae49-01b0961f68bb" diff --git a/config.h b/config.h index 4897161..1d30043 100644 --- a/config.h +++ b/config.h @@ -46,6 +46,14 @@ #define CFG_BT_NAME "loraprs" #define CFG_BT_USE_BLE false // set to true to use bluetooth low energy (for ios devices) +// USB +#define CFG_USB_SERIAL_ENABLE false // true - enable communication over USB Serial +#if CFG_USB_SERIAL_ENABLE == true +#define DEBUGLOG_DISABLE_LOG // logging must be disabled when using USB mode +#undef CFG_BT_NAME +#define CFG_BT_NAME "" +#endif + // KISS protocol options #define CFG_KISS_EXTENSIONS false // true - enable modem control from application with KISS commands #define CFG_KISS_TCP_IP false // true - run as KISS TCP/IP server, no bluetooth operations performed diff --git a/esp32_loraprs.ino b/esp32_loraprs.ino index 77f1937..eb7c921 100644 --- a/esp32_loraprs.ino +++ b/esp32_loraprs.ino @@ -48,6 +48,9 @@ void initializeConfig(LoraPrs::Config &cfg) { cfg.AprsRawBeacon = CFG_APRS_RAW_BKN; cfg.AprsRawBeaconPeriodMinutes = 20; + // USB + cfg.UsbSerialEnable = CFG_USB_SERIAL_ENABLE; + // bluetooth device name cfg.BtName = CFG_BT_NAME; cfg.BtEnableBle = CFG_BT_USE_BLE; diff --git a/kiss_processor.cpp b/kiss_processor.cpp index ec7a1f6..2f06606 100644 --- a/kiss_processor.cpp +++ b/kiss_processor.cpp @@ -36,12 +36,12 @@ void Processor::sendRigToSerial(Cmd cmd, const byte *packet, int packetLength) { void ICACHE_RAM_ATTR Processor::queueRigToSerialIsr(Cmd cmd, const byte *packet, int packetLength) { if (!rigToSerialQueueIndex_.unshift(packetLength)) { - Serial.println("Rig to serial queue is full!"); + LOG_WARN("Rig to serial queue is full!"); return; } for (int i = 0; i < packetLength; i++) { if (!rigToSerialQueue_.unshift(packet[i])) { - Serial.println("Rig to serial queue is full!"); + LOG_WARN("Rig to serial queue is full!"); return; } } @@ -71,7 +71,7 @@ void Processor::queueSerialToRig(Cmd cmd, const byte *packet, int packetLength) result &= serialToRigQueue_.unshift(Marker::Fend); if (!result) { - Serial.println("Serial to rig queue overflow!"); + LOG_WARN("Serial to rig queue overflow!"); } } @@ -109,7 +109,7 @@ bool Processor::processSerialToRig() if (onSerialRxHasData()) { if (onSerialRx(&rxByte)) { if (!serialToRigQueue_.unshift(rxByte)) { - Serial.println("Serial to rig buffer is full!"); + LOG_WARN("Serial to rig buffer is full!"); } } } diff --git a/kiss_processor.h b/kiss_processor.h index 02b4269..02b590b 100644 --- a/kiss_processor.h +++ b/kiss_processor.h @@ -2,6 +2,7 @@ #define KISS_PROCESSOR_H #include +#include #include #define CIRCULAR_BUFFER_INT_SAFE diff --git a/loraprs_config.h b/loraprs_config.h index 061fea0..ffe79d5 100644 --- a/loraprs_config.h +++ b/loraprs_config.h @@ -26,6 +26,9 @@ struct Config bool LoraUseIsr; // true to use interrupts, false for fallback polling, e.g. if Dio0 is not connected bool LoraUseCad; // use carrier detect before transmitting + // usb + bool UsbSerialEnable; // true - operate in USB Serial mode, debug logging is disabled + // bluetooth String BtName; // bluetooth device name for the client, set to empty string to disable bluetooth in server mode bool BtEnableBle; // bluetooth device presents as BLE rather than serial bluetooth e.g. for iOS devices diff --git a/loraprs_service.cpp b/loraprs_service.cpp index 05e71a4..08224d1 100644 --- a/loraprs_service.cpp +++ b/loraprs_service.cpp @@ -5,8 +5,11 @@ namespace LoraPrs { byte Service::rxBuf_[256]; #ifdef USE_RADIOLIB +#pragma message("Using RadioLib") bool Service::interruptEnabled_ = true; std::shared_ptr Service::radio_; +#else +#pragma message("Using arduino-LoRa") #endif Service::Service() @@ -26,17 +29,24 @@ Service::Service() void Service::setup(const Config &conf) { -#ifdef USE_RADIOLIB - Serial.println("Built with RadioLib library"); -#else - Serial.println("Built with arudino-LoRa library"); -#endif config_ = conf; previousBeaconMs_ = 0; + LOG_SET_OPTION(false, false, true); // disable file, line, enable func + + // disable logging when USB is used for data transfer + if (config_.UsbSerialEnable) { + LOG_SET_LEVEL(DebugLogLevel::LVL_NONE); + } +#ifdef USE_RADIOLIB + LOG_INFO("Built with RadioLib library"); +#else + LOG_INFO("Built with arduino-LoRa library"); +#endif + ownCallsign_ = AX25::Callsign(config_.AprsLogin); if (!ownCallsign_.IsValid()) { - Serial.println("Own callsign is not valid"); + LOG_ERROR("Own callsign", config_.AprsLogin, "is not valid"); } aprsLoginCommand_ = String("user ") + config_.AprsLogin + String(" pass ") + @@ -63,7 +73,7 @@ void Service::setup(const Config &conf) } if (config_.PttEnable) { - Serial.println("External PTT is enabled"); + LOG_INFO("External PTT is enabled"); pinMode(config_.PttPin, OUTPUT); } } @@ -71,29 +81,34 @@ void Service::setup(const Config &conf) void Service::setupWifi(const String &wifiName, const String &wifiKey) { WiFi.setHostname("loraprs"); + + // AP mode if (config_.WifiEnableAp) { - Serial.println("WIFI is running in AP mode " + wifiName); + LOG_INFO("WIFI is running in AP mode", wifiName); WiFi.softAP(wifiName.c_str(), wifiKey.c_str()); - Serial.println(WiFi.softAPIP()); + LOG_INFO("IP address:", WiFi.softAPIP()); + + // Client/STA mode } else { - Serial.print("WIFI connecting to " + wifiName); + LOG_INFO("WIFI connecting to", wifiName); WiFi.mode(WIFI_STA); WiFi.begin(wifiName.c_str(), wifiKey.c_str()); int retryCnt = 0; while (WiFi.status() != WL_CONNECTED) { delay(CfgConnRetryMs); - Serial.print("."); + LOG_WARN("WIFI retrying", retryCnt); if (retryCnt++ >= CfgConnRetryMaxTimes) { - Serial.println("failed"); + LOG_ERROR("WIFI connect failed"); return; } } - Serial.println("ok"); - Serial.println(WiFi.localIP()); + LOG_INFO("WIFI connected to", wifiName); + LOG_INFO("IP address:", WiFi.localIP()); } + // Run KISS server if enabled if (config_.KissEnableTcpIp) { - Serial.print("KISS TCP/IP server started on port "); Serial.println(CfgKissPort); + LOG_INFO("KISS TCP/IP server started on port", CfgKissPort); kissServer_->begin(); } } @@ -103,59 +118,59 @@ void Service::reconnectWifi() const // AP mode does not require re-connection if (config_.WifiEnableAp) return; - Serial.print("WIFI re-connecting..."); + LOG_WARN("WIFI re-connecting..."); int retryCnt = 0; while (WiFi.status() != WL_CONNECTED || WiFi.localIP() == IPAddress(0,0,0,0)) { WiFi.reconnect(); delay(CfgConnRetryMs); - Serial.print("."); + LOG_WARN("WIFI re-connecting", retryCnt); if (retryCnt++ >= CfgConnRetryMaxTimes) { - Serial.println("failed"); + LOG_ERROR("WIFI re-connect failed"); return; } } - Serial.println("ok"); - Serial.println(WiFi.localIP()); + LOG_INFO("WIFI reconnected, IP address", WiFi.localIP()); if (config_.KissEnableTcpIp) { + LOG_INFO("KISS TCP/IP server started on port", CfgKissPort); kissServer_->begin(); } } bool Service::reconnectAprsis() { - Serial.print("APRSIS connecting..."); + LOG_INFO("APRSIS connecting to", config_.AprsHost); if (!aprsisConn_.connect(config_.AprsHost.c_str(), config_.AprsPort)) { - Serial.println("Failed to connect to " + config_.AprsHost + ":" + config_.AprsPort); + LOG_ERROR("Failed to connect to", config_.AprsHost, ":", config_.AprsPort); return false; } - Serial.println("ok"); - + LOG_INFO("APRSIS connected"); aprsisConn_.print(aprsLoginCommand_); + LOG_INFO("APRSIS logged in"); return true; } void Service::setupLora(long loraFreq, long bw, int sf, int cr, int pwr, int sync, bool enableCrc) { - Serial.print("LoRa init: "); - Serial.print(loraFreq); Serial.print(", "); - Serial.print(bw); Serial.print(", "); - Serial.print(sf); Serial.print(", "); - Serial.print(cr); Serial.print(", "); - Serial.print(pwr); Serial.print(", "); - Serial.print(sync, 16); Serial.print(", "); - Serial.print(enableCrc); Serial.print("..."); - + LOG_INFO("Initializing LoRa"); + LOG_INFO("Frequency:", loraFreq, "Hz"); + LOG_INFO("Bandwidth:", bw, "Hz"); + LOG_INFO("Spreading:", sf); + LOG_INFO("Coding rate:", cr); + LOG_INFO("Power:", pwr, "dBm"); + LOG_INFO("Sync:", "0x" + String(sync, 16)); + LOG_INFO("CRC:", enableCrc ? "enabled" : "disabled"); + isImplicitHeaderMode_ = sf == 6; #ifdef USE_RADIOLIB radio_ = std::make_shared(new Module(config_.LoraPinSs, config_.LoraPinDio0, config_.LoraPinRst, RADIOLIB_NC)); int state = radio_->begin((float)loraFreq / 1e6, (float)bw / 1e3, sf, cr, sync, pwr); if (state != ERR_NONE) { - Serial.print("Radio start error: "); Serial.println(state); + LOG_ERROR("Radio start error:", state); } radio_->setCRC(enableCrc); //radio_->forceLDRO(false); @@ -166,7 +181,7 @@ void Service::setupLora(long loraFreq, long bw, int sf, int cr, int pwr, int syn state = radio_->startReceive(); if (state != ERR_NONE) { - Serial.print("Receive start error: "); Serial.println(state); + LOG_ERROR("Receive start error:", state); } #else // USE_RADIOLIB @@ -175,10 +190,10 @@ void Service::setupLora(long loraFreq, long bw, int sf, int cr, int pwr, int syn int retryCnt = 0; while (!LoRa.begin(loraFreq)) { - Serial.print("."); + LOG_WARN("LoRa init retry", retryCnt); delay(CfgConnRetryMs); if (retryCnt++ >= CfgConnRetryMaxTimes) { - Serial.println("failed"); + LOG_ERROR("LoRa init failed"); return; } } @@ -198,23 +213,23 @@ void Service::setupLora(long loraFreq, long bw, int sf, int cr, int pwr, int syn } #endif // USE_RADIOLIB - Serial.println("ok"); + LOG_INFO("LoRa initialized"); } void Service::setupBt(const String &btName) { String btType = config_.BtEnableBle ? "BLE" : "BT"; - Serial.print(btType + " init " + btName + "..."); + LOG_INFO(btType, "init", btName); bool btOk = config_.BtEnableBle ? serialBLE_.begin(btName.c_str()) : serialBt_.begin(btName); if (btOk) { - Serial.println("ok"); + LOG_INFO(btType, "initialized"); } else { - Serial.println("failed"); + LOG_ERROR(btType, "failed"); } } @@ -262,7 +277,7 @@ void Service::loop() #ifdef USE_RADIOLIB int state = radio_->startReceive(); if (state != ERR_NONE) { - Serial.print("Start receive error: "); Serial.println(state); + LOG_ERROR("Start receive error: ", state); } #else if (config_.LoraUseIsr) { @@ -296,12 +311,12 @@ ICACHE_RAM_ATTR void Service::onLoraDataAvailableIsr() { if (state == ERR_NONE) { queueRigToSerialIsr(Cmd::Data, rxBuf_, packetSize); } else { - Serial.print("Read data error: "); Serial.println(state); + LOG_ERROR("Read data error: ", state); } state = radio_->startReceive(); if (state != ERR_NONE) { - Serial.print("Start receive error: "); Serial.println(state); + LOG_ERROR("Start receive error: ", state); } } } @@ -332,10 +347,10 @@ void Service::sendPeriodicBeacon() if (config_.EnableRfToIs) { sendToAprsis(payload.ToString()); } - Serial.println("Periodic beacon is sent"); + LOG_INFO("Periodic beacon is sent"); } else { - Serial.println("Beacon payload is invalid"); + LOG_ERROR("Beacon payload is invalid"); } previousBeaconMs_ = currentMs; } @@ -363,22 +378,23 @@ void Service::onAprsisDataAvailable() while (aprsisConn_.available() > 0) { char c = aprsisConn_.read(); if (c == '\r') continue; - Serial.print(c); if (c == '\n') break; aprsisData += c; if (aprsisData.length() >= CfgMaxAprsInMessageSize) { - Serial.println("APRS-IS incoming message is too long, skipping tail"); + LOG_WARN("APRS-IS incoming message is too long, skipping tail"); break; } } + LOG_INFO(aprsisData); + if (config_.EnableIsToRf && aprsisData.length() > 0) { AX25::Payload payload(aprsisData); if (payload.IsValid()) { sendAX25ToLora(payload); } else { - Serial.println("Unknown payload from APRSIS, ignoring"); + LOG_WARN("Unknown payload from APRSIS, ignoring"); } } } @@ -398,7 +414,7 @@ bool Service::sendAX25ToLora(const AX25::Payload &payload) byte buf[CfgMaxAX25PayloadSize]; int bytesWritten = payload.ToBinary(buf, sizeof(buf)); if (bytesWritten <= 0) { - Serial.println("Failed to serialize payload"); + LOG_WARN("Failed to serialize payload"); return false; } queueSerialToRig(Cmd::Data, buf, bytesWritten); @@ -414,12 +430,12 @@ void Service::onRigPacket(void *packet, int packetLength) #endif if (config_.EnableAutoFreqCorrection && abs(frequencyErrorHz) > config_.AutoFreqCorrectionDeltaHz) { config_.LoraFreq -= frequencyErrorHz; - Serial.print("Correcting frequency: "); Serial.println(frequencyErrorHz); + LOG_INFO("Correcting frequency:", frequencyErrorHz); #ifdef USE_RADIOLIB radio_->setFrequency((float)config_.LoraFreq / 1e6); int state = radio_->startReceive(); if (state != ERR_NONE) { - Serial.print("Start receive error: "); Serial.println(state); + LOG_ERROR("Start receive error:", state); } #else LoRa.setFrequency(config_.LoraFreq); @@ -484,18 +500,18 @@ void Service::processIncomingRawPacketAsServer(const byte *packet, int packetLen String("Hz"); String textPayload = payload.ToString(config_.EnableSignalReport ? signalReport : String()); - Serial.println(textPayload); + LOG_INFO(textPayload); if (config_.EnableRfToIs) { sendToAprsis(textPayload); - Serial.println("Packet sent to APRS-IS"); + LOG_INFO("Packet sent to APRS-IS"); } if (config_.EnableRepeater && payload.Digirepeat(ownCallsign_)) { sendAX25ToLora(payload); - Serial.println("Packet digirepeated"); + LOG_INFO("Packet digirepeated"); } } else { - Serial.println("Skipping non-AX25 payload"); + LOG_WARN("Skipping non-AX25 payload"); } } @@ -536,7 +552,7 @@ void Service::onRigTxEnd() interruptEnabled_ = false; int state = radio_->transmit(txBuf, txPacketSize); if (state != ERR_NONE) { - Serial.print("TX error: "); Serial.println(state); + LOG_ERROR("TX error: ", state); } interruptEnabled_ = true; #endif @@ -559,7 +575,7 @@ void Service::attachKissNetworkClient() // connected, client dropped off if (isKissConn_) { if (!kissConn_.connected()) { - Serial.println("KISS TCP/IP client disconnected"); + LOG_INFO("KISS TCP/IP client disconnected"); isKissConn_ = false; kissConn_.stop(); } @@ -571,7 +587,7 @@ void Service::attachKissNetworkClient() if (isKissConn_) { kissConn_.stop(); } - Serial.println("New KISS TCP/IP client connected"); + LOG_INFO("New KISS TCP/IP client connected"); kissConn_ = wifiClient; isKissConn_ = true; } @@ -579,7 +595,10 @@ void Service::attachKissNetworkClient() void Service::onSerialTx(byte b) { - if (isKissConn_) { + if (config_.UsbSerialEnable) { + Serial.write(b); + } + else if (isKissConn_) { kissConn_.write(b); } else if (config_.BtEnableBle) { @@ -592,7 +611,10 @@ void Service::onSerialTx(byte b) bool Service::onSerialRxHasData() { - if (isKissConn_) { + if (config_.UsbSerialEnable) { + return Serial.available(); + } + else if (isKissConn_) { return kissConn_.available(); } else if (config_.BtEnableBle) { @@ -606,8 +628,11 @@ bool Service::onSerialRxHasData() bool Service::onSerialRx(byte *b) { int rxResult; - - if (isKissConn_) { + + if (config_.UsbSerialEnable) { + rxResult = Serial.read(); + } + else if (isKissConn_) { rxResult = kissConn_.read(); // client dropped off if (rxResult == -1) { @@ -631,19 +656,19 @@ void Service::onControlCommand(Cmd cmd, byte value) { switch (cmd) { case Cmd::P: - Serial.print("CSMA P: "); Serial.println(value); + LOG_INFO("CSMA P:", value); csmaP_ = value; break; case Cmd::SlotTime: - Serial.print("CSMA SlotTime: "); Serial.println(value); + LOG_INFO("CSMA SlotTime:", value); csmaSlotTime_ = (long)value * 10; break; case Cmd::TxDelay: - Serial.print("TX delay: "); Serial.println(value); + LOG_INFO("TX delay:", value); config_.PttTxDelayMs = (long)value * 10; break; case Cmd::TxTail: - Serial.print("TX tail: "); Serial.println(value); + LOG_INFO("TX tail:", value); config_.PttTxTailMs = (long)value * 10; break; default: @@ -667,13 +692,13 @@ void Service::onRadioControlCommand(const std::vector &rawCommand) { setupLora(config_.LoraFreq, config_.LoraBw, config_.LoraSf, config_.LoraCodingRate, config_.LoraPower, config_.LoraSync, config_.LoraEnableCrc); } else { - Serial.println("Radio control command of wrong size"); + LOG_ERROR("Radio control command of wrong size"); } } void Service::onRebootCommand() { - Serial.println("Reboot requested"); + LOG_INFO("Reboot requested"); ESP.restart(); } diff --git a/loraprs_service.h b/loraprs_service.h index 89e9fa9..a00e64a 100644 --- a/loraprs_service.h +++ b/loraprs_service.h @@ -3,6 +3,7 @@ #include #include +#include // When USE_RADIOLIB is defined then RadioLib will be used, otherwise arduino-LoRa will be used // When using RadioLib, default module is SX1278, if you are using @@ -12,10 +13,8 @@ #ifdef USE_RADIOLIB #include -#pragma message("Using RadioLib") #else #include -#pragma message("Using arduino-LoRa") #endif #include