M17 - IP Frame and UDP Socket Connect/Blaster(WIP);

This commit is contained in:
lwvmobile 2024-03-05 16:00:35 -05:00
parent a2113fcdcc
commit 0ba3fee968
4 changed files with 174 additions and 25 deletions

View File

@ -338,6 +338,12 @@ typedef struct
int udp_portno;
char udp_hostname[1024];
//M17 UDP for IP frame output
int m17_use_ip; //if enabled, open UDP and broadcast IP frame
int m17_portno; //default is 17000
int m17_udp_sock; //actual UDP socket for M17 to send to
char m17_hostname[1024];
//tcp socket for SDR++, etc
int tcp_sockfd;
int tcp_portno;
@ -1275,6 +1281,8 @@ int udp_socket_connect(dsd_opts * opts, dsd_state * state);
int udp_socket_connectA(dsd_opts * opts, dsd_state * state);
int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
int udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state);
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
#ifdef __cplusplus
extern "C" {

View File

@ -702,6 +702,12 @@ initOpts (dsd_opts * opts)
opts->udp_portno = 23456; //default port, same os OP25's sockaudio.py
sprintf (opts->udp_hostname, "%s", "127.0.0.1");
//M17 UDP Port and hostname
opts->m17_use_ip = 0; //if enabled, open UDP and broadcast IP frame
opts->m17_portno = 17000; //default is 17000
opts->m17_udp_sock = 0; //actual UDP socket for M17 to send to
sprintf (opts->m17_hostname, "%s", "127.0.0.1");
//tcp input options
opts->tcp_sockfd = 0;
opts->tcp_portno = 7355; //default favored by SDR++

View File

@ -32,6 +32,7 @@ void error(char *msg) {
struct sockaddr_in address;
struct sockaddr_in addressA;
struct sockaddr_in addressM17;
//
// Connect
@ -334,6 +335,22 @@ int udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void *
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
}
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
{
UNUSED(state);
size_t err = 0;
//listen with:
//54 packed bytes
//socat stdio udp-listen:17000 | (decoder)
//send audio or data to socket
err = sendto(opts->m17_udp_sock, data, nsam, 0, (const struct sockaddr * ) & addressM17, sizeof(struct sockaddr_in));
if (err < 0) fprintf (stderr, "\n UDP SENDTO ERR %ld", err); //return value here is size_t number of characters sent, or -1 for failure
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
}
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
{
UNUSED(state);
@ -412,6 +429,45 @@ int udp_socket_connectA(dsd_opts * opts, dsd_state * state)
}
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state)
{
UNUSED(state);
long int err = 0;
err = opts->m17_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (err < 0)
{
fprintf (stderr, " UDP Socket Error %ld\n", err);
return (err);
}
// Don't think this is needed, but doesn't seem to hurt to keep it here either
int broadcastEnable = 1;
err = setsockopt(opts->m17_udp_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
if (err < 0)
{
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
return (err);
}
memset((char * ) & addressM17, 0, sizeof(addressM17));
addressM17.sin_family = AF_INET;
err = addressM17.sin_addr.s_addr = inet_addr(opts->m17_hostname);
if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs
{
fprintf (stderr, " UDP inet_addr Error %ld\n", err);
return (err);
}
addressM17.sin_port = htons(opts->m17_portno); //plus 2 to current port assignment for the analog port value
if (err < 0)
{
fprintf (stderr, " UDP htons Error %ld\n", err);
return (err);
}
}
void return_to_cc (dsd_opts * opts, dsd_state * state)
{
//extra safeguards due to sync issues with NXDN

129
src/m17.c
View File

@ -885,12 +885,52 @@ const int8_t symbol_map[4] = {+1, +3, -1, -3};
void encodeM17STR(dsd_opts * opts, dsd_state * state)
{
//TODO: Standard IP Framing
//TODO: Finish creating audio of the encoded signal
//Enable frame, TX and Ncurses Printer
opts->frame_m17 = 1;
state->m17encoder_tx = 1;
if (opts->use_ncurses_terminal == 1)
ncursesOpen(opts, state);
//User Defined Variables
int use_ip = 0; //1 to enable IP Frame Broadcast over UDP
int udpport = 17000; //port number for M17 IP Frmae (default is 17000)
sprintf (opts->m17_hostname, "%s", "127.0.0.1"); //enter IP address or hostname here
uint8_t can = 7; //channel access number
//numerical representation of dst and src after b40 encoding, or special/reserved value
unsigned long long int dst = 0;
unsigned long long int src = 0;
//DST and SRC Callsign Data (pick up to 9 characters from the b40 char array)
char d40[] = "BROADCAST"; //DST
char s40[] = "DSD-FME "; //SRC
//end User Defined Variables
int i, j, k, x; //basic utility counters
short sample = 0; //individual audio sample from source
size_t nsam = 160; //number of samples to be read in (default is for codec2 3200 bps)
//WIP: Open UDP port to 17000 and see if any other config info is necessary for running standard IP frames, etc,
//or perhaps just also configure an input format for that ip streaming method, may need to handle UDP control packets (conn, ackn, nack, ping, pong, disc)
int sock_err;
if (use_ip == 1)
{
opts->m17_portno = udpport;
sock_err = udp_socket_connectM17(opts, state);
if (sock_err < 0)
{
fprintf (stderr, "Error Configuring UDP Socket for M17 IP Frame :( \n");
use_ip = 0;
}
else opts->m17_use_ip = 1;
}
//TODO: See if we need to send a conn and/or receice any ackn/nack/ping/pong commands later
//WIP: Standard IP Framing
uint8_t magic[4] = {0x4D, 0x31, 0x37, 0x20}; UNUSED(magic);
uint8_t sid[2]; memset (sid, 0, sizeof(sid)); UNUSED(sid);
//TODO: Finish creating audio of the encoded signal
//NONCE
time_t ts = time(NULL); //timestamp since epoch / "Unix Time"
srand(ts); //randomizer seed based on timestamp
@ -921,27 +961,6 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state)
nonce[12] = rand() & 0xFF;
nonce[13] = rand() & 0xFF;
//Enable frame, TX and Ncurses Printer
opts->frame_m17 = 1;
state->m17encoder_tx = 1;
if (opts->use_ncurses_terminal == 1)
ncursesOpen(opts, state);
//User Defined Variables
uint8_t can = 7; //channel access number
//numerical representation of dst and src after b40 encoding, or special/reserved value
unsigned long long int dst = 0;
unsigned long long int src = 0;
//DST and SRC Callsign Data (pick up to 9 characters from the b40 char array)
char d40[] = "BROADCAST"; //DST
char s40[] = "DSD-FME "; //SRC
//end User Defined Variables
int i, j, k, x; //basic utility counters
short sample = 0; //individual audio sample from source
size_t nsam = 160; //number of samples to be read in (default is for codec2 3200 bps)
//debug print nonce
// fprintf (stderr, " nonce:");
// for (i = 0; i < 14; i++)
@ -1347,8 +1366,68 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state)
UNUSED(output_symbols);
//TODO: symbols to audio
//Contruct an IP frame using previously created arrays
uint8_t m17_ip_frame[432]; memset (m17_ip_frame, 0, sizeof(m17_ip_frame)); UNUSED(m17_ip_frame);
uint8_t m17_ip_packed[54]; memset (m17_ip_packed, 0, sizeof(m17_ip_packed)); UNUSED(m17_ip_packed);
uint16_t ip_crc = 0; UNUSED(ip_crc);
//TODO: Send via Standard IP Framing
//NOTE: The Manual doesn't say much about this area, so assuming the elements are arranged as per the table
//add MAGIC
k = 0;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 8; i++)
m17_ip_frame[k++] = (magic[j] >> 7-i) &1;
}
//add StreamID to ip_frame
for (j = 0; j < 2; j++)
{
for (i = 0; i < 8; i++)
m17_ip_frame[k++] = (sid[j] >> 7-i) &1;
}
//add the current LSF, sans CRC
for (i = 0; i < 224; i++)
m17_ip_frame[k++] = m17_lsf[i];
//add current fsn value
for (i = 0; i < 16; i++)
m17_ip_frame[k++] = (fsn >> 15-i)&1;
//voice and/or data payload
for (i = 0; i < 64; i++)
m17_ip_frame[k++] = v1_bits[i];
//voice and/or data payload
for (i = 0; i < 64; i++)
m17_ip_frame[k++] = v2_bits[i];
//pack current bit array into a byte array for a CRC check
for (i = 0; i < 52; i++)
m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8);
ip_crc = crc16m17(m17_ip_packed, 52);
//add CRC value to the ip frame
for (i = 0; i < 16; i++)
m17_ip_frame[k++] = (ip_crc >> 15-i)&1;
//pack it into the byte array as well
for (i = 52; i < 54; i++)
m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8);
//debug print packed byte output for IP frame
// fprintf (stderr, "\n IP: ");
// for (i = 0; i < 54; i++)
// {
// if ( (i%12)==0) fprintf (stderr, "\n");
// fprintf (stderr, " %02X", m17_ip_packed[i]);
// }
//WIP: Send packed IP frame to UDP port 17000 if opened successfully
if (opts->m17_use_ip == 1)
m17_socket_blaster (opts, state, 54, m17_ip_packed);
//increment lich_cnt, reset on 6
lich_cnt++;