diff --git a/firmware/application/apps/ui_pocsag_tx.cpp b/firmware/application/apps/ui_pocsag_tx.cpp index fc0a9916..b9bc06d7 100644 --- a/firmware/application/apps/ui_pocsag_tx.cpp +++ b/firmware/application/apps/ui_pocsag_tx.cpp @@ -42,6 +42,32 @@ POCSAGTXView::~POCSAGTXView() { baseband::shutdown(); } +void POCSAGTXView::on_remote(const PocsagTosendMessage data) { + // check if still sending or not + size_t tmp = 0; + if (data.baud == 1200) tmp = 1; + if (data.baud == 2400) tmp = 2; + options_bitrate.set_selected_index(tmp); + tmp = 0; + options_type.set_selected_index(data.type); + if (data.function == 'B') tmp = 1; + if (data.function == 'C') tmp = 2; + if (data.function == 'D') tmp = 3; + options_function.set_selected_index(tmp); + options_phase.set_selected_index(data.phase == 'P' ? 0 : 1); + field_address.set_value(data.addr); + message = (char*)data.msg; + text_message.set(message); + options_bitrate.dirty(); + options_type.dirty(); + options_function.dirty(); + options_phase.dirty(); + field_address.dirty(); + text_message.dirty(); + tx_view.focus(); + start_tx(); +} + void POCSAGTXView::on_tx_progress(const uint32_t progress, const bool done) { if (done) { transmitter_model.disable(); diff --git a/firmware/application/apps/ui_pocsag_tx.hpp b/firmware/application/apps/ui_pocsag_tx.hpp index cba4a444..634e12f9 100644 --- a/firmware/application/apps/ui_pocsag_tx.hpp +++ b/firmware/application/apps/ui_pocsag_tx.hpp @@ -76,6 +76,7 @@ class POCSAGTXView : public View { void on_set_text(NavigationView& nav); void on_tx_progress(const uint32_t progress, const bool done); + void on_remote(const PocsagTosendMessage data); bool start_tx(); Labels labels{ @@ -142,6 +143,13 @@ class POCSAGTXView : public View { const auto message = *reinterpret_cast(p); this->on_tx_progress(message.progress, message.done); }}; + + MessageHandlerRegistration message_handler_tx_remote{ + Message::ID::PocsagTosend, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_remote(message); + }}; }; } /* namespace ui */ diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 768f4ff7..3964e6ed 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -1053,6 +1053,84 @@ static void cmd_settingsreset(BaseSequentialStream* chp, int argc, char* argv[]) chprintf(chp, "ok\r\n"); } +static void cmd_sendpocsag(BaseSequentialStream* chp, int argc, char* argv[]) { + const char* usage = "usage: sendpocsag [baud] [type] [function] [phase] \r\n"; + (void)argv; + if (argc < 2) { + chprintf(chp, usage); + return; + } + uint64_t addr = atol(argv[0]); + int msglen = atoi(argv[1]); // without minimum limit, since addr only don't send anything + if (msglen > 30 || msglen < 0) { + chprintf(chp, "error, msglen max is 30\r\n"); + return; + } + + int baud = 1200; + if (argc >= 3) { + baud = atoi(argv[2]); + if (baud != 512 && baud != 1200 && baud != 2400) { + chprintf(chp, "error, baud can only be 512, 1200 or 2400\r\n"); + return; + } + } + + int type = 2; + if (argc >= 4) { + type = atoi(argv[3]); + if (type > 2 || type < 0) { + chprintf(chp, "error, type can be 0 (ADDRESS_ONLY) 1 (NUMERIC_ONLY) 2 (ALPHANUMERIC)\r\n"); + return; + } + } + + char function = 'D'; + if (argc >= 5) { + function = *argv[4]; + if (function < 'A' && function > 'D') { + chprintf(chp, "error, function can be A, B, C or D\r\n"); + return; + } + } + + char phase = 'P'; + if (argc >= 6) { + phase = *argv[5]; + if (phase != 'P' && phase != 'N') { + chprintf(chp, "error, phase can be P or N\r\n"); + return; + } + } + + uint8_t msg[31] = {0}; + if (msglen > 0) { + chprintf(chp, "send %d bytes\r\n", msglen); + do { + size_t bytes_to_read = msglen > USB_BULK_BUFFER_SIZE ? USB_BULK_BUFFER_SIZE : msglen; + size_t bytes_read = chSequentialStreamRead(chp, &msg[0], bytes_to_read); + if (bytes_read != bytes_to_read) + return; + msglen -= bytes_read; + } while (msglen > 0); + } + + auto evtd = getEventDispatcherInstance(); + if (!evtd) return; + auto top_widget = evtd->getTopWidget(); + if (!top_widget) return; + auto nav = static_cast(top_widget)->get_navigation_view(); + if (!nav) return; + if (!nav->StartAppByName("pocsagtx")) { + chprintf(chp, "error starting pocsagtx\r\n"); + return; + } + chThdSleepMilliseconds(1000); // wait for app to start + PocsagTosendMessage message{(uint16_t)baud, (uint8_t)type, function, phase, (uint8_t)msglen, msg, addr}; + EventDispatcher::send_message(message); + chprintf(chp, "ok\r\n"); +} + static const ShellCommand commands[] = { {"reboot", cmd_reboot}, {"dfu", cmd_dfu}, @@ -1083,6 +1161,7 @@ static const ShellCommand commands[] = { {"radioinfo", cmd_radioinfo}, {"pmemreset", cmd_pmemreset}, {"settingsreset", cmd_settingsreset}, + {"sendpocsag", cmd_sendpocsag}, {NULL, NULL}}; static const ShellConfig shell_cfg1 = { diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index e116aa3f..9f5da610 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -122,6 +122,7 @@ class Message { OrientationData = 64, EnvironmentData = 65, AudioBeep = 66, + PocsagTosend = 67, MAX }; @@ -1379,4 +1380,33 @@ class AudioBeepMessage : public Message { uint32_t sample_rate = 24000; uint32_t duration_ms = 100; }; + +class PocsagTosendMessage : public Message { + public: + constexpr PocsagTosendMessage( + uint16_t baud = 1200, + uint8_t type = 2, + char function = 'D', + char phase = 'N', + uint8_t msglen = 0, + uint8_t msg[31] = {0}, + uint64_t addr = 0) + : Message{ID::PocsagTosend}, + baud{baud}, + type{type}, + function{function}, + phase{phase}, + msglen{msglen}, + addr{addr} { + memcpy(this->msg, msg, 31); + } + uint16_t baud = 1200; + uint8_t type = 2; + char function = 'D'; + char phase = 'N'; + uint8_t msglen = 0; + uint8_t msg[31] = {0}; + uint64_t addr = 0; +}; + #endif /*__MESSAGE_H__*/