diff --git a/Plugin.cmake b/Plugin.cmake index 46289b03..ed5295d5 100644 --- a/Plugin.cmake +++ b/Plugin.cmake @@ -65,7 +65,7 @@ set(SRC ) -set(PKG_API_LIB api-18) # A directory in libs/ e. g., api-18 or api-19 +set(PKG_API_LIB api-19) # A directory in libs/ e. g., api-18 or api-19 macro(late_init) # Perform initialization after the PACKAGE_NAME library, compilers @@ -80,8 +80,8 @@ macro(add_plugin_libraries) # add_subdirectory("${CMAKE_SOURCE_DIR}/opencpn-libs/tinyxml") # target_link_libraries(${PACKAGE_NAME} ocpn::tinyxml) -# add_subdirectory("${CMAKE_SOURCE_DIR}/opencpn-libs/wxJSON") -# target_link_libraries(${PACKAGE_NAME} ocpn::wxjson) +add_subdirectory("${CMAKE_SOURCE_DIR}/opencpn-libs/wxJSON") +target_link_libraries(${PACKAGE_NAME} ocpn::wxjson) # add_subdirectory("${CMAKE_SOURCE_DIR}/opencpn-libs/plugingl") # target_link_libraries(${PACKAGE_NAME} ocpn::plugingl) diff --git a/src/vdr_pi.cpp b/src/vdr_pi.cpp index 5a5e2508..e85daf15 100644 --- a/src/vdr_pi.cpp +++ b/src/vdr_pi.cpp @@ -26,6 +26,8 @@ #include "wx/tokenzr.h" #include "wx/statline.h" #include "wx/display.h" +#include "wx/jsonreader.h" +#include "wx/jsonwriter.h" #include #include @@ -230,6 +232,7 @@ void vdr_pi::UpdateSignalKListeners() { m_protocols.signalK); if (m_protocols.signalK) { // TODO: Implement SignalK configuration. + m_eventHandler->Bind(EVT_SIGNALK, &vdr_pi::OnSignalKEvent, this); } } @@ -320,7 +323,57 @@ void vdr_pi::OnSignalKEvent(wxCommandEvent& event) { // SignalK recording is disabled. return; } - // TODO: Implement SignalK recording. +#ifndef ANDROID + // Note: the plugin API 1.19 is not available on Android. + // When it is available, the ifndef condition can be removed. + + ObservedEvt& ev = dynamic_cast(event); + auto ptr = GetSignalkPayload(ev); + const auto msg = *std::static_pointer_cast(ptr); + + // Create a default empty JSON value + const wxJSONValue defaultValue; + + const wxJSONValue& data = msg.Get("Data", defaultValue); + wxString context = msg.Get("Context", defaultValue).AsString(); + wxString self = msg.Get("ContextSelf", defaultValue).AsString(); + + // Format message for recording + wxString formatted_message; + wxJSONWriter writer; + switch (m_data_format) { + case VDRDataFormat::CSV: { + // CSV format: timestamp,type,id,data + // Where 'id' is the SignalK context. + wxString timestamp = FormatIsoDateTime(wxDateTime::UNow()); + wxString json_str; + writer.Write(data, json_str); // Get full JSON representation + // Escape any commas in the JSON + json_str.Replace("\"", "\"\""); + formatted_message = wxString::Format("%s,SignalK,%s,\"%s\"\n", timestamp, + context, json_str); + break; + } + case VDRDataFormat::RawNMEA: + // $SKLL format (local format for SignalK): + // $SKLL,context,json_data*checksum + wxString json_str; + writer.Write(data, json_str); // Get full JSON representation + formatted_message = wxString::Format("$SKLL,%s,%s", context, json_str); + // Add checksum + unsigned char checksum = 0; + for (size_t i = 1; i < formatted_message.length(); i++) { + checksum ^= static_cast(formatted_message[i].GetValue()); + } + formatted_message += wxString::Format("*%02X\r\n", checksum); + break; + } + + // Check if we need to rotate the VDR file. + CheckLogRotation(); + + m_ostream.Write(formatted_message.ToStdString()); +#endif // ANDROID } // Helper function to convert little-endian bytes to float @@ -892,12 +945,10 @@ bool vdr_pi::LoadConfig(void) { pConf->Read(_T("NMEA2000_Port"), &m_protocols.n2kNet.port, 10112); pConf->Read(_T("NMEA2000_Enabled"), &m_protocols.n2kNet.enabled, false); -#if 0 // Signal K network settings pConf->Read(_T("SignalK_UseTCP"), &m_protocols.signalKNet.useTCP, true); pConf->Read(_T("SignalK_Port"), &m_protocols.signalKNet.port, 8375); pConf->Read(_T("SignalK_Enabled"), &m_protocols.signalKNet.enabled, false); -#endif return true; } @@ -940,12 +991,10 @@ bool vdr_pi::SaveConfig(void) { pConf->Write(_T("NMEA2000_Port"), m_protocols.n2kNet.port); pConf->Write(_T("NMEA2000_Enabled"), m_protocols.n2kNet.enabled); -#if 0 // Signal K network settings pConf->Write(_T("SignalK_UseTCP"), m_protocols.signalKNet.useTCP); pConf->Write(_T("SignalK_Port"), m_protocols.signalKNet.port); pConf->Write(_T("SignalK_Enabled"), m_protocols.signalKNet.enabled); -#endif return true; } diff --git a/src/vdr_pi_prefs.cpp b/src/vdr_pi_prefs.cpp index 727af736..a6a58aac 100644 --- a/src/vdr_pi_prefs.cpp +++ b/src/vdr_pi_prefs.cpp @@ -142,11 +142,9 @@ wxPanel* VDRPrefsDialog::CreateRecordingTab(wxWindow* parent) { m_nmea2000Check->SetValue(m_protocols.nmea2000); protocolSizer->Add(m_nmea2000Check, 0, wxALL, 5); -#if 0 m_signalKCheck = new wxCheckBox(panel, ID_SIGNALK_CHECK, _("Signal K")); m_signalKCheck->SetValue(m_protocols.signalK); protocolSizer->Add(m_signalKCheck, 0, wxALL, 5); -#endif mainSizer->Add(protocolSizer, 0, wxEXPAND | wxALL, 5); @@ -297,11 +295,9 @@ wxPanel* VDRPrefsDialog::CreateReplayTab(wxWindow* parent) { new ConnectionSettingsPanel(panel, _("NMEA 2000"), m_protocols.n2kNet); mainSizer->Add(m_nmea2000NetPanel, 0, wxEXPAND | wxALL, 5); -#if 0 // Signal K support disabled for now - m_signalKNetPanel = new ConnectionSettingsPanel(panel, _("Signal K"), - m_protocols.signalKNet); + m_signalKNetPanel = + new ConnectionSettingsPanel(panel, _("Signal K"), m_protocols.signalKNet); mainSizer->Add(m_signalKNetPanel, 0, wxEXPAND | wxALL, 5); -#endif panel->SetSizer(mainSizer); @@ -321,16 +317,12 @@ void VDRPrefsDialog::OnOK(wxCommandEvent& event) { // Protocol settings m_protocols.nmea0183 = m_nmea0183Check->GetValue(); m_protocols.nmea2000 = m_nmea2000Check->GetValue(); -#if 0 m_protocols.signalK = m_signalKCheck->GetValue(); -#endif // Network settings m_protocols.nmea0183Net = m_nmea0183NetPanel->GetSettings(); m_protocols.n2kNet = m_nmea2000NetPanel->GetSettings(); -#if 0 m_protocols.signalKNet = m_signalKNetPanel->GetSettings(); -#endif m_protocols.nmea0183ReplayMode = m_nmea0183InternalRadio->GetValue() ? NMEA0183ReplayMode::INTERNAL_API : NMEA0183ReplayMode::NETWORK; diff --git a/src/vdr_pi_prefs.h b/src/vdr_pi_prefs.h index b135a4e0..effcf37e 100644 --- a/src/vdr_pi_prefs.h +++ b/src/vdr_pi_prefs.h @@ -143,9 +143,7 @@ class VDRPrefsDialog : public wxDialog { // Protocol selection wxCheckBox* m_nmea0183Check; //!< Enable NMEA 0183 recording wxCheckBox* m_nmea2000Check; //!< Enable NMEA 2000 recording -#if 0 - wxCheckBox* m_signalKCheck; //!< Enable Signal K recording -#endif + wxCheckBox* m_signalKCheck; //!< Enable Signal K recording // Replay tab controls // NMEA 0183 replay mode @@ -155,9 +153,7 @@ class VDRPrefsDialog : public wxDialog { // Network selection ConnectionSettingsPanel* m_nmea0183NetPanel; ConnectionSettingsPanel* m_nmea2000NetPanel; -#if 0 ConnectionSettingsPanel* m_signalKNetPanel; -#endif VDRDataFormat m_format; //!< Selected data format wxString m_recording_dir; //!< Selected recording directory