Skip to content

Commit d56ce73

Browse files
committed
add initial support for "SDR-like" operation (this currently doesn't support any specific targeted SDR, and currently generates 4FSK frames carried by ZeroMQ to a target application for mod/demod);
1 parent c6ad0b0 commit d56ce73

17 files changed

+2857
-5
lines changed

Defines.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
66
*
77
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
8-
* Copyright (C) 2018 Bryan Biedenkapp, N2PLL
8+
* Copyright (C) 2018,2025 Bryan Biedenkapp, N2PLL
99
*
1010
*/
1111
/**
@@ -17,6 +17,8 @@
1717

1818
#include <stdint.h>
1919

20+
21+
2022
#if !defined(NATIVE_SDR)
2123
#if defined(__SAM3X8E__) && !defined(STM32F4XX)
2224
#define ARM_MATH_CM3
@@ -31,7 +33,11 @@
3133
#include <cstring>
3234
#endif
3335

36+
#if !defined(NATIVE_SDR)
3437
#include <arm_math.h>
38+
#else
39+
#include "sdr/arm_math.h"
40+
#endif
3541

3642
// ---------------------------------------------------------------------------
3743
// Types
@@ -150,6 +156,7 @@ const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x0
150156
#define CPU_TYPE_ARDUINO_DUE 0x00U
151157
#define CPU_TYPE_NXP 0x01U
152158
#define CPU_TYPE_STM32 0x02U
159+
#define CPU_TYPE_NATIVE_SDR 0xF0U
153160

154161
// ---------------------------------------------------------------------------
155162
// Macros

FirmwareMain.cpp

Lines changed: 308 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,35 @@
77
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
88
* Copyright (C) 2016 Mathis Schmieder, DB9MAT
99
* Copyright (C) 2016 Colin Durbridge, G4EML
10-
* Copyright (C) 2018,2024 Bryan Biedenkapp, N2PLL
10+
* Copyright (C) 2018,2024,2025 Bryan Biedenkapp, N2PLL
1111
*
1212
*/
1313
#include "Globals.h"
1414

15+
#if defined(NATIVE_SDR)
16+
#include "sdr/port/PseudoPTYPort.h"
17+
18+
#include <sys/types.h>
19+
#include <unistd.h>
20+
#include <signal.h>
21+
#include <fcntl.h>
22+
#include <pwd.h>
23+
#include <cstdio>
24+
#include <cassert>
25+
#include <cstdlib>
26+
#include <cstring>
27+
28+
#include <zmq.hpp>
29+
#endif
30+
31+
// ---------------------------------------------------------------------------
32+
// Macros
33+
// ---------------------------------------------------------------------------
34+
35+
#if defined(NATIVE_SDR)
36+
#define IS(s) (::strcmp(argv[i], s) == 0)
37+
#endif
38+
1539
// ---------------------------------------------------------------------------
1640
// Globals Variables
1741
// ---------------------------------------------------------------------------
@@ -60,6 +84,29 @@ CWIdTX cwIdTX;
6084
SerialPort serial;
6185
IO io;
6286

87+
#if defined(NATIVE_SDR)
88+
std::string g_progExe = std::string(__EXE_NAME__);
89+
90+
std::string m_zmqRx = std::string("ipc:///tmp/dvm-rx.ipc");
91+
std::string m_zmqTx = std::string("ipc:///tmp/dvm-tx.ipc");
92+
93+
std::string m_ptyPort = std::string("/dev/ptmx");
94+
95+
std::string g_logFileName = std::string("dsp.log");
96+
97+
bool g_debug = false;
98+
99+
int g_signal = 0;
100+
bool g_killed = false;
101+
102+
bool g_daemon = false;
103+
104+
extern sdr::port::PseudoPTYPort* m_serialPort;
105+
106+
extern zmq::socket_t m_zmqSocketTx;
107+
extern zmq::socket_t m_zmqSocketRx;
108+
#endif
109+
63110
// ---------------------------------------------------------------------------
64111
// Global Functions
65112
// ---------------------------------------------------------------------------
@@ -278,3 +325,263 @@ int main()
278325
loop();
279326
}
280327
#endif // defined(STM32F4XX)
328+
329+
#if defined(NATIVE_SDR)
330+
void fatal(const char* message)
331+
{
332+
::fprintf(stderr, "%s: %s\n", g_progExe.c_str(), message);
333+
exit(EXIT_FAILURE);
334+
}
335+
336+
void usage(const char* message, const char* arg)
337+
{
338+
::fprintf(stdout, "" DESCRIPTION " (built %s)\r\n", __BUILD__);
339+
::fprintf(stdout, "Copyright (c) 2025 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\n");
340+
::fprintf(stdout, "Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others\n\n");
341+
if (message != nullptr) {
342+
::fprintf(stderr, "%s: ", g_progExe.c_str());
343+
::fprintf(stderr, message, arg);
344+
::fprintf(stderr, "\n\n");
345+
}
346+
347+
::fprintf(stdout,
348+
"usage: %s [-bdvh]"
349+
" [--syslog]"
350+
" [-r <ZeroMQ Rx IPC Endpoint>] [-t <ZeroMQ Tx IPC Endpoint>]"
351+
" [-p <PTY port>]"
352+
" [-l <log filename>]\n\n"
353+
" -b background process\n"
354+
"\n"
355+
" -d enable debug\n"
356+
" -v show version information\n"
357+
" -h show this screen\n"
358+
"\n"
359+
" --syslog force logging to syslog\n"
360+
"\n"
361+
" -r ZeroMQ Rx IPC Endpoint\n"
362+
" -t ZeroMQ Tx IPC Endpoint\n"
363+
"\n"
364+
" -p PTY Port\n"
365+
"\n"
366+
" -l Log Filename\n"
367+
"\n"
368+
" -- stop handling options\n",
369+
g_progExe.c_str());
370+
exit(EXIT_FAILURE);
371+
}
372+
373+
int checkArgs(int argc, char* argv[])
374+
{
375+
int i, p = 0;
376+
377+
// iterate through arguments
378+
for (i = 1; i <= argc; i++)
379+
{
380+
if (argv[i] == nullptr) {
381+
break;
382+
}
383+
384+
if (*argv[i] != '-') {
385+
continue;
386+
}
387+
else if (IS("--")) {
388+
++p;
389+
break;
390+
}
391+
else if (IS("-r")) {
392+
if ((argc - 1) <= 0)
393+
usage("error: %s", "must specify the ZeroMQ Rx IPC Endpoint");
394+
m_zmqRx = std::string(argv[++i]);
395+
396+
if (m_zmqRx == "")
397+
usage("error: %s", "IPC endpoint cannot be blank!");
398+
399+
p += 2;
400+
}
401+
else if (IS("-t")) {
402+
if ((argc - 1) <= 0)
403+
usage("error: %s", "must specify the ZeroMQ Tx IPC Endpoint");
404+
m_zmqTx = std::string(argv[++i]);
405+
406+
if (m_zmqTx == "")
407+
usage("error: %s", "IPC endpoint cannot be blank!");
408+
409+
p += 2;
410+
}
411+
else if (IS("-p")) {
412+
if ((argc - 1) <= 0)
413+
usage("error: %s", "must specify the PTY port");
414+
m_ptyPort = std::string(argv[++i]);
415+
416+
if (m_ptyPort == "")
417+
usage("error: %s", "PTY port cannot be blank!");
418+
419+
p += 2;
420+
}
421+
else if (IS("-l")) {
422+
if ((argc - 1) <= 0)
423+
usage("error: %s", "must specify the log filename");
424+
g_logFileName = std::string(argv[++i]);
425+
426+
if (g_logFileName == "")
427+
usage("error: %s", "log filename cannot be blank!");
428+
429+
p += 2;
430+
}
431+
else if (IS("-b")) {
432+
++p;
433+
g_daemon = true;
434+
}
435+
else if (IS("-d")) {
436+
++p;
437+
g_debug = true;
438+
}
439+
else if (IS("--syslog")) {
440+
g_useSyslog = true;
441+
}
442+
else if (IS("-v")) {
443+
::fprintf(stdout, "" DESCRIPTION " (built %s)\r\n", __BUILD__);
444+
::fprintf(stdout, "Copyright (c) 2022 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\r\n");
445+
::fprintf(stdout, "Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others\r\n");
446+
if (argc == 2)
447+
exit(EXIT_SUCCESS);
448+
}
449+
else if (IS("-h")) {
450+
usage(nullptr, nullptr);
451+
if (argc == 2)
452+
exit(EXIT_SUCCESS);
453+
}
454+
else {
455+
usage("unrecognized option `%s'", argv[i]);
456+
}
457+
}
458+
459+
if (p < 0 || p > argc) {
460+
p = 0;
461+
}
462+
463+
return ++p;
464+
}
465+
466+
static void sigHandler(int signum)
467+
{
468+
g_killed = true;
469+
g_signal = signum;
470+
}
471+
472+
// ---------------------------------------------------------------------------
473+
// Program Entry Point
474+
// ---------------------------------------------------------------------------
475+
476+
int main(int argc, char** argv)
477+
{
478+
m_zmqRx = std::string("ipc:///tmp/dvm-rx.ipc");
479+
m_zmqTx = std::string("ipc:///tmp/dvm-tx.ipc");
480+
481+
if (argv[0] != nullptr && *argv[0] != 0)
482+
g_progExe = std::string(argv[0]);
483+
484+
if (argc > 1) {
485+
// check arguments
486+
int i = checkArgs(argc, argv);
487+
if (i < argc) {
488+
argc -= i;
489+
argv += i;
490+
}
491+
else {
492+
argc--;
493+
argv++;
494+
}
495+
}
496+
497+
::signal(SIGINT, sigHandler);
498+
::signal(SIGTERM, sigHandler);
499+
::signal(SIGHUP, sigHandler);
500+
501+
// initialize system logging
502+
bool ret = ::LogInitialise(".", g_logFileName.c_str(), 1U, 1U);
503+
if (!ret) {
504+
::fprintf(stderr, "unable to open the log file\n");
505+
return 1;
506+
}
507+
508+
// handle POSIX process forking
509+
if (g_daemon) {
510+
// create new process
511+
pid_t pid = ::fork();
512+
if (pid == -1) {
513+
::fprintf(stderr, "%s: Couldn't fork() , exiting\n", g_progExe.c_str());
514+
::LogFinalise();
515+
return EXIT_FAILURE;
516+
}
517+
else if (pid != 0) {
518+
::LogFinalise();
519+
exit(EXIT_SUCCESS);
520+
}
521+
522+
// create new session and process group
523+
if (::setsid() == -1) {
524+
::fprintf(stderr, "%s: Couldn't setsid(), exiting\n", g_progExe.c_str());
525+
::LogFinalise();
526+
return EXIT_FAILURE;
527+
}
528+
529+
// set the working directory to the root directory
530+
if (::chdir("/") == -1) {
531+
::fprintf(stderr, "%s: Couldn't cd /, exiting\n", g_progExe.c_str());
532+
::LogFinalise();
533+
return EXIT_FAILURE;
534+
}
535+
536+
::close(STDIN_FILENO);
537+
::close(STDOUT_FILENO);
538+
::close(STDERR_FILENO);
539+
}
540+
541+
do {
542+
g_signal = 0;
543+
544+
{
545+
::LogInfo("" DESCRIPTION " (built %s)", __BUILD__);
546+
::LogInfo("Copyright (c) 2017-2025 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.");
547+
::LogInfo("Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others");
548+
549+
::LogInfoEx(LOG_DSP, "DSP is performing initialization and warmup");
550+
setup();
551+
552+
::LogInfoEx(LOG_DSP, "DSP is up and running");
553+
while (!g_killed) {
554+
loop();
555+
::usleep(1);
556+
}
557+
}
558+
559+
if (g_signal == 2)
560+
::LogInfoEx(LOG_DSP, "Exited on receipt of SIGINT");
561+
562+
if (g_signal == 15)
563+
::LogInfoEx(LOG_DSP, "Exited on receipt of SIGTERM");
564+
565+
if (g_signal == 1)
566+
::LogInfoEx(LOG_DSP, "Restarting on receipt of SIGHUP");
567+
} while (g_signal == 1);
568+
569+
::LogInfoEx(LOG_DSP, "DSP is shutting down");
570+
571+
if (m_serialPort != nullptr) {
572+
m_serialPort->close();
573+
delete m_serialPort;
574+
}
575+
576+
try
577+
{
578+
m_zmqSocketTx.close();
579+
m_zmqSocketRx.close();
580+
}
581+
catch(const zmq::error_t& zmqE) { /* stub */ }
582+
catch(const std::exception& e) { /* stub */ }
583+
584+
::LogFinalise();
585+
return 0;
586+
}
587+
#endif // defined(NATIVE_SDR)

0 commit comments

Comments
 (0)