Initial load of CODEC2/FreeDV software and wrapper

This commit is contained in:
Stephen Hicks, N5AC 2014-09-05 21:48:37 -05:00
parent f524f31e45
commit cea38b61ea
204 changed files with 41852 additions and 0 deletions

View file

@ -0,0 +1,81 @@
/* *****************************************************************************
* cmd.h 2014 AUG 31
*
* Header file for cmd_engine.c and cmd_basics.c
*
* date March 30, 2012
* author Stephen Hicks, N5AC
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef CMD_H_
#define CMD_H_
#include "datatypes.h"
#define ACCESS_GUEST 0x0
#define ACCESS_SERIAL 0x1
#define ACCESS_TCP 0x2
#define ACCESS_SERIAL_TCP 0x3
#define SVC_SER 1
#define SVC_TCP 2
#define SVC_BOT 3
#define MAX_ARGC 16
#define MAX_ARGC_STATUS 100
// #define PROMPT "\033[92mSmartSDR> \033[m"
extern char* CMD_UNRECOGNIZED;
extern char* EEPROM_BAD_BYTE;
extern char* EEPROM_TOO_LARGE;
extern char* EEPROM_USAGE;
/* ------------------------------------------------------------------------ *
* Prototypes *
* ------------------------------------------------------------------------ */
unsigned int command (void);
void tokenize (char *line, int *pargc, char **argv, int max_arguments);
//void process_command (int fd, char line[]);
uint32 process_command(char* command_txt);
uint32 cmd_banner();
uint32 cmd_cls(int requester_fd, int argc,char **argv);
uint32 cmd_date(int requester_fd, int argc,char **argv);
uint32 cmd_exit(int requester_fd, int argc,char **argv);
uint32 cmd_help(int requester_fd, int argc, char **argv);
uint32 cmd_slice(int requester_fd, int argc,char **argv);
uint32 cmd_time(int requester_fd, int argc,char **argv);
// uint32 cmd_register(int requester_fd, int argc,char **argv);
uint32 cmd_undefined(int requester_fd, int argc,char **argv);
void get_line(char* line, int maxlen);
char getch(void); // Read 1 character
char getche(void); // Read 1 character with echo
#endif /* CMD_H_ */

View file

@ -0,0 +1,282 @@
/* *****************************************************************************
* cmd_basics.c 2014 AUG 30
*
* Uses header file cmd.h
*
* Basic commands for the command_engine
* Display the sign-on banner
* Clear Screen
* Process Exit
* Display time
* Display date
* Display help
* Display "undefined"
*
*
* \author Terry Gerdes, AB5K
* \author Stephen Hicks, N5AC
* \author Graham / KE9H
*
*******************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "common.h"
#include "main.h"
#include "cmd.h"
#include "main.h"
/* *****************************************************************************
* uint32 cmd_banner(void)
*
* Print a banner
*
*/
uint32 cmd_banner()
{
char *build_date = __DATE__;
char *build_time = __TIME__;
uint32 ip = net_get_ip();
output(ANSI_GREEN "*\n");
output("* This program is free software: you can redistribute it and/or modify\n");
output("* it under the terms of the GNU General Public License as published by\n");
output("* the Free Software Foundation, either version 3 of the License, or\n");
output("* (at your option) any later version.\n");
output("* This program is distributed in the hope that it will be useful,\n");
output("* but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
output("* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
output("* GNU General Public License for more details.\n");
output("* You should have received a copy of the GNU General Public License\n");
output("* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n");
output("* Contact Information:\n");
output("* email: gpl<at>flexradiosystems.com\n");
output("* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728\n*\n");
output("\033[92m");
output("**************************************************************************\r\n");
output("* \r\n");
output("* * * * * * * ****** ****** **** ***** ** ** \r\n");
output("* * * * * * * * * * * * * * * * * * \r\n");
output("* * * * ***** * * ***** **** * * **** * * * \r\n");
output("* ** ** * * * * * * * * * * * * \r\n");
output("* * * * * * ****** * **** * * * * \r\n");
output("*\r\n");
output("* FlexRadio Systems\r\n");
output("* Copyright (C) 2014 FlexRadio Systems. All Rights Reserved.\r\n");
output("* www.flexradio.com\r\n");
output("**************************************************************************\r\n");
//output("\033[32mSoftware version : \033[m%s\r\n", software_version);
output("\033[32mBuild Date & Time: \033[m%s %s\r\n",build_date, build_time);
output("\033[32mIP Address : \033[m%d.%d.%d.%d\r\n", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24);
output("\033[32mType <help> for options\r\n\n\033[m");
return SUCCESS;
}
/* *****************************************************************************
* uint32 cmd_cls(int requester_fd, int argc,char **argv)
*
* HANDLE: command_cls
* ANSI escape sequence to go to home position in screen
* and clear remainder of screen
*/
uint32 cmd_cls(int requester_fd, int argc,char **argv)
{
static char *CLS = "\033[H\033[2J";
write(requester_fd, CLS, strlen(CLS));
return SUCCESS;
}
/* *****************************************************************************
* uint32 cmd_exit(int requester_fd, int argc,char **argv)
*
* Exit the application
*/
uint32 cmd_exit(int requester_fd, int argc,char **argv)
{
const char string1[] = "\n\033[92m73 de WaveForm !!!\033[m\n";
write(requester_fd, string1, strlen(string1));
// if(argc > 1 && tolower(*argv[1]) == 'r')
// end_firmware(power_reboot);
// else
// end_firmware(power_leaveon);
_exit(0);
return SUCCESS;
}
/* *****************************************************************************
* uint32 cmd_time(int requester_fd, int argc,char **argv)
*
* Display the time
*/
uint32 cmd_time(int requester_fd, int argc,char **argv)
{
time_t t = time(NULL);
struct tm time = *localtime(&t);
// client_response(SUCCESS,"%02d:%02d:%02dZ",time.tm_hour,time.tm_min,time.tm_sec);
output("%02d:%02d:%02dZ \n",time.tm_hour,time.tm_min,time.tm_sec);
// char *time_string = 0;
//
// time_string = drv_Bq32000AsciiTime();
// strcat(time_string,"\n");
//
// write(requester_fd, time_string, strlen(time_string));
return SUCCESS;
}
/* *****************************************************************************
* uint32 cmd_date(int requester_fd, int argc,char **argv)
*
* Display the date
*/
uint32 cmd_date(int requester_fd, int argc,char **argv)
{
time_t t = time(NULL);
struct tm time = *localtime(&t);
// client_response(SUCCESS,"%d-%d-%d",time.tm_year+1900,time.tm_mon+1,time.tm_mday);
output("%d-%d-%d \n",time.tm_year+1900,time.tm_mon+1,time.tm_mday);
// char *time_string = 0;
//
// time_string = drv_Bq32000AsciiDatetime();
// strcat(time_string,"\n");
//
// write(requester_fd, time_string, strlen(time_string));
return SUCCESS;
}
//
// Command Description displayed from HELP menu.
//
const char* commandDescriptionBasic[] =
{
0,
"b Display banner",
"banner Display the WaveForm banner",
"cls Clear screen",
"date Display the Date",
"exit Exit the process",
"quit Exit the process",
"time Display the Time",
"help|? View this menu",
0
};
/* *****************************************************************************
* uint32 cmd_help(int requester_fd, int argc, char **argv)
*
* HANDLE: help
*/
uint32 cmd_help(int requester_fd, int argc, char **argv)
{
int i;
i=1;
output("==========================================================\n\r");
while(commandDescriptionBasic[i] != 0)
{
write(requester_fd, commandDescriptionBasic[i], strlen(
commandDescriptionBasic[i]));
output(" %s\n\r", commandDescriptionBasic[i++]);
}
return SUCCESS;
}
/* *****************************************************************************
* uint32 cmd_undefined(int requester_fd, int argc, char **argv)
*
* Undefined
*/
uint32 cmd_undefined(int requester_fd, int argc, char **argv)
{
//debug(LOG_CERROR, TRUE, SL_R_UNKNOWN_COMMAND);
//client_response(SL_UNKNOWN_COMMAND, NULL);
output("I have no idea what you are talking about !!!\n");
return SL_UNKNOWN_COMMAND;
}
uint32 cmd_slice(int requester_fd, int argc, char **argv)
{
uint32 slc = INVALID_SLICE_RX;
if (strcmp(argv[0], "slice") == 0)
{
if(argc < 3)
{
return SL_BAD_COMMAND;
}
// get the slice number
errno = 0;
slc = strtoul(argv[1], NULL, 0);
if(errno)
{
output(ANSI_RED "Unable to parse slice number (%s)\n", argv[1]);
return SL_BAD_COMMAND;
}
if(strncmp(argv[2], "string", strlen("string")) == 0)
{
char* new_string = argv[2]+strlen("string")+1;
freedv_set_string(slc, new_string);
return SUCCESS;
}
}
return SUCCESS;
}

View file

@ -0,0 +1,347 @@
/* *****************************************************************************
* cmd_engine.c
*
* \brief Command Engine - Command processing
*
*
* \author Terry, AB5K
* \author Stephen Hicks, N5AC
* \date 23-AUG-2011
*
* Instructions for adding a new command:
* 1. Add a reference in the "command_defs commands[]" array below
* 2. If help is needed, add a reference to lpszCommandDescriptionBasic[] in the cmd_basics.c file.
*
*******************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/termios.h>
#include "../common.h"
#include "datatypes.h"
#include "cmd.h"
#include "main.h"
static struct termios old, new; // For Terminal IO
//#include "drv_bq32000.h"
//#include "messages.h"
//#include "client_manager.h"
//#include "radio.h"
char *CMD_UNRECOGNIZED = "Unrecognized command \"%s\".\r\n";
// Command Function Pointer called by the interpreter.
typedef uint32 handler(int, int, char**);
static char PrevLine[80];
typedef struct _command_def
{
const char* commandName;
handler *pFunction;
} command_def;
static command_def commands[] =
{
{ 0, cmd_undefined }, // Space Holder
{ "b", cmd_banner }, // Display Banner
{ "banner", cmd_banner }, // Display Banner
{ "cls", cmd_cls }, // Clear Screen
{ "date", cmd_date }, // Print the date/time
{ "exit", cmd_exit }, // Exit the program
{ "help", cmd_help }, // Help Menu
{ "quit", cmd_exit }, // Exit the program
{ "slice", cmd_slice }, // Handle slice changes
{ "time", cmd_time }, // Print the time
{ "?", cmd_help }, // Display Help
{ 0, cmd_undefined }, // Undefined - must be last in the list
};
//long execute_command(int requester_fd, int cmd_num, int argc, char *argv);
// #################################################################
// ##
// ## Command Interpreter
// ##
// #################################################################
unsigned int command(void)
{
char line[80];
char *pLine = line;
get_line(pLine, sizeof(line));
process_command(line);
return (1);
}
uint32 process_command(char* command_txt)
{
uint32 cmd_ret = SUCCESS;
int cmd_num;
int argc;
char *argv[MAX_ARGC + 1]; //Add one extra so we can null terminate the array
tokenize(command_txt, &argc, argv, MAX_ARGC);
if (argc > 0)
{
cmd_num = 1;
while (cmd_num > 0)
{
if ((commands[cmd_num].commandName == 0) || (strcmp(argv[0], commands[cmd_num].commandName) == 0))
{
//Execute the requested command
cmd_ret = commands[cmd_num].pFunction(1, argc, argv);
cmd_num = 0;
}
else
{
cmd_num++;
}
}
}
return cmd_ret;
}
// #################################################################
// ##
// ## void tokenize(char*, int*, char**, max_arguments);
// ##
// ## Breaks a single character string into an array of tokens.
// #################################################################
void tokenize(
char* line, // Input String
int* pargc, // Number of arguments
char** argv, // Array of strings holding tokens
int max_arguments // Maximum Tokens allowed
)
{
BOOL inside_string = FALSE;
BOOL inside_token = FALSE;
char* readp;
*pargc = 0;
// Read through the entire string searching for tokens
for (readp = line; *readp; readp++)
{
// Search for start of token
if (!inside_token)
{
// Ignore white spaces
if ((*readp == ' ') || (*readp == '\t'))
{
;
}
// Start of a new token
else
{
if (*readp == '\"')
{
inside_string = TRUE;
}
else
{
inside_token = TRUE;
argv[*pargc] = readp;
(*pargc)++;
if(*pargc > max_arguments)
break;
}
}
}
// We are inside the token
else
{ // inside token
// Found the end of the token
if ( (!inside_string && ((*readp == ' ') || (*readp == '\t'))) |
(inside_string && (*readp == '\"'))
)
{
inside_string = FALSE;
inside_token = FALSE;
*readp = 0;
}
}
}
// End of input line terminates a token
if (inside_token)
{
*readp = 0;
readp++;
}
argv[*pargc] = 0; // Null-terminate just to be nice
}
// #################################################################
// ##
// ## void command_get_line(char *, int)
// ##
// #################################################################
void get_line(char * line, int maxlen)
{
char *pLine = line;
char *pPrevLine = PrevLine;
char c = 0;
*pLine = 0;
for (;;) {
c = getch();
// Escape Sequences
if (c == '\033') {
while (pLine > line) {
printf("\b \b");
pLine--;
*pLine = 0;
}
c = getch();
if (c == '[') {
c = getch();
if (c == 'A') {
// Restore previous command
pLine = line;
pPrevLine = PrevLine;
while(*pPrevLine) {
*pLine = *pPrevLine;
pLine++;
pPrevLine++;
}
*pLine = 0;
printf("%s",line);
}
}
}
else if ((c == '\n') || (c == '\r')) {
printf("\r\n");
break;
}
// Check for backspace or delete key.
else if ((c == '\b') || (c == 0x7F)) {
if (pLine > line) {
printf("\b \b");
pLine--;
*pLine = 0;
}
}
// Check for escape key or control-U.
else if (c == 0x15) {
while (pLine > line) {
printf("\b \b");
pLine--;
*pLine = 0;
}
}
else if (c > 0) {
printf("%c",c);
*pLine = c;
pLine++;
*pLine = 0;
}
}
*pLine = 0;
pLine = line;
pPrevLine = PrevLine;
while(*pLine) {
*pPrevLine = *pLine;
pLine++;
pPrevLine++;
}
*pPrevLine = 0;
}
/* *****************************************************************************
* getch() and getche() functionality for UNIX,
* based on termios (terminal handling functions)
*
* This code snippet was written by Wesley Stessens (wesley@ubuntu.com)
* It is released in the Public Domain.
*/
/* Initialize new terminal i/o settings */
void initTermios(int echo) {
int n = tcgetattr(0, &old); /* grab old terminal i/o settings */
if (n == -1) return;
new = old; /* make new settings same as old settings */
new.c_lflag &= ~ICANON; /* disable buffered i/o */
new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void) {
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo) {
char ch;
initTermios(echo);
ch = (char)getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
char getch(void) {
return getch_(0);
}
/* Read 1 character with echo */
char getche(void) {
return getch_(1);
}

View file

@ -0,0 +1,61 @@
/* *****************************************************************************
* complex.h
*
* \date Mar 31, 2012
* \author Bob / N4HY
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include <math.h>
#include "datatypes.h"
typedef struct _complex {
float real; // left
float imag; // right
} Complex;
#define CReal(x) ((x.real))
#define CImag(x) ((x.imag))
extern Complex Cplx(float x, float y);
extern Complex ComplexAdd(Complex x, Complex y);
extern Complex ComplexSub(Complex x, Complex y);
extern Complex ComplexMul(Complex x, Complex y);
extern Complex ComplexDiv(Complex x, Complex y);
extern Complex ComplexScl(Complex x, float scl);
extern Complex ComplexCjg(Complex x);
extern float ComplexPwr(Complex x);
extern float ComplexMag(Complex x);
#endif /* COMPLEX_H_ */

View file

@ -0,0 +1,65 @@
/* *****************************************************************************
* datatypes.h
*
* datatypes definition file
*
*
* \date Sep 15, 2011
* \author Eric
*
* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _DATATYPES_H
#define _DATATYPES_H
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef signed long long int64;
typedef uint8 BOOL;
/// VITA-49 format frequency data
typedef int64 VITAfrequency;
typedef int16 VITAfrequency_trunc;
typedef int32 VITAdb;
typedef int16 VITAdb_trunc;
typedef uint32 packedVITAcalPoint;
typedef int32 VITAtemp;
typedef int16 VITAtemp_trunc;
typedef uint32 ant_port_id_type;
#define TRUE (uint32)1
#define FALSE (uint32)0
#define INVALID -1
#endif // _DATATYPES_H

View file

@ -0,0 +1,320 @@
/* *****************************************************************************
* discovery_client.c
*
* \brief Discovery Client - Receives and parses discovery packets
*
*
* \author Eric Wachsmann, KE5DTO
* \date 2014-09-01
*
*******************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ***************************************************************************/
#include <stdio.h>
#include <stdlib.h> // for malloc
#include <string.h> // for memset
#include <sys/socket.h>
#include <netinet/in.h> // for htonl, htons, IPPROTO_UDP
#include <pthread.h>
#include <errno.h> // for errno
#include <unistd.h>
#include "common.h"
#include "discovery_client.h"
#include "cmd.h" // for tokenize
#include "io_utils.h"
static int _dc_sock;
static pthread_t _dc_thread;
static BOOL _dc_abort = FALSE;
void printRadio(Radio radio)
{
output("discovery_protocol_version=%s model=%s serial=%s version=%s nickname=%s callsign=%s ip=%s port=%s status=%s\n",
radio->discovery_protocol_version,
radio->model,
radio->serial,
radio->version,
radio->nickname,
radio->callsign,
radio->ip,
radio->port,
radio->status);
}
char* protocol_version;
char* model;
char* serial;
char* version;
char* nickname;
char* callsign;
char* ip;
char* port;
char* status;
static void _dc_RadioFound(Radio radio)
{
if(getIP(radio->ip) == ntohl(net_get_ip()))
{
output("Radio found");
// yes -- connect and stop looking for more radios
// TODO: connect
// start a keepalive to keep the channel open and know when it dies
uint32 result = register_mode();
// quick and dirty fail for now
if (result != SUCCESS) exit(1);
tc_startKeepalive();
usleep(250000);
hal_Listener_Init();
dc_Exit();
}
// print the content of the object
//printRadio(radio);
// because the radio object is malloc'ed, we need to recover the memory
safe_free(radio);
radio = 0;
}
static void _dc_ListenerParsePacket(uint8* packet, int32 length, struct sockaddr_in* sender)
{
//output("_dc_ListenerParsePacket\n");
// is this packet long enough to inspect for VITA header info?
if(length < 16)
{
// no -- discard the packet
//output("_dc_ListenerParsePacket: packet too short\n");
return;
}
// cast the incoming packet as a VITA packet
VitaIFData p = (VitaIFData)packet;
// does this packet have our OUI?
if(htonl(p->class_id_h) != 0x00001C2D)
{
// no -- discard this packet
//output("_dc_ListenerParsePacket: wrong OUI (0x%08X)\n", htonl(p->class_id_h));
return;
}
// is this packet an extended data packet?
if((p->header & VITA_HEADER_PACKET_TYPE_MASK) != VITA_PACKET_TYPE_EXT_DATA_WITH_STREAM_ID)
{
// no -- discard this packet
//output("_dc_ListenerParsePacket: wrong packet type (0x%08X)\n", p->header & VITA_HEADER_PACKET_TYPE_MASK);
return;
}
// is this packet marked as a SL_VITA_DISCOVERY_CLASS?
if((htonl(p->class_id_l) & VITA_CLASS_ID_PACKET_CLASS_MASK) != 0xFFFF)
{
// no -- discard this packet
//output("_dc_ListenerParsePacket: wrong packet class (0x%04X)\n", p->class_id_l & VITA_CLASS_ID_PACKET_CLASS_MASK);
return;
}
// if we made it this far, then we can safely assume this is a
// discovery packet and we will attempt to split the payload up
// similar to a command on spaces and parse the data
int argc, i;
char *argv[MAX_ARGC + 1]; //Add one extra so we can null terminate the array
// split the payload string up
tokenize((char*)p->payload, &argc, argv, MAX_ARGC);
//output("_dc_ListenerParsePacket: payload: %s\n", p->payload);
//output("_dc_ListenerParsePacket: tokenize argc=%u\n", argc);
Radio radio = (Radio)safe_malloc(sizeof(radioType));
if(!radio)
{
output("_dc_ListenerParsePacket: Out of memory!\n");
return;
}
// clear the newly allocated memory
memset(radio, 0, sizeof(radioType));
// for each token, process the string
for(i=0; i<argc; i++)
{
if(strncmp(argv[i], "discovery_protocol_version", strlen("discovery_protocol_version")) == 0)
radio->discovery_protocol_version = argv[i]+strlen("discovery_protocol_version=");
else if(strncmp(argv[i], "model", strlen("model")) == 0)
radio->model = argv[i]+strlen("model=");
else if(strncmp(argv[i], "serial", strlen("serial")) == 0)
radio->serial = argv[i]+strlen("serial=");
else if(strncmp(argv[i], "version", strlen("version")) == 0)
radio->version = argv[i]+strlen("version=");
else if(strncmp(argv[i], "nickname", strlen("nickname")) == 0)
radio->nickname = argv[i]+strlen("nickname=");
else if(strncmp(argv[i], "callsign", strlen("callsign")) == 0)
radio->callsign = argv[i]+strlen("callsign=");
else if(strncmp(argv[i], "ip", strlen("ip")) == 0)
radio->ip = argv[i]+strlen("ip=");
else if(strncmp(argv[i], "port", strlen("port")) == 0)
radio->port = argv[i]+strlen("port=");
else if(strncmp(argv[i], "status", strlen("status")) == 0)
radio->status = argv[i]+strlen("status=");
}
// did we get at least an IP, port, and version?
if(radio->ip != 0 && radio->port != 0 && radio->version != 0)
{
// yes -- report the radio as found
_dc_RadioFound(radio);
}
}
static struct timeval timeout;
//! Allocates a buffer and receives one packet.
//! /param buffer Buffer to be allocated and populated with packet data
//! /returns Number of bytes read if successful, otherwise an error (recvfrom)
static BOOL _dc_ListenerRecv(uint8* buffer, int32* len, struct sockaddr_in* sender_addr)
{
//output("_dc_ListenerRecv\n");
uint32 addr_len = sizeof(struct sockaddr_in);
// we will wait up to 1 second for data in case someone is trying to abort us
timeout.tv_sec = 1;
timeout.tv_usec = 0;
fd_set socks;
FD_ZERO(&socks);
FD_SET(_dc_sock, &socks);
// see if there is data in the socket (but timeout if none)
select(_dc_sock + 1, &socks, NULL, NULL, &timeout);
if (FD_ISSET(_dc_sock, &socks))
{
// yes there is data -- get it
*len = recvfrom(_dc_sock, buffer, ETH_FRAME_LEN, 0, (struct sockaddr*)sender_addr, &addr_len);
//precisionTimerLap("HAL Listener Recv");
if(*len < 0)
output("_dc_ListenerRecv: recvfrom returned -1 errno=%08X\n", errno);
//else
//output("_hal_ListenerRecv: Error len=%d sender=%s:%u\n", len, inet_ntoa(sender_addr.sin_addr), htons(sender_addr.sin_port));
// TODO: May need to filter here to handle security (packet injection)
return TRUE;
}
*len = 0;
return FALSE;
}
static void* _dc_ListenerLoop(void* param)
{
//printf("_dc_ListenerLoop\n");
struct sockaddr_in sender;
uint8 buf[ETH_FRAME_LEN];
while(!_dc_abort)
{
// get some data
int32 length = 0;
BOOL success = FALSE;
while (!success && !_dc_abort)
{
memset(&sender,0,sizeof(struct sockaddr_in));
memset(&buf,0,ETH_FRAME_LEN);
success = _dc_ListenerRecv(buf, &length, &sender);
}
if (!_dc_abort)
{
if(length == 0) // socket has been closed
{
output("_dc_ListenerLoop error: socket closed\n");
break;
}
if(length < 0)
{
output("_dc_ListenerLoop error: loop stopped\n");
break;
}
// length was reasonable -- lets try to parse the packet
//precisionTimerLap("HAL Listener Parse Packet");
_dc_ListenerParsePacket(buf, length, &sender);
}
}
return NULL;
}
void dc_Init(void)
{
output("Discovery Client Init: Opening socket");
int true = TRUE;
if((_dc_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
output("...failed! (socket call returned -1)\n");
return;
}
// set up destination address
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // this is where we could limit to one IP
addr.sin_port=htons(DISCOVERY_PORT);
/* If you're running on the same box as the smartsdr firmware this is necessary so
* that both processes can bind to the same VITA port
*/
/*int32 ret_val =*/ setsockopt(_dc_sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true));
if (errno)
{
output("error with reuse option: errno=%d",errno);
}
// bind the socket to the port and/or IP
output("...binding");
errno = 0;
if(bind(_dc_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
output("...failed! (bind call returned -1: errno:%d)\n", errno);
return;
}
output("\n");
// start the listener thread
pthread_create(&_dc_thread, NULL, &_dc_ListenerLoop, NULL);
}
void dc_Exit(void)
{
_dc_abort = TRUE;
}

View file

@ -0,0 +1,54 @@
/* *****************************************************************************
* discovery_client.h
*
* \brief Discovery Client - Receives and parses discovery packets
*
*
* \author Eric Wachsmann, KE5DTO
* \date 2014-09-01
*
*******************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef DISCOVERY_CLIENT_H_
#define DISCOVERY_CLIENT_H_
typedef struct _radio
{
char* discovery_protocol_version;
char* model;
char* serial;
char* version;
char* nickname;
char* callsign;
char* ip;
char* port;
char* status;
} radioType, *Radio;
void dc_Init(void);
void dc_Exit(void);
void printRadio(Radio radio);
#endif // DISCOVERY_CLIENT_H_

View file

@ -0,0 +1,133 @@
/* *****************************************************************************
* hal_buffer.c
*
* Buffer structures to support getting samples from the right stream to
* the DSP.
*
*
* \date 29-MAR-2012
* \author Eric & Steve
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset
#include <math.h>
#include "common.h"
//#include "platform.h"
#include "hal_buffer.h"
BufferDescriptor hal_BufferRequest(uint32 num_samples, uint32 sample_size)
{
// allocate memory for the new object
// BufferDescriptor buf = (BufferDescriptor)safe_malloc(sizeof(buffer_descriptor));
BufferDescriptor buf = (BufferDescriptor)safe_malloc(sizeof(buffer_descriptor)); // substitute non-thread-safe malloc
// debug(LOG_DEV, TRUE, "\033[32m+ buf_desc alloc: %08X %04X\033[m", (uint32)buf, sizeof(buffer_descriptor));
if(!buf)
{
// debug(LOG_DEV, TRUE, "Error allocating buffer descriptor (size=%u)", sizeof(buffer_descriptor));
return 0;
}
// clear memory of new descriptor object
memset(buf, 0, sizeof(buffer_descriptor));
// initialize size and allocate buffer
buf->num_samples = num_samples;
buf->sample_size = sample_size;
// buf->buf_ptr = safe_malloc(num_samples * sample_size);
buf->buf_ptr = safe_malloc(num_samples * sample_size); // substitute non-thread-safe malloc
// debug(LOG_DEV, TRUE, "\033[35m+ buf alloc: %08X, %04X\033[m", (uint32)buf->buf_ptr, num_samples * sample_size);
if(!buf->buf_ptr)
{
// debug(LOG_DEV, TRUE, "Error allocating buffer descriptor (size=%u)", num_samples * sample_size);
// safe_free(buf); // prevent memory leak
free(buf); // un-thread-safe free
buf = NULL;
return NULL;
}
// clear memory of new buffer object
memset(buf->buf_ptr, 0, num_samples * sample_size);
return buf;
}
void hal_BufferRelease(BufferDescriptor *buf_desc)
{
if(*buf_desc)
{
if((*buf_desc)->buf_ptr != NULL)
{
// debug(LOG_DEV, TRUE, "\033[35m- releasing buf: %08X\033[m", (uint32)(*buf_desc)->buf_ptr);
// safe_free((*buf_desc)->buf_ptr);
free((*buf_desc)->buf_ptr); // un-thread-safe free
(*buf_desc)->buf_ptr = NULL;
}
// debug(LOG_DEV, TRUE, "\033[32m- releasing buf_desc: %08X\033[m", (uint32)*buf_desc);
// safe_free(*buf_desc);
free(*buf_desc); // un-thread-safe free
*buf_desc = NULL;
}
}
BufferDescriptor hal_BufferClone(BufferDescriptor buf)
{
BufferDescriptor new_buf = hal_BufferRequest(buf->num_samples, buf->sample_size);
if(!new_buf)
{
// debug(LOG_DEV, TRUE, "Error allocating new buffer");
return 0;
}
// copy member variables
new_buf->stream_id = buf->stream_id;
new_buf->timestamp_int = buf->timestamp_int;
new_buf->timestamp_frac_h = buf->timestamp_frac_h;
new_buf->timestamp_frac_l = buf->timestamp_frac_l;
// copy the actual buffer
memcpy(new_buf->buf_ptr, buf->buf_ptr, buf->num_samples*buf->sample_size);
return new_buf;
}
void hal_BufferPrint(BufferDescriptor buf_desc)
{
int i;
for(i=0; i<16; i++)
printf("%.2f ", ((float*)buf_desc->buf_ptr)[i]);
}
float hal_BufferMag(BufferDescriptor buf_desc)
{
int i;
float sum = 0.0f;
for(i=0; i<buf_desc->num_samples*2; i++)
sum += fabs(((float*)buf_desc->buf_ptr)[i]);
return sum;
}

View file

@ -0,0 +1,83 @@
/* *****************************************************************************
* hal_buffer.h
*
* Buffer structures to support getting samples from the right stream to
* the DSP.
*
* \date Mar 29, 2012
* \author Eric & Steve
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _BUFFER_H
#define _BUFFER_H
#include <pthread.h>
#include "datatypes.h"
#pragma pack(4)
///@{
//! buffer_descriptor
//! \brief describes a VITA-49 buffer received for processing and decomposed
typedef struct _buffer_descriptor
{
//! stream id showing where this buffer came from
uint32 stream_id;
//! number of samples stored in the buffer
uint32 num_samples; // in frames
//! size in bytes of the sample
uint32 sample_size;
//! pointer to the buffer containing the samples
void* buf_ptr; // pointer to the actual buffer
//! integer timestamp for the first sample in the buffer (see VITA-49 spec)
uint32 timestamp_int;
//! high 32-bits of fractional portion of the timestamp
uint32 timestamp_frac_h;
//! low 32-bits of the fractional portion of the timestamp
uint32 timestamp_frac_l;
//! pointer to next buffer descriptor
struct _buffer_descriptor* next;
//! pointer to previous buffer descriptor
struct _buffer_descriptor* prev;
} buffer_descriptor, *BufferDescriptor;
///@}
#pragma pack()
//! Requests a Buffer to be used in the DSP
//! \param size Number of frames to allocate
BufferDescriptor hal_BufferRequest(uint32 size, uint32 sample_size);
//! To be called once finished with the buffer (cleanup)
//! \param buf Buffer that is no longer in use
void hal_BufferRelease(BufferDescriptor *buf);
//! Does a deep copy of the buffer descriptor including the buffer
//! \param buf The buffer descriptor to copy
BufferDescriptor hal_BufferClone(BufferDescriptor buf);
void hal_BufferPrint(BufferDescriptor buf_desc);
float hal_BufferMag(BufferDescriptor buf_desc);
#endif // _BUFFER_H

View file

@ -0,0 +1,568 @@
///*! \file hal_listener.c
// * \brief Listener for VITA-49 packets
// *
// * \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 28-MAR-2012
// * \author Eric & Steve
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <string.h> // for memset
#include <sys/socket.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <netinet/in.h> // for htonl, htons
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h> // for errno
#include <unistd.h> // for usleep
#include <netdb.h>
// #define LOG_MODULE LOG_MODULE_HAL_LISTENER
#include "vita.h"
#include "hal_vita.h"
#include "common.h"
#include "stream.h"
#include "vita_output.h"
#include "hal_buffer.h"
#include "sched_waveform.h"
extern int errno;
// static local variables
static int fpga_sock;
static BOOL hal_listen_abort;
static pthread_t _hal_listen_thread;
//static Thread _hal_counter_thread;
// prototypes
static void _hal_ListenerParsePacket(uint8* packet, int32 length, struct sockaddr_in* sender);
static void _hal_ListenerProcessWaveformPacket(VitaIFData p, uint32 stream_id, int32 length, struct sockaddr_in* sender);
#define MAX_COUNTED_STREAMS 100
#define COUNTER_INTERVAL_MS 1000
//static stream_count_type current_counters[MAX_COUNTED_STREAMS];
//static stream_count_type report_counters[MAX_COUNTED_STREAMS];
//static uint32 _end_count, _report_count;
//void HAL_update_count(uint32 stream_id, uint32 class_id_h, uint32 class_id_l, uint32 size, uint32 status, StreamDirection direction, ShortStreamType strm_type, uint32 ip, uint16 port)
//{
// acquireLocalLock(_counter_lock, LOCAL_LOCK_WRITE);
// int i;
// for (i = 0; i < _end_count; i++)
// {
// if (stream_id == current_counters[i].stream_id &&
// class_id_h == current_counters[i].class_id_h &&
// class_id_l == current_counters[i].class_id_l &&
// direction == current_counters[i].direction &&
// strm_type == current_counters[i].stream_type &&
// ip == current_counters[i].ip &&
// port == current_counters[i].port)
// {
// current_counters[i].count++;
// current_counters[i].size += size;
// goto end;
// }
// }
// if (_end_count == MAX_COUNTED_STREAMS) return;
// current_counters[_end_count].direction = direction;
// current_counters[_end_count].stream_type = strm_type;
// current_counters[_end_count].class_id_h = class_id_h;
// current_counters[_end_count].class_id_l = class_id_l;
// current_counters[_end_count].count = 1;
// current_counters[_end_count].size = size;
// current_counters[_end_count].stream_id = stream_id;
// current_counters[_end_count].status = status;
// current_counters[_end_count].ip = ip;
// current_counters[_end_count].port = port;
// _end_count++;
//
//end:
// releaseLocalLock(_counter_lock);
//}
//static void _hal_reset_count(void)
//{
// int i;
//
//// acquireLocalLock(_print_lock, LOCAL_LOCK_WRITE);
//// acquireLocalLock(_counter_lock, LOCAL_LOCK_WRITE);
// // make a backup copy of the counters for reporting
// memcpy(report_counters, current_counters, sizeof(stream_count_type)*_end_count);
// _report_count = _end_count;
//
// for (i = 0; i < _report_count; i++)
// {
// report_counters[i].speed = (float)report_counters[i].size / COUNTER_INTERVAL_MS * 0.008;
// report_counters[i].count = (int)(report_counters[i].count * 1000 / COUNTER_INTERVAL_MS);
// report_counters[i].printed = FALSE;
// }
// // clear out the current current_counters
// memset(current_counters, 0, sizeof(stream_count_type)*_end_count);
// _end_count = 0;
// releaseLocalLock(_counter_lock);
// releaseLocalLock(_print_lock);
//}
//static void* _hal_counter_loop(void* param)
//{
// // show that we are running
// thread_setRunning(_hal_counter_thread);
//
// while (!hal_listen_abort)
// {
// // sleep for the designated time
// usleep (COUNTER_INTERVAL_MS * 1000);
// _hal_reset_count();
// }
//
// destroyLocalLock(&_counter_lock);
// thread_done(_hal_counter_thread);
// return NULL;
//}
char* _hal_getStreamType(ShortStreamType strm_type)
{
switch (strm_type)
{
case FFT: return "FFT";
case MMX: return "MMX";
case AUD: return "AUD";
case MET: return "MET";
case DSC: return "DSC";
case IQD: return "IQD";
case TXD: return "TXD";
case PAN: return "PAN";
case WFL: return "WFL";
case WFM: return "WFM";
case XXX: return "---";
}
return "---";
}
//
//void _hal_showStreamLine(uint32 i)
//{
// char* status;
// switch(report_counters[i].status)
// {
// case HAL_STATUS_PROCESSED: status = "\033[32mProcessing \033[m"; break;
// case HAL_STATUS_INVALID_OUI: status = "\033[91mInvalid OUI \033[m"; break;
// case HAL_STATUS_NO_DESC: status = "\033[33mNo Descriptor \033[m"; break;
// case HAL_STATUS_UNSUPPORTED_SAMP: status = "\033[31mUnsupported MMX Rate\033[m"; break;
// case HAL_STATUS_UNSUPPORTED_FFT: status = "\033[31mUnsupported FFT Rate\033[m"; break;
// case HAL_STATUS_BAD_TYPE: status = "\033[33mBad Type \033[m"; break;
// case HAL_STATUS_OUTPUT_OK: status = "\033[32mPacket Sent OK \033[m"; break;
// case HAL_STATUS_TX_SKIP: status = "\033[32mSkipping, in TX \033[m"; break;
// case HAL_STATUS_TX_ZERO: status = "\033[32mSending Zero, in TX \033[m"; break;
// case HAL_STATUS_WFM_SIZE_WRONG: status = "\033[91mWFM packet size bad \033[m"; break;
// case HAL_STATUS_WFM_NO_STREAM: status = "\033[33mNo WFM stream \033[m"; break;
// case HAL_STATUS_UNK_STREAM: status = "\033[33mUnknown Stream ID \033[m"; break;
// default: status = "\033[35mUnknown \033[m"; break;
// }
//
//// if (report_counters[i].direction == INPUT)
//// {
//// output("%s %s 0x%08X 0x%08X %08X %5u %s %6.3f Mbps\n",
//// (report_counters[i].direction == INPUT) ? " IN" : "OUT",
//// _hal_getStreamType(report_counters[i].stream_type),
//// report_counters[i].stream_id,
//// report_counters[i].class_id_h,
//// report_counters[i].class_id_l,
//// report_counters[i].count,
//// status,
//// report_counters[i].speed);
//// }
//// else
// {
// uint32 ip = htonl(report_counters[i].ip);
// uint16 port = htons(report_counters[i].port);
// if (ip == 0xAC1E0102)
// {
// output("%s %s 0x%08X 0x%08X %08X %5u %s %6.3f Mbps \033[33mFPGA\033[m\n",
// (report_counters[i].direction == INPUT) ? " IN" : "OUT",
// _hal_getStreamType(report_counters[i].stream_type),
// report_counters[i].stream_id,
// report_counters[i].class_id_h,
// report_counters[i].class_id_l,
// report_counters[i].count,
// status,
// report_counters[i].speed);
// }
// else
// {
// output("%s %s 0x%08X 0x%08X %08X %5u %s %6.3f Mbps %u.%u.%u.%u:%u ",
// (report_counters[i].direction == INPUT) ? " IN" : "OUT",
// _hal_getStreamType(report_counters[i].stream_type),
// report_counters[i].stream_id,
// report_counters[i].class_id_h,
// report_counters[i].class_id_l,
// report_counters[i].count,
// status,
// report_counters[i].speed,
// ip>>24, (ip>>16)&0xFF, (ip>>8)&0xFF, ip&0xFF, port);
//
// //output("(%s)",getHost(ip));
// //char* program = client_getClientProgram(htonl(report_counters[i].ip), htons(report_counters[i].port));
// //if (program != NULL) output(" %s",program);
// output ("\n");
// }
// }
//}
//
//void hal_showStreamReport(void)
//{
// int i;
// float input_total = 0, output_total = 0;
// uint32 input_packet_rate = 0, output_packet_rate = 0;
//
//// acquireLocalLock(_print_lock, LOCAL_LOCK_WRITE);
//
// output("\033[96mDIR TYP Stream ID Class ID Count Status Rate (includes VITA o/h)\033[m\n");
//
// // output sorted list of input streams
// uint32 min_stream_id;
// do
// {
// min_stream_id = 0xFFFFFFFF;
// for (i = 0; i < _report_count; i++)
// {
// if (report_counters[i].direction == INPUT &&
// !report_counters[i].printed &&
// report_counters[i].stream_id < min_stream_id)
// {
// min_stream_id = report_counters[i].stream_id;
// }
// }
// for (i = 0; i < _report_count; i++)
// {
// if ((report_counters[i].stream_id == min_stream_id) && !report_counters[i].printed)
// {
// _hal_showStreamLine(i);
// input_total += report_counters[i].speed;
// input_packet_rate += report_counters[i].count;
// report_counters[i].printed = TRUE;
// }
// }
// }
// while (min_stream_id != 0xFFFFFFFF);
//
//
// uint32 percent = (uint32)(input_total + 0.5);
// output("\033[32mAggregate input rate: \033[m%u packets/s, %.3f Mbps (%u%%)\n\n",input_packet_rate,input_total,percent);
//
//
// do
// {
// min_stream_id = 0xFFFFFFFF;
// for (i = 0; i < _report_count; i++)
// {
// if (report_counters[i].direction == OUTPUT &&
// !report_counters[i].printed &&
// report_counters[i].stream_id < min_stream_id)
// {
// min_stream_id = report_counters[i].stream_id;
// }
// }
// for (i = 0; i < _report_count; i++)
// {
// if (report_counters[i].stream_id == min_stream_id && !report_counters[i].printed)
// {
// _hal_showStreamLine(i);
// output_total += report_counters[i].speed;
// output_packet_rate += report_counters[i].count;
// report_counters[i].printed = TRUE;
// }
// }
// }
// while (min_stream_id != 0xFFFFFFFF);
//
// // clear the print flags
// for (i = 0; i < _report_count; i++)
// {
// report_counters[i].printed = FALSE;
// }
//
//// releaseLocalLock(_print_lock);
//
// output("\033[32mAggregate output rate: \033[m%u packets/s, %.3f Mbps\n",output_packet_rate,output_total);
//}
//
//float hal_getStreamRate(uint32 stream_id)
//{
// int i;
// for (i = 0; i < _report_count; i++)
// {
// if (report_counters[i].stream_id == stream_id)
// {
// return report_counters[i].speed;
// }
// }
// return 0.0f;
//
//}
static void _hal_ListenerProcessWaveformPacket(VitaIFData p, uint32 stream_id, int32 length, struct sockaddr_in* sender)
{
/*TODO: Make the buffer size a define*/
BufferDescriptor buf_desc;
buf_desc = hal_BufferRequest(HAL_RX_BUFFER_SIZE, sizeof(Complex));
// BufferDescriptor buf_desc = s->buf_desc_ptr;
//
// if(buf_desc == NULL) {
// output( "buf_desc was null. race?)");
// return;
// }
// /* set timestamp for start of buffer if necessary */
if(!buf_desc->timestamp_int)
{
buf_desc->timestamp_int = htonl(p->timestamp_int);
buf_desc->timestamp_frac_h = htonl(p->timestamp_frac_h);
buf_desc->timestamp_frac_l = htonl(p->timestamp_frac_l);
}
// calculate number of samples in the buffer
uint32 packet_frames = hal_VitaIFPacketPayloadSize(p)/buf_desc->sample_size;
// verify the frames fit in the actual packet size
if(packet_frames * 8 > length - 28)
{
output( "\033[91mIncoming packet size (%d) smaller than vita header claims\033[m\n", length);
//HAL_update_count(htonl(p->stream_id), htonl(p->class_id_h), htonl(p->class_id_l),length,HAL_STATUS_WFM_SIZE_WRONG, INPUT, AUD, sender->sin_addr.s_addr, sender->sin_port);
hal_BufferRelease(&buf_desc);
return;
}
//output("Packet frames = %d\n", packet_frames);
//HAL_update_count(buf_desc->stream_id, htonl(p->class_id_h), htonl(p->class_id_l), length,HAL_STATUS_PROCESSED, INPUT, AUD, sender->sin_addr.s_addr, sender->sin_port);
// figure out how many frames it would take to fill the buffer
//uint32 buf_frames_left = buf_desc->num_samples - s->sample_count;
// figure out how many frames to copy to the buffer
uint32 frames_to_copy = packet_frames;
//output("Buffer mag before memcpy %.6g\n", hal_BufferMag(buf_desc));
// copy the frames from the packet into the buffer
memcpy(buf_desc->buf_ptr, // dest
p->payload, // src
frames_to_copy * buf_desc->sample_size); // number of bytes to copy
//output("Buffer mag after memcpy %.6g\n", hal_BufferMag(buf_desc));
/* We now require a full frame to arrive in each packet so we don't handle segmentation of data across packets */
buf_desc->stream_id = ntohl(p->stream_id);
// send off the buffer to processor that handles giving it to the correct waveform
sched_waveform_Schedule(buf_desc);
}
static struct timeval timeout;
//! Allocates a buffer and receives one packet.
//! /param buffer Buffer to be allocated and populated with packet data
//! /returns Number of bytes read if successful, otherwise an error (recvfrom)
static BOOL _hal_ListenerRecv(uint8* buffer, int32* len, struct sockaddr_in* sender_addr)
{
uint32 addr_len = sizeof(struct sockaddr_in);
// we will wait up to 1 second for data in case someone is trying to abort us
timeout.tv_sec = 1;
timeout.tv_usec = 0;
fd_set socks;
FD_ZERO(&socks);
FD_SET(fpga_sock, &socks);
// see if there is data in the socket (but timeout if none)
select(fpga_sock + 1, &socks, NULL, NULL, &timeout);
if (FD_ISSET(fpga_sock, &socks))
{
// yes there is data -- get it
*len = recvfrom(fpga_sock, buffer, ETH_FRAME_LEN, 0, (struct sockaddr*)sender_addr, &addr_len);
//precisionTimerLap("HAL Listener Recv");
if(*len < 0)
output("_hal_ListenerRecv: recvfrom returned -1 errno=%08X\n", errno);
//else
//output("_hal_ListenerRecv: Error len=%d sender=%s:%u\n", len, inet_ntoa(sender_addr.sin_addr), htons(sender_addr.sin_port));
// TODO: May need to filter here to handle security (packet injection)
return TRUE;
}
*len = 0;
return FALSE;
}
static void* _hal_ListenerLoop(void* param)
{
// show that we are running
// thread_setRunning(_hal_listen_thread);
struct sockaddr_in sender;
uint8 buf[ETH_FRAME_LEN];
while(!hal_listen_abort)
{
// get some data
int32 length = 0;
BOOL success = FALSE;
while (!success && !hal_listen_abort)
{
memset(&sender,0,sizeof(struct sockaddr_in));
memset(&buf,0,ETH_FRAME_LEN);
success = _hal_ListenerRecv(buf, &length, &sender);
}
if (!hal_listen_abort)
{
if(length == 0) // socket has been closed
{
output("_hal_ListenerLoop error: socket closed\n");
break;
}
if(length < 0)
{
output("_hal_ListenerLoop error: loop stopped\n");
break;
}
// length was reasonable -- lets try to parse the packet
//precisionTimerLap("HAL Listener Parse Packet");
_hal_ListenerParsePacket(buf, length, &sender);
}
}
//thread_done(_hal_listen_thread);
return NULL;
}
static void _hal_ListenerParsePacket(uint8* packet, int32 length, struct sockaddr_in* sender)
{
//Stream s;
// make sure packet is long enough to inspect for VITA header info
if(length < 28)
return;
VitaIFData p = (VitaIFData) packet;
// does this packet have our OUI?
if(htonl(p->class_id_h) != 0x00001C2D)
{
//HAL_update_count(htonl(p->stream_id), htonl(p->class_id_h), htonl(p->class_id_l),length,HAL_STATUS_INVALID_OUI, INPUT, XXX, sender->sin_addr.s_addr, sender->sin_port);
return;
}
// verify the length of the packet matches the VITA header
//uint32 vita_length = (htonl(p->header) & VITA_HEADER_PACKET_SIZE_MASK) * 4;
/*
if(vita_length != length - vitaPacketOffset)
{
output("_hal_ListenerParsePacket: Vita packet size (%u*4=%u) and packet length (%u) do not match\n",
vita_length/4, vita_length, length - vitaPacketOffset);
return;
}
*/
// what kind of Vita Packet is this?
//if(!(htonl(p->header) & VITA_HEADER_PACKET_TYPE_MASK) == VITA_PACKET_TYPE_IF_DATA_WITH_STREAM_ID)
// output("_hal_ListenerParsePacket: received ext data packet from unexpected packet tpe (0x%08X)\n", htonl(p->header) & VITA_HEADER_PACKET_TYPE_MASK);
// lockBits locks;
switch(htonl(p->stream_id) & STREAM_BITS_MASK)
{
case STREAM_BITS_WAVEFORM | STREAM_BITS_IN:
//output("Received a STREAM_BITS_WAVEFORM | STREAM_BITS_IN buffer!!! wooo!!!!");
// if ( s->buf_desc_ptr == NULL)
// {
// HAL_update_count(htonl(p->stream_id), htonl(p->class_id_h), htonl(p->class_id_l),length,HAL_STATUS_NO_DESC, INPUT, WFM, sender->sin_addr.s_addr, sender->sin_port);
// }
// else
// {
_hal_ListenerProcessWaveformPacket(p, p->stream_id, length, sender);
// }
break;
default:
// HAL_update_count(htonl(p->stream_id), htonl(p->class_id_h), htonl(p->class_id_l),length,HAL_STATUS_UNK_STREAM, INPUT, XXX, sender->sin_addr.s_addr, sender->sin_port);
output("Undefined stream in %08X", p->stream_id);
break;
}
}
void hal_Listener_Init(void)
{
output("Vita Listener Init: Opening socket");
if((fpga_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
output("...failed! (socket call returned -1)\n");
return;
}
// set up destination address
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // this is where we could limit to one IP
addr.sin_port=htons(VITA_49_PORT);
// bind the socket to the port and/or IP
output("...binding");
if(bind(fpga_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
output("...failed! (bind call returned -1)\n");
return;
}
output("\n");
_hal_listen_thread = (pthread_t) NULL;
pthread_create(&_hal_listen_thread, NULL, &_hal_ListenerLoop, NULL);
// _hal_counter_thread = NULL;
// _hal_counter_thread = thread_add(locks, "HALSTATS", "Monitors System I/O", _hal_counter_loop, SCHED_OTHER, 0);
// if (action == THREAD_START)
// {
// thread_start(locks, _hal_counter_thread, NULL);
// }
}

View file

@ -0,0 +1,115 @@
///*! \file hal_listener.h
// * \brief Listener for VITA-49 packets
// *
// * \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date Mar 28, 2012
// * \author Eric & Steve
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _LISTENER_H
#define _LISTENER_H
#include "../common.h"
// #include "hal_display.h"
// #include "display_list.h"
#include "datatypes.h"
#define HAL_RX_BUFFER_SIZE 128
#define HAL_TX_BUFFER_SIZE HAL_RX_BUFFER_SIZE
#define HAL_SAMPLE_SIZE sizeof(Complex);
enum STREAM_DIRECTION
{
INPUT = 1,
OUTPUT = 2
};
typedef enum STREAM_DIRECTION StreamDirection;
enum STREAM_TYPEX
{
FFT = 1,
MMX = 2,
IQD = 3,
AUD = 4,
MET = 5,
DSC = 6,
TXD = 7,
PAN = 8,
WFL = 9,
WFM = 10,
XXX = 99
};
typedef enum STREAM_TYPEX ShortStreamType;
//
//typedef struct _stream_counters
//{
// uint32 stream_id;
// StreamDirection direction;
// ShortStreamType stream_type;
// uint32 class_id_h;
// uint32 class_id_l;
// uint32 size;
// uint32 count;
// uint32 status;
// float speed;
// BOOL printed;
// uint32 ip;
// uint16 port;
//} stream_count_type, *StreamCount;
void hal_Listener_Init(void);
//DisplayClient hal_ListenerGetFFTClient();
//void hal_showStreamReport(void);
//float hal_getStreamRate(uint32 stread_id);
//void HAL_update_count(uint32 stream_id, uint32 class_id_h, uint32 class_id_l, uint32 size, uint32 status, StreamDirection direction, ShortStreamType strm_type, uint32 ip, uint16 port);
#define HAL_STATUS_PROCESSED 1
#define HAL_STATUS_INVALID_OUI 2
#define HAL_STATUS_NO_DESC 3
#define HAL_STATUS_UNSUPPORTED_SAMP 4
#define HAL_STATUS_UNSUPPORTED_FFT 5
#define HAL_STATUS_BAD_TYPE 6
#define HAL_STATUS_FFT_NO_STREAM 7
#define HAL_STATUS_IQ_NO_STREAM 8
#define HAL_STATUS_OUTPUT_OK 9
#define HAL_STATUS_DSP_NO_STREAM 10
#define HAL_STATUS_DAX_NO_STREAM 11
#define HAL_STATUS_DAX_SIZE_WRONG 12
#define HAL_STATUS_DAX_WRONG_CHAN 13
#define HAL_STATUS_TX_SKIP 14
#define HAL_STATUS_TX_ZERO 15
#define HAL_STATUS_UNK_STREAM 16
/* Waveform defines */
#define HAL_STATUS_WFM_SIZE_WRONG 17
#define HAL_STATUS_WFM_NO_STREAM 18
#endif // _LISTENER_H

View file

@ -0,0 +1,67 @@
///*! \file hal_vita.c
// * \brief Structure to support VITA-49 packets
// *
// * \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 29-MAR-2012
// * \author Eric & Steve
// */
/* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <netinet/in.h> // htonl
#include "common.h"
#include "hal_vita.h"
uint32 hal_VitaIFPacketPayloadSize(VitaIFData packet)
{
uint32 header = htonl(packet->header);
uint32 bytes = (header & VITA_HEADER_PACKET_SIZE_MASK)*4; // packet size is in 32-bit words
switch(header & VITA_HEADER_PACKET_TYPE_MASK)
{
case VITA_PACKET_TYPE_IF_DATA: // do nothing
break;
case VITA_PACKET_TYPE_IF_DATA_WITH_STREAM_ID:
bytes -= 4; // account for stream ID
break;
default: // wrong kind of packet here
//output("Called with wrong type of packet (%X)\n", header>>28);
break;
}
bytes -= 4; // account for header
if(header & VITA_HEADER_C_MASK) bytes -= 8; // account for class ID
if(header & VITA_HEADER_T_MASK) bytes -= 4; // account for trailer
if((header & VITA_HEADER_TSI_MASK) != VITA_TSI_NONE)
bytes -= 4;
if((header & VITA_HEADER_TSF_MASK) != VITA_TSF_NONE)
bytes -= 8;
return bytes;
}

View file

@ -0,0 +1,39 @@
/* *****************************************************************************
* vita.h
*
* Describes VITA 49 structures
*
* \date 28-MAR-2012
* \author Eric Wachsmann, KE5DTO
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _HAL_VITA_H
#define _HAL_VITA_H
#include "datatypes.h"
#include "vita.h"
//! gets the size of the payload in bytes based on the header
uint32 hal_VitaIFPacketPayloadSize(VitaIFData packet);
#endif /* _HAL_VITA_H */

View file

@ -0,0 +1,58 @@
///*! \file io_utils.c
// * \brief Module that contains various IO utilities
// *
// * \copyright Copyright 2011-2012 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 9-NOV-2011
// * \author Terry Gerdes, AB5K
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "common.h"
uint32 net_get_ip()
{
struct ifaddrs* ifAddrStruct = NULL;
struct ifaddrs* ifa = NULL;
uint32 ip = 0;
getifaddrs(&ifAddrStruct);
ifa = ifAddrStruct->ifa_next->ifa_next->ifa_next->ifa_next; // skip to 4th interface
ip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
freeifaddrs(ifAddrStruct);
return ip;
}

View file

@ -0,0 +1,50 @@
///*! \file io_utils.h
// * \brief \\TODO Add summary description of this module
// *
// * Copyright 2011 FlexRadio Systems. All Rights Reserved.
// *
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date Nov 9, 2011
// * \author Terry - AB5K
// *
// * Date: 23-AUG-2011
// *
// *
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef IO_UTILS_H_
#define IO_UTILS_H_
#include <sys/socket.h>
#include "datatypes.h"
/* ------------------------------------------------------------------------ *
* Prototypes *
* ------------------------------------------------------------------------ */
uint32 net_get_ip();
#endif /* IO_UTILS_H_ */

View file

@ -0,0 +1,703 @@
///*! \file sched_waveform.c
// * \brief Schedule Wavefrom Streams
// *
// * \copyright Copyright 2012-2014 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 29-AUG-2014
// * \author Ed Gonzalez
// *
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h> // for memset
#include <unistd.h>
#include "common.h"
#include "datatypes.h"
#include "hal_buffer.h"
#include "sched_waveform.h"
#include "vita_output.h"
//static Queue sched_fft_queue;
static pthread_rwlock_t _list_lock;
static BufferDescriptor _root;
static pthread_t _waveform_thread;
static BOOL _waveform_thread_abort = FALSE;
static sem_t sched_waveform_sem;
static void _dsp_convertBufEndian(BufferDescriptor buf_desc)
{
int i;
if(buf_desc->sample_size != 8)
{
//TODO: horrendous error here
return;
}
for(i = 0; i < buf_desc->num_samples*2; i++)
((int32*)buf_desc->buf_ptr)[i] = htonl(((int32*)buf_desc->buf_ptr)[i]);
}
static BufferDescriptor _WaveformList_UnlinkHead(void)
{
BufferDescriptor buf_desc = NULL;
pthread_rwlock_wrlock(&_list_lock);
if (_root == NULL || _root->next == NULL)
{
output("Attempt to unlink from a NULL head");
pthread_rwlock_unlock(&_list_lock);
return NULL;
}
if(_root->next != _root)
buf_desc = _root->next;
if(buf_desc != NULL)
{
// make sure buffer exists and is actually linked
if(!buf_desc || !buf_desc->prev || !buf_desc->next)
{
output( "Invalid buffer descriptor");
buf_desc = NULL;
}
else
{
buf_desc->next->prev = buf_desc->prev;
buf_desc->prev->next = buf_desc->next;
buf_desc->next = NULL;
buf_desc->prev = NULL;
}
}
pthread_rwlock_unlock(&_list_lock);
return buf_desc;
}
static void _WaveformList_LinkTail(BufferDescriptor buf_desc)
{
pthread_rwlock_wrlock(&_list_lock);
buf_desc->next = _root;
buf_desc->prev = _root->prev;
_root->prev->next = buf_desc;
_root->prev = buf_desc;
pthread_rwlock_unlock(&_list_lock);
}
void sched_waveform_Schedule(BufferDescriptor buf_desc)
{
_WaveformList_LinkTail(buf_desc);
sem_post(&sched_waveform_sem);
}
void sched_waveform_signal()
{
sem_post(&sched_waveform_sem);
}
/* *********************************************************************************************
* *********************************************************************************************
* *********************************************************************************************
* ******************** TEMPORARY LOCATION OF DEMOD/MOD **************************************
* *********************************************************************************************
* *********************************************************************************************
* *********************************************************************************************
*/
#include <stdio.h>
#include "freedv_api.h"
#include "circular_buffer.h"
#include "resampler.h"
#define PACKET_SAMPLES 128
#define SCALE_RX_IN 8000.0
#define SCALE_RX_OUT 8000.0
#define SCALE_TX_IN 8000.0
#define SCALE_TX_OUT 32768.0
#define FILTER_TAPS 48
#define DECIMATION_FACTOR 3
/* These are offsets for the input buffers to decimator */
#define MEM_24 FILTER_TAPS /* Memory required in 24kHz buffer */
#define MEM_8 FILTER_TAPS/DECIMATION_FACTOR /* Memory required in 8kHz buffer */
static struct freedv *_freedvS; // Initialize Coder structure
static struct my_callback_state _my_cb_state;
#define MAX_RX_STRING_LENGTH 40
static char _rx_string[MAX_RX_STRING_LENGTH + 5];
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Circular Buffer Declarations
float RX1_buff[(PACKET_SAMPLES * 6)+1]; // RX1 Packet Input Buffer
short RX2_buff[(PACKET_SAMPLES * 6)+1]; // RX2 Vocoder input buffer
short RX3_buff[(PACKET_SAMPLES * 6)+1]; // RX3 Vocoder output buffer
float RX4_buff[(PACKET_SAMPLES * 12)+1]; // RX4 Packet output Buffer
float TX1_buff[(PACKET_SAMPLES * 6) +1]; // TX1 Packet Input Buffer
short TX2_buff[(PACKET_SAMPLES * 6)+1]; // TX2 Vocoder input buffer
short TX3_buff[(PACKET_SAMPLES * 6)+1]; // TX3 Vocoder output buffer
float TX4_buff[(PACKET_SAMPLES * 12)+1]; // TX4 Packet output Buffer
circular_float_buffer rx1_cb;
Circular_Float_Buffer RX1_cb = &rx1_cb;
circular_short_buffer rx2_cb;
Circular_Short_Buffer RX2_cb = &rx2_cb;
circular_short_buffer rx3_cb;
Circular_Short_Buffer RX3_cb = &rx3_cb;
circular_float_buffer rx4_cb;
Circular_Float_Buffer RX4_cb = &rx4_cb;
circular_float_buffer tx1_cb;
Circular_Float_Buffer TX1_cb = &tx1_cb;
circular_short_buffer tx2_cb;
Circular_Short_Buffer TX2_cb = &tx2_cb;
circular_short_buffer tx3_cb;
Circular_Short_Buffer TX3_cb = &tx3_cb;
circular_float_buffer tx4_cb;
Circular_Float_Buffer TX4_cb = &tx4_cb;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Callbacks for embedded ASCII stream, transmit and receive
void my_put_next_rx_char(void *callback_state, char c)
{
char new_char[2];
new_char[0] = c;
new_char[1] = 0;
strncat(_rx_string, new_char, MAX_RX_STRING_LENGTH+4);
if (strlen(_rx_string) > MAX_RX_STRING_LENGTH)
{
// lop off first character
strcpy(_rx_string, _rx_string+1);
}
output(ANSI_MAGENTA "new string = '%s'\n",_rx_string);
char* api_cmd = safe_malloc(80);
sprintf(api_cmd, "waveform status slice=%d string=\"%s\"",0,_rx_string);
tc_sendSmartSDRcommand(api_cmd,FALSE,NULL);
safe_free(api_cmd);
}
struct my_callback_state
{
char tx_str[80];
char *ptx_str;
};
char my_get_next_tx_char(void *callback_state)
{
struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
char c = *pstate->ptx_str++;
if (*pstate->ptx_str == 0)
{
pstate->ptx_str = pstate->tx_str;
}
return c;
}
void freedv_set_string(uint32 slice, char* string)
{
strcpy(_my_cb_state.tx_str, string);
_my_cb_state.ptx_str = _my_cb_state.tx_str;
output(ANSI_MAGENTA "new TX string is '%s'\n",string);
}
/* *********************************************************************************************
* *********************************************************************************************
* *********************************************************************************************
* ******************** ^^^ TEMPORARY LOCATION OF DEMOD/MOD ^^^ **************************************
* *********************************************************************************************
* *********************************************************************************************
* *********************************************************************************************
*/
static void* _sched_waveform_thread(void* param)
{
/* *********************************************************************************************
* ******************** ^ TEMPORARY LOCATION OF DEMOD/MOD ^^^ **************************************
* *********************************************************************************************
*/
int nin, nout;
int i; // for loop counter
float fsample; // a float sample
// float Sig2Noise; // Signal to noise ratio
// Flags ...
int initial_tx = 1; // Flags for TX circular buffer, clear if starting transmit
int initial_rx = 1; // Flags for RX circular buffer, clear if starting receive
//int Coder_ON = 0; // Is CODEC2 On/Active ???
//int transmit_ON = 0; // Is CODEC2 in transmit mode?
//int New_Packet_Waiting = 0; // Is new packet waiting?
//int Is_Control_Packet = 0; // Is the new packet a control packet?
//int InputRxPacketReady = 0; // Is the new packet a sampled data packet for RX input?
//int InputTxPacketReady = 0; // Is the new packet a sampled data packet for TX input?
// VOCODER I/O BUFFERS
short speech_in[FREEDV_NSAMPLES];
short speech_out[FREEDV_NSAMPLES];
short demod_in[FREEDV_NSAMPLES];
short mod_out[FREEDV_NSAMPLES];
// RX RESAMPLER I/O BUFFERS
float float_in_8k[PACKET_SAMPLES + FILTER_TAPS];
float float_out_8k[PACKET_SAMPLES];
float float_in_24k[PACKET_SAMPLES * DECIMATION_FACTOR + FILTER_TAPS];
float float_out_24k[PACKET_SAMPLES * DECIMATION_FACTOR ];
// TX RESAMPLER I/O BUFFERS
float tx_float_in_8k[PACKET_SAMPLES + FILTER_TAPS];
float tx_float_out_8k[PACKET_SAMPLES];
float tx_float_in_24k[PACKET_SAMPLES * DECIMATION_FACTOR + FILTER_TAPS];
float tx_float_out_24k[PACKET_SAMPLES * DECIMATION_FACTOR ];
// ======================= Initialization Section =========================
_freedvS = freedv_open(FREEDV_MODE_1600); // Default system, only
//assert(_freedvS != NULL); // debug only
// Initialize the Circular Buffers
RX1_cb->size = PACKET_SAMPLES*6 +1; // size = no.elements in array+1
RX1_cb->start = 0;
RX1_cb->end = 0;
RX1_cb->elems = RX1_buff;
RX2_cb->size = PACKET_SAMPLES*6 +1; // size = no.elements in array+1
RX2_cb->start = 0;
RX2_cb->end = 0;
RX2_cb->elems = RX2_buff;
RX3_cb->size = PACKET_SAMPLES*6 +1; // size = no.elements in array+1
RX3_cb->start = 0;
RX3_cb->end = 0;
RX3_cb->elems = RX3_buff;
RX4_cb->size = PACKET_SAMPLES*12 +1; // size = no.elements in array+1
RX4_cb->start = 0;
RX4_cb->end = 0;
RX4_cb->elems = RX4_buff;
TX1_cb->size = PACKET_SAMPLES*6 +1; // size = no.elements in array+1
TX1_cb->start = 0;
TX1_cb->end = 0;
TX1_cb->elems = TX1_buff;
TX2_cb->size = PACKET_SAMPLES*6 +1; // size = no.elements in array+1
TX2_cb->start = 0;
TX2_cb->end = 0;
TX2_cb->elems = TX2_buff;
TX3_cb->size = PACKET_SAMPLES *6 +1; // size = no.elements in array+1
TX3_cb->start = 0;
TX3_cb->end = 0;
TX3_cb->elems = TX3_buff;
TX4_cb->size = PACKET_SAMPLES *12 +1; // size = no.elements in array+1
TX4_cb->start = 0;
TX4_cb->end = 0;
TX4_cb->elems = TX4_buff;
initial_tx = TRUE;
initial_rx = TRUE;
// initialize the rx callback
_freedvS->freedv_put_next_rx_char = &my_put_next_rx_char;
// Set up callback for txt msg chars
// clear tx_string
memset(_my_cb_state.tx_str,0,80);
_my_cb_state.ptx_str = _my_cb_state.tx_str;
_freedvS->callback_state = (void*)&_my_cb_state;
_freedvS->freedv_get_next_tx_char = &my_get_next_tx_char;
/* *********************************************************************************************
* ******************** ^ TEMPORARY LOCATION OF DEMOD/MOD ^^^ **************************************
* *********************************************************************************************
*/
// show that we are running
BufferDescriptor buf_desc;
while( !_waveform_thread_abort )
{
// wait for a buffer descriptor to get posted
sem_wait(&sched_waveform_sem);
if(!_waveform_thread_abort)
{
do {
buf_desc = _WaveformList_UnlinkHead();
if (buf_desc == NULL)
{
//output( "We were signaled that there was another buffer descriptor, but there's not one here");
break;
}
else
{
// convert the buffer to little endian
_dsp_convertBufEndian(buf_desc);
//output("buf_desc unlinked with mag %.6g", hal_BufferMag(buf_desc));
//output(" \"Processed\" buffer stream id = 0x%08X\n", buf_desc->stream_id);
BOOL emit = FALSE;
if( (buf_desc->stream_id & 1) == 0) { //RX BUFFER
// If 'initial_rx' flag, clear buffers RX1, RX2, RX3, RX4
if(initial_rx)
{
RX1_cb->start = 0; // Clear buffers RX1, RX2, RX3, RX4
RX1_cb->end = 0;
RX2_cb->start = 0;
RX2_cb->end = 0;
RX3_cb->start = 0;
RX3_cb->end = 0;
RX4_cb->start = 0;
RX4_cb->end = 0;
/* Clear filter memory */
for ( i = 0; i < MEM_24; i++) {
float_in_24k[i] = 0.0;
}
for ( i = 0; i < MEM_8; i++ ) {
float_in_8k[i] = 0;
}
/* Requires us to set initial_rx to FALSE which we do at the end of
* the first loop
*/
}
// Set the transmit 'initial' flag
initial_tx = TRUE;
// Check for new receiver input packet & move to RX1_cb.
// TODO - If transmit packet, discard here?
for(i=0;i<128;i++)
{
//output("Outputting ")
// fsample = Get next float from packet;
cbWriteFloat(RX1_cb, ((Complex*)buf_desc->buf_ptr)[i].real);
}
//
// Check for >= 384 samples in RX1_cb and spin downsampler
// Convert to shorts and move to RX2_cb.
if(cfbContains(RX1_cb) >= 384)
{
for(i=0 ; i<384 ; i++)
{
float_in_24k[i + MEM_24] = cbReadFloat(RX1_cb);
}
fdmdv_24_to_8(float_out_8k, &float_in_24k[MEM_24], 128);
for(i=0 ; i<128 ; i++)
{
cbWriteShort(RX2_cb, (short) (float_out_8k[i]*SCALE_RX_IN));
}
}
//
// // Check for >= 320 samples in RX2_cb and spin vocoder
// Move output to RX3_cb.
// do {
nin = freedv_nin(_freedvS); // TODO Is nin, nout really necessary?
if ( csbContains(RX2_cb) >= nin )
{
//
for( i=0 ; i< nin ; i++)
{
demod_in[i] = cbReadShort(RX2_cb);
}
nout = freedv_rx(_freedvS, speech_out, demod_in);
// if(nout != 320 ) {
// output("NOUT not 320 it is %d\nNIN was %d\n", nout, nin);
// }
for( i=0 ; i < nout ; i++)
{
cbWriteShort(RX3_cb, speech_out[i]);
}
}
// } else {
// break; /* Break out of while loop */
//}
//} while (1);
//
// Check for >= 128 samples in RX3_cb, convert to floats
// and spin the upsampler. Move output to RX4_cb.
if(csbContains(RX3_cb) >= 128)
{
for( i=0 ; i<128 ; i++)
{
float_in_8k[i+MEM_8] = ((float) (cbReadShort(RX3_cb) / SCALE_RX_OUT) );
}
fdmdv_8_to_24(float_out_24k, &float_in_8k[MEM_8], 128);
for( i=0 ; i<384 ; i++)
{
cbWriteFloat(RX4_cb, float_out_24k[i]);
}
//Sig2Noise = (_freedvS->fdmdv_stats.snr_est);
}
// Check for >= 128 samples in RX4_cb. Form packet and
// export.
uint32 check_samples = 128;
if(initial_rx)
check_samples = 128 * 3;
if(cfbContains(RX4_cb) >= check_samples )
{
for( i=0 ; i<128 ; i++)
{
//output("Fetching from end buffer \n");
// Set up the outbound packet
fsample = cbReadFloat(RX4_cb);
// put the fsample into the outbound packet
((Complex*)buf_desc->buf_ptr)[i].real = fsample;
((Complex*)buf_desc->buf_ptr)[i].imag = fsample;
}
emit = TRUE;
} else {
output("RX Starved buffer out\n");
for( i=0 ; i<128 ; i++)
{
((Complex*)buf_desc->buf_ptr)[i].real = 0.0f;
((Complex*)buf_desc->buf_ptr)[i].imag = 0.0f;
}
if(initial_rx)
initial_rx = FALSE;
emit = FALSE;
}
} else if ( (buf_desc->stream_id & 1) == 1) { //TX BUFFER
// If 'initial_rx' flag, clear buffers TX1, TX2, TX3, TX4
if(initial_tx)
{
TX1_cb->start = 0; // Clear buffers RX1, RX2, RX3, RX4
TX1_cb->end = 0;
TX2_cb->start = 0;
TX2_cb->end = 0;
TX3_cb->start = 0;
TX3_cb->end = 0;
TX4_cb->start = 0;
TX4_cb->end = 0;
/* Clear filter memory */
for ( i = 0; i < MEM_24; i++) {
tx_float_in_24k[i] = 0.0;
}
for ( i = 0; i < MEM_8; i++ ) {
tx_float_in_8k[i] = 0;
}
/* Requires us to set initial_rx to FALSE which we do at the end of
* the first loop
*/
}
initial_rx = TRUE;
// Check for new receiver input packet & move to TX1_cb.
// TODO - If transmit packet, discard here?
for(i=0;i<128;i++)
{
//output("Outputting ")
// fsample = Get next float from packet;
cbWriteFloat(TX1_cb, ((Complex*)buf_desc->buf_ptr)[i].real);
}
//
// Check for >= 384 samples in TX1_cb and spin downsampler
// Convert to shorts and move to TX2_cb.
if(cfbContains(TX1_cb) >= 384)
{
for(i=0 ; i<384 ; i++)
{
tx_float_in_24k[i + MEM_24] = cbReadFloat(TX1_cb);
}
fdmdv_24_to_8(tx_float_out_8k, &tx_float_in_24k[MEM_24], 128);
for(i=0 ; i<128 ; i++)
{
cbWriteShort(TX2_cb, (short) (tx_float_out_8k[i]*SCALE_TX_IN));
}
}
//
// // Check for >= 320 samples in TX2_cb and spin vocoder
// Move output to TX3_cb.
if ( csbContains(TX2_cb) >= 320 )
{
for( i=0 ; i< 320 ; i++)
{
speech_in[i] = cbReadShort(TX2_cb);
}
freedv_tx(_freedvS, mod_out, speech_in);
for( i=0 ; i < 320 ; i++)
{
cbWriteShort(TX3_cb, mod_out[i]);
}
}
// Check for >= 128 samples in TX3_cb, convert to floats
// and spin the upsampler. Move output to TX4_cb.
if(csbContains(TX3_cb) >= 128)
{
for( i=0 ; i<128 ; i++)
{
tx_float_in_8k[i+MEM_8] = ((float) (cbReadShort(TX3_cb) / SCALE_TX_OUT));
}
fdmdv_8_to_24(tx_float_out_24k, &tx_float_in_8k[MEM_8], 128);
for( i=0 ; i<384 ; i++)
{
cbWriteFloat(TX4_cb, tx_float_out_24k[i]);
}
//Sig2Noise = (_freedvS->fdmdv_stats.snr_est);
}
// Check for >= 128 samples in RX4_cb. Form packet and
// export.
uint32 tx_check_samples = 128;
if(initial_tx)
tx_check_samples = 128 * 3;
if(cfbContains(TX4_cb) >= tx_check_samples )
{
for( i=0 ; i<128 ; i++)
{
//output("Fetching from end buffer \n");
// Set up the outbound packet
fsample = cbReadFloat(TX4_cb);
// put the fsample into the outbound packet
((Complex*)buf_desc->buf_ptr)[i].real = fsample;
((Complex*)buf_desc->buf_ptr)[i].imag = fsample;
}
emit = TRUE;
} else {
output("TX Starved buffer out\n");
for( i=0 ; i<128 ; i++)
{
((Complex*)buf_desc->buf_ptr)[i].real = 0.0f;
((Complex*)buf_desc->buf_ptr)[i].imag = 0.0f;
}
if(initial_tx)
initial_tx = FALSE;
emit = FALSE;
}
}
if(emit) {
emit_waveform_output(buf_desc);
}
hal_BufferRelease(&buf_desc);
usleep(10);
}
} while(1); // Seems infinite loop but will exit once there are no longer any buffers linked in _Waveformlist
}
}
_waveform_thread_abort = TRUE;
freedv_close(_freedvS);
return NULL;
}
void sched_waveform_Init(void)
{
pthread_rwlock_init(&_list_lock, NULL);
pthread_rwlock_wrlock(&_list_lock);
_root = (BufferDescriptor)safe_malloc(sizeof(buffer_descriptor));
memset(_root, 0, sizeof(buffer_descriptor));
_root->next = _root;
_root->prev = _root;
pthread_rwlock_unlock(&_list_lock);
sem_init(&sched_waveform_sem, 0, 0);
pthread_create(&_waveform_thread, NULL, &_sched_waveform_thread, NULL);
}
void sched_waveformThreadExit()
{
_waveform_thread_abort = TRUE;
sem_post(&sched_waveform_sem);
}

View file

@ -0,0 +1,45 @@
///*! \file sched_waveform.h
// * \brief Schedule Wavefrom Streams
// *
// * \copyright Copyright 2012-2014 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 29-AUG-2014
// * \author Ed Gonzalez
// *
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef SCHED_WAVEFORM_H_
#define SCHED_WAVEFORM_H_
#include "hal_buffer.h"
void sched_waveform_Schedule(BufferDescriptor buf);
void sched_waveform_Init(void);
void sched_waveform_signal(void);
void sched_waveformTreadExit(void);
#endif /* SCHED_WAVEFORM_H_ */

View file

@ -0,0 +1,307 @@
///* \file smartsdr_dsp_api.c
// * \brief Main SmartSDR DSP API Entry point
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// * \author Graham Haddock, KE9H
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h> // File Control functions
#include "common.h"
#include "traffic_cop.h"
#include "discovery_client.h"
#include "sched_waveform.h"
static uint32 _api_version;
static uint32 _handle;
static pthread_t _console_thread_ID;
static BOOL console_thread_abort = FALSE;
#define PROMPT "\n\033[92mWaveform -->\033[33m"
static sem_t _startup_sem, _communications_sem;
extern const char* APP_NAME;
extern const char* CFG_FILE;
void api_setVersion(uint32 version)
{
_api_version = version;
output(ANSI_MAGENTA "version = %d.%d.%d.%d\n",_api_version >> 24,_api_version >> 16 & 0xFF,
_api_version >> 8 & 0xFF,_api_version & 0xFF);
}
uint32 api_getVersion(void)
{
return _api_version;
}
void api_setHandle(uint32 handle)
{
_handle = handle;
output(ANSI_MAGENTA "handle = 0x%08X\n",handle);
// let everyone know we've established communications with the radio
sem_post(&_communications_sem);
}
uint32 api_getHandle(void)
{
return _handle;
}
void SmartSDR_API_Shutdown(void)
{
// stop the keepalive thread if we are done
tc_abort();
}
void* _console_thread(void* param)
{
cmd_banner();
// let everybody know we're through printing
sem_post(&_startup_sem);
sem_wait(&_communications_sem);
output(PROMPT);
while (!console_thread_abort)
{
command();
output(PROMPT);
}
SmartSDR_API_Shutdown();
return NULL;
}
void SmartSDR_API_Init(void)
{
sem_init(&_startup_sem,0,0);
sem_init(&_communications_sem,0,0);
// initialize printed output
lock_printf_init();
lock_malloc_init();
vita_output_Init();
sched_waveform_Init();
// Start the console thread
pthread_create(&_console_thread_ID, NULL, &_console_thread, NULL);
// wait for the console to print out all it's stuff
sem_wait(&_startup_sem);
tc_Init();
dc_Init();
}
/* *****************************************************************************
* uint32 register_mode(void)
*
* Transmits configuration information from ConfigFile.cfg
* Expected file contents are ASCII text.
*/
uint32 register_mode(void)
{
FILE* cfgStream; // Stream ID for config file when opened
ssize_t numRead; // Number of bytes read by getline()
size_t nbytes = 120; // Default size of input buffer
char *inputBuffer; // The input buffer
// ssize_t result; // strncmp() result
char* charptr; // pointer returned by strstr()
BOOL readFlag; // file readflag [TRUE -> continue]
struct stat statbuf;
char MinRadioVerString[40];
// Check for existence of file before opening, otherwise will segfault.
if(stat(CFG_FILE, &statbuf) == 0)
{
output(ANSI_WHITE"Configuration file exists.\n");
}
else
{
output(ANSI_RED"CONFIGURATION FILE DOES NOT EXIST.\n");
usleep(1000000);
return 999;
}
cfgStream = fopen(CFG_FILE, "r");
if (ferror(cfgStream))
{
output(ANSI_YELLOW"Error opening file %s \n", CFG_FILE);
return 999;
}
else{
}
/* Transfer data expecting to encounter end of input (or an error) */
inputBuffer = (char *) malloc (nbytes + 1); // Initial buffer size
readFlag = TRUE;
while(readFlag) // Look for the start of the [header]
{
numRead = getline(&inputBuffer, &nbytes, cfgStream);
if (numRead == -1)
{
output(ANSI_YELLOW"Error reading config file %s\n", CFG_FILE);
return 999;
}
// Process it here
charptr = strstr(inputBuffer, "[header]");
if(charptr != NULL)
{
output(ANSI_CYAN "FreeDV: Start of [header] found.\n");
readFlag = FALSE;
}
else
{
if (ferror(cfgStream))
{
output(ANSI_YELLOW"Read error %s, reached end of file, [header] not found. \n", CFG_FILE);
return 999; // should return a fail return -1;
}
}
}
readFlag = TRUE;
while(readFlag) // Look for the minimum version
{
numRead = getline(&inputBuffer, &nbytes, cfgStream);
if (numRead == -1)
{
output(ANSI_YELLOW"Error reading config file %s\n", CFG_FILE);
// TODO return here?
}
// Process it here
charptr = strstr(inputBuffer, "Minimum-SmartSDR-Version:");
if(charptr != NULL)
{
output(ANSI_CYAN "FreeDV: Minimum Version found.\n");
charptr += strlen("Minimum-SmartSDR-Version:");
strcpy(MinRadioVerString, charptr );
readFlag = FALSE;
}
else
{
if (ferror(cfgStream))
{
output(ANSI_YELLOW"Read error %s, minimum version not found, reached end of file. \n", CFG_FILE);
return 999;
}
}
}
readFlag = TRUE;
while(readFlag) // Find the start of the [setup] section
{
numRead = getline(&inputBuffer, &nbytes, cfgStream);
if (numRead == -1)
{
output(ANSI_YELLOW"Error reading config file %s\n", CFG_FILE);
return 999;
}
// Process it here
charptr = strstr(inputBuffer, "[setup]");
if(charptr != NULL)
{
output(ANSI_CYAN "FreeDV: Start of [setup] found.\n");
readFlag = FALSE;
}
else
{
if (ferror(cfgStream))
{
output(ANSI_YELLOW"Read error %s, [setup] not found. \n", CFG_FILE);
return 999; // should return a fail return -1;
}
}
}
readFlag = TRUE;
while(readFlag) // Export the setup configuration information
{ // Stop on "[end]" or EOF
numRead = getline(&inputBuffer, &nbytes, cfgStream);
if (numRead == -1)
{
output("Error reading config file %s\n", CFG_FILE);
return 999;
}
// turn trailing 'carriage returns" to nulls.
charptr = strstr(inputBuffer, "\r");
if(charptr != NULL)
*charptr = 0;
charptr = strstr(inputBuffer, "[end]");
if(strlen(inputBuffer) == 0)
{
output(ANSI_CYAN "FreeDV: Blank line, not sent. \n");
}
else if(charptr != NULL)
{
output(ANSI_CYAN "FreeDV: Script end marker [end] found.\n");
readFlag = FALSE;
}
else if (ferror(cfgStream))
{
output("End of file %s, reached. \n\n", CFG_FILE);
readFlag = FALSE;
}
else
{
// Process it here
output(ANSI_CYAN "FreeDV: %s \n", inputBuffer);
tc_sendSmartSDRcommand(inputBuffer, FALSE, NULL);
}
}
if (fclose(cfgStream) == EOF)
{
output(ANSI_YELLOW"Error closing config file %s\n", CFG_FILE);
}
else
{
output(ANSI_CYAN "FreeDV: SUCCESS, closed config file %s\n", CFG_FILE);
}
return SUCCESS;
}

View file

@ -0,0 +1,52 @@
///* \file smartsdr_dsp_api.c
// * \brief Main SmartSDR DSP API Entry point
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef SMARTSDR_DSP_API_H_
#define SMARTSDR_DSP_API_H_
#include "common.h"
#include "traffic_cop.h"
static const int MAX_API_COMMAND_SIZE = 1024;
static const int RECV_BUF_SIZE = 8192;
static const int RECV_BUF_SIZE_TO_GET = 2048;
void api_setVersion(uint32 version);
uint32 api_getVersion(void);
void api_setHandle(uint32 handle);
uint32 api_getHandle(void);
void SmartSDR_API_Shutdown(void);
void SmartSDR_API_Init(void);
uint32 register_mode(void);
#endif /* SMARTSDR_DSP_API_H_ */

View file

@ -0,0 +1,207 @@
///* \file status_processor.c
// * \brief Main SmartSDR DSP API Entry point
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#include "traffic_cop.h"
static void _handle_status(char* string)
{
int argc;
uint32 slc; // slice number
char *argv[MAX_ARGC_STATUS + 1]; //Add one extra so we can null terminate the array
// get the actual status message -- we don't care about the handle
char* save = 0;
char* start = strtok_r(string,"|",&save);
start = strtok_r(NULL,"|",&save);
// first let's look for a slice status -- these are most important
if (strncmp(start, "slice", strlen("slice")) == 0)
{
tokenize(start, &argc, argv, MAX_ARGC);
if (argc < 3)
{
// bad slice status ... ignoring it
return;
}
errno = 0;
slc = strtoul(argv[1], NULL, 0);
if(errno)
{
output(ANSI_RED "Unable to parse slice number (%s)\n", argv[1]);
return;
}
int i;
for (i = 2; i < argc; i++)
{
if(strncmp(argv[i], "mode", strlen("mode")) == 0)
{
errno = 0;
char* smode = argv[i]+strlen("mode")+1;
if (strncmp(smode,"FDV",3) == 0)
{
// we are now in FDV mode
output(ANSI_MAGENTA "slice %d is now in FDV mode\n",slc);
}
else
{
// we have left FDV mode
output(ANSI_MAGENTA "slice %d is in %s mode\n",slc,smode);
}
}
if(strncmp(argv[i], "in_use", strlen("in_use")) == 0)
{
errno = 0;
int in_use = strtoul(argv[i]+strlen("in_use")+1, NULL, 0);
if (!in_use)
{
output(ANSI_MAGENTA "slice %d has been removed\n",slc);
}
}
if(strncmp(argv[i], "tx", strlen("tx")) == 0)
{
errno = 0;
int tx = strtoul(argv[i]+strlen("tx")+1, NULL, 0);
if (tx)
{
output(ANSI_MAGENTA "slice %d is the transmit slice\n",slc);
}
else
{
output(ANSI_MAGENTA "slice %d is NOT transmit slice\n",slc);
}
}
}
}
else if (strncmp(start, "interlock", strlen("interlock")) == 0)
{
tokenize(start, &argc, argv, MAX_ARGC);
if (argc < 2)
{
// bad interlock status ... ignoring it
return;
}
int i;
for (i = 1; i < argc; i++)
{
if(strncmp(argv[i], "state", strlen("state")) == 0)
{
errno = 0;
char* state = argv[i]+strlen("state")+1;
if (strncmp(state,"PTT_REQUESTED",strlen("PTT_REQUESTED")) == 0)
{
output(ANSI_MAGENTA "we are transmitting\n");
}
else if (strncmp(state,"READY",strlen("READY")) == 0 ||
strncmp(state,"NOT_READY",strlen("NOT_READY")) == 0)
{
output(ANSI_MAGENTA "we are receiving\n");
}
}
}
}
// now we could check for other statuses that were interesting
}
void status_processor(char* string)
{
switch (*string)
{
case 'V': // version
{
string++;
uint32 version = getIP(string);
api_setVersion(version);
break;
}
case 'H': // handle
{
string++;
uint32 val;
sscanf(string, "%08X", &val);
api_setHandle(val);
break;
}
case 'R': // response
{
char* save = NULL;
string++;
uint32 val;
sscanf(string, "%i", &val);
char* response = strtok_r(string, "|", &save);
response = strtok_r(NULL, "", &save);
tc_commandList_respond(val, response);
break;
}
case 'C': // command
{
char* save = NULL;
string++;
uint32 val;
sscanf(string, "%i", &val);
char* cmd = strtok_r(string, "|", &save);
cmd = strtok_r(NULL, "", &save);
output("\033[32mExecuting command from SmartSDR: \033[m%s\n",cmd);
process_command(cmd);
break;
}
case 'S': // status
{
// here we translate from SmartSDR status message we are interested in
// and the corresponding commands we want to execute
_handle_status(string);
break;
}
case 'M': // message
break;
default:
output(ANSI_YELLOW "Status Processor: unknown status \033[m%s\n",string);
break;
}
}

View file

@ -0,0 +1,40 @@
///* \file status_processor.h
// * \brief Main SmartSDR DSP API Entry point
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef STATUS_PROCESSOR_H_
#define STATUS_PROCESSOR_H_
#include "common.h"
void status_processor(char* string);
#endif /* STATUS_PROCESSOR_H_ */

View file

@ -0,0 +1,72 @@
/* *****************************************************************************
* file stream.h
* \brief Collection for system streams
*
* \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
* Unauthorized use, duplication or distribution of this software is
* strictly prohibited by law.
*
* \date Mar 29, 2012
* \author Eric & Steve
*
* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _STREAM_H
#define _STREAM_H
#include "../common.h"
#define STREAM_BITS_IN 0x80000000
#define STREAM_BITS_OUT 0x00000000
#define STREAM_BITS_METER 0x08000000
#define STREAM_BITS_WAVEFORM 0x01000000
#define STREAM_BITS_MASK (STREAM_BITS_IN | STREAM_BITS_OUT | STREAM_BITS_METER | \
STREAM_BITS_WAVEFORM)
#define STREAM_PREFIX 0x7700
enum STREAM_TYPE
{
STREAM_NULL = STREAM_PREFIX,
STREAM_IN_RF_IQ,
STREAM_IN_AUDIO,
STREAM_IN_RF_NAR,
STREAM_IN_FFT,
STREAM_OUT_RF_IQ,
STREAM_OUT_PANADAPTER,
STREAM_OUT_WATERFALL,
STREAM_OUT_AUDIO,
STREAM_OUT_METER,
STREAM_IN_WAVEFORM,
STREAM_OUT_WAVEFORM
};
typedef enum STREAM_TYPE STREAMtype;
typedef uint32 Stream_ID;
#endif // _STREAM_H

View file

@ -0,0 +1,612 @@
///* \file traffic_cop.c
// * \brief TCP Communications Server
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/tcp.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include "common.h"
#include "traffic_cop.h"
#include "status_processor.h"
static pthread_t _tc_thread_id;
static pthread_t _keepalive_thread_id;
static __thread receive_data __local;
//! address of the host to connect to -- defaults to 127.0.0.1
//! but this is generally provided by discovery
static char* _hostname = "127.0.0.1";
//const char* gai_strerror(int ecode);
static BOOL _abort = FALSE;
static int _socket;
static BOOL _abort_keepalive = FALSE;
static uint32 _sequence = 0;
static Command _root;
static pthread_mutex_t _commandList_mutex;
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
static void _tc_openSocket(void)
{
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(_hostname, SMARTSDR_API_PORT, &hints, &servinfo)) != 0) {
output(ANSI_RED "getaddrinfo: %s\n", gai_strerror(rv));
// this is fatal
exit(1);
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((_socket = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
output(ANSI_RED "Traffic Cop: socket error\n");
continue;
}
if (connect(_socket, p->ai_addr, p->ai_addrlen) == -1) {
close(_socket);
output(ANSI_RED "Traffic Cop: connect error\n");
continue;
}
break;
}
if (p == NULL) {
output(ANSI_RED "Traffic Cop: failed to connect\n");
exit(2);
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
output(ANSI_GREEN "Traffic Cop: connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
}
static BOOL _have_terminate_char(void)
{
if (__local.recv_buf[0] == 3) return TRUE; // ctrl-c
if (__local.recv_buf[0] == 4) return TRUE; // ctrl-d
if (__local.recv_buf[0] == 26) return TRUE; // ctrl-z
return FALSE;
}
static void _eat_characters(int n)
{
//output("eating %u characters\n",n);
if (n >= __local.buf_len)
{
// if we are trying to eat more than is in the buffer, just clear the buffer
memset(__local.recv_buf, 0, n+1);
//output("zeroing buffer\n");
__local.read_ptr = __local.recv_buf;
__local.buf_len = 0;
}
else if (n > 0)
{
char* to = __local.recv_buf;
char* from = __local.recv_buf + n;
// move the rest of the buffer over the stuff we are eating
int i;
for (i = 0; i < (__local.buf_len - n); i++)
{
//output("moving a 0x%02X '%c'\n",*from,*from);
*to++ = *from;
*from++ = 0;
}
// correct length to show we ate some characters
__local.buf_len -= n;
//output("new buf len = %u\n",__local.buf_len);
// set where we will read in the next data
__local.read_ptr = (__local.recv_buf + __local.buf_len);
//output("new read ptr = 0x%08X\n",__local.read_ptr);
//output("next character = 0x%02X '%c'\n",*__local.recv_buf, *__local.recv_buf);
}
}
static void _eat_crlf(void)
{
BOOL done_eating = FALSE;
// check for tasty morsels
while (!done_eating)
{
// don't overeat -- it's bad for you
if (__local.buf_len == 0)
{
done_eating = TRUE;
}
else if (__local.recv_buf[0] == '\n' || __local.recv_buf[0] == '\r' || __local.recv_buf[0] == 0x0)
{
_eat_characters(1);
}
else
{
done_eating = TRUE;
}
}
}
static void _skip_esc_sequences(void)
{
// is the first character a telnet escape character (see RFC 2877)
while (__local.recv_buf[0] == 0xFF)
{
_eat_characters(3);
}
}
static BOOL _check_for_timeout(void)
{
// if keepalive is not turned on, just say everything is AOK
if (!__local.keepalive_enabled) return TRUE;
// bail if we're uninitialized
if (__local.last_ping.tv_sec == 0) return TRUE;
// find out how long it has been since the last ping
uint32 since = usSince(__local.last_ping);
// 500% margin -- we should get a ping once per second
if (since > 5000000) return FALSE;
return TRUE;
}
static uint32 _read_more_data(void)
{
int read_len, errsv;
BOOL done = FALSE;
// loop ignoring any timeout errors that occur
while (!done)
{
read_len = recv(_socket, __local.read_ptr, RECV_BUF_SIZE_TO_GET, 0);
errsv = errno;
// if read_len is zero and er got EAGAIN, it means the client closed the socket
if ( read_len == 0 && (errsv == EAGAIN || errsv == EPIPE || errsv == EBADF ) )
{
// debug(LOG_DEV, TRUE, "socket error: read_len = %d, errno = %d",read_len,errsv);
return SL_CLOSE_CLIENT;
}
// if we got new text from the socket OR we have an error other than timeout, exit the loop
if (read_len > 0) done = TRUE;
// EINTR seems to get asserted with breakpoint adds when debugging, so let's just
// read again if we see that too
if (read_len == -1 && errsv != EAGAIN && errsv != EINTR)
{
// debug(LOG_DEV, TRUE, "socket error: read_len = %d, errno = %d",read_len,errsv);
return SL_CLOSE_CLIENT;
}
// see if we have keepalive enabled and if so and we've not received a ping, terminate
// this client
if (!_check_for_timeout())
{
output(ANSI_RED "\nTraffic Cop has failed keepalive test; terminating\n");
// hal_listen_abort = TRUE;
}
// if someone wants to shutdown the system, we will terminate this thread
if (_abort) return SL_TERMINATE;
}
if (read_len <= 0 || read_len > RECV_BUF_SIZE_TO_GET)
{
// ok we're done here -- time to go
return SL_CLOSE_CLIENT;
}
else
{
__local.buf_len += read_len;
//output("total text length = %u\n",__local.buf_len);
return SUCCESS;
}
}
static uint32 _get_string_len(void)
{
uint32 len;
BOOL found_terminator = FALSE;
for (len = 0; len < __local.buf_len; len++)
{
if (*(__local.recv_buf+len) == '\r' ||
*(__local.recv_buf+len) == '\n' ||
*(__local.recv_buf+len) == 0)
{
found_terminator = TRUE;
break;
}
}
if (found_terminator)
{
return len;
}
else
{
// prevent tight CPU loops waiting on data
usleep(500);
return 0;
}
}
static uint32 _get_command(void)
{
BOOL got_command = FALSE;
while (!got_command && !_abort)
{
// if there something in the buffer
if (__local.buf_len != 0)
{
if (_have_terminate_char()) return SL_TERMINATE;
_skip_esc_sequences();
_eat_crlf();
uint32 len = _get_string_len();
if (len != 0)
{
__local.command = (char*)safe_malloc(len+1);
if(!__local.command)
{
//output("Error allocating command (size=%u)\n", len+1);
__local.command = NULL;
return SL_OUT_OF_MEMORY;
}
// clear the newly allocated memory
memset(__local.command, 0, len+1);
memcpy(__local.command, __local.recv_buf, len);
_eat_characters(len);
got_command = TRUE;
}
}
if (!got_command)
{
uint32 ret_val = _read_more_data();
if (ret_val != SUCCESS) return ret_val;
}
}
return SUCCESS;
}
void process_status(char* string)
{
#ifdef DEBUG
output(ANSI_GREEN "Traffic Cop: received \033[m'%s'\n",string);
#endif
status_processor(string);
}
//! main traffic cop receiver thread
static void* _tc_thread(void* arg)
{
uint32 result;
memset(&__local, 0, sizeof(receive_data));
__local.last_ping.tv_sec = 0;
__local.recv_buf = safe_malloc(RECV_BUF_SIZE);
memset(__local.recv_buf, 0, RECV_BUF_SIZE);
__local.buf_len = RECV_BUF_SIZE;
// make a connection to SmartSDR
// if this fails, the program just exits
_tc_openSocket();
// loop recieving data from SmartSDR and sending it where it should go
while (!_abort)
{
result = _get_command();
if (result == SUCCESS)
{
if(__local.command != NULL)
{
process_status(__local.command);
safe_free(__local.command);
__local.command = NULL;
}
}
else if (result == SL_TERMINATE)
{
_abort = TRUE;
// close(client->sd); -- it's actually closed after the end: label
//debug(LOG_DEV,TRUE,"Client asked to close connection with a termination character");
}
else if (result == SL_CLOSE_CLIENT)
{
_abort = TRUE;
//close(client->sd); -- it's actually closed after the end: label
//debug(LOG_DEV,TRUE,"An error on the port has forced the client to close");
}
}
close(_socket);
safe_free(__local.recv_buf);
return NULL;
}
void _commandList_LinkHead(Command cmd)
{
pthread_mutex_lock(&_commandList_mutex);
cmd->prev = _root;
cmd->next = _root->next;
_root->next->prev = cmd;
_root->next = cmd;
pthread_mutex_unlock(&_commandList_mutex);
}
void _commandList_LinkTail(Command cmd)
{
pthread_mutex_lock(&_commandList_mutex);
cmd->next = _root;
cmd->prev = _root->prev;
_root->prev->next = cmd;
_root->prev = cmd;
pthread_mutex_unlock(&_commandList_mutex);
}
void _commandList_Unlink(Command cmd)
{
// list should already be locked with entering!
// ensure not root
if(cmd == _root) return;
// make sure cmd exists and is actually linked
if(!cmd || !cmd->prev || !cmd->next) return;
cmd->next->prev = cmd->prev;
cmd->prev->next = cmd->next;
cmd->next = NULL;
cmd->prev = NULL;
}
void _commandList_Init()
{
_root = (Command)safe_malloc(sizeof(command_type));
memset(_root, 0, sizeof(command_type));
_root->next = _root;
_root->prev = _root;
pthread_mutex_init(&_commandList_mutex, NULL);
}
Command tc_commandList_respond(uint32 sequence, char* response)
{
#ifdef DEBUG
output("response for %d: '%s'\n",sequence,response);
#endif
pthread_mutex_lock(&_commandList_mutex);
Command iterator = _root;
while(iterator->next != _root)
{
iterator = iterator->next;
if (iterator->sequence != sequence) continue;
uint32 len = strlen(response);
char* resp = safe_malloc(len+1);
strncpy(resp, response, len+1);
iterator->response = resp;
#ifdef DEBUG
// let the thread blocking on this know that we now have it
output("posting %d...\n",sequence);
#endif
sem_post(&iterator->semaphore);
break;
}
pthread_mutex_unlock(&_commandList_mutex);
return NULL;
}
char* _tc_commandList_getResponse(uint32 sequence)
{
pthread_mutex_lock(&_commandList_mutex);
Command iterator = _root;
while(iterator->next != _root)
{
iterator = iterator->next;
if (iterator->sequence != sequence) continue;
pthread_mutex_unlock(&_commandList_mutex);
sem_wait(&iterator->semaphore);
#ifdef DEBUG
output("received post %d...\n",sequence);
#endif
sem_destroy(&iterator->semaphore);
_commandList_Unlink(iterator);
char* response = iterator->response;
free(iterator);
return response;
}
pthread_mutex_unlock(&_commandList_mutex);
return NULL;
}
static void _tc_commandList_add(uint32 sequence)
{
Command cmd = safe_malloc(sizeof(command_type));
memset(cmd, 0, sizeof(command_type));
sem_init(&cmd->semaphore,0,0);
cmd->sequence = sequence;
_commandList_LinkTail(cmd);
}
static uint32 _sendAPIcommand(char* command, uint32* sequence, BOOL block)
{
int result;
uint32 ret_val;
char* mpointer = NULL;
char* message = safe_malloc(MAX_API_COMMAND_SIZE);
memset(message, 0, MAX_API_COMMAND_SIZE);
_sequence++;
*sequence = _sequence;
if (block) _tc_commandList_add(*sequence);
// first, we need to put the status header on the front of the string
int len = snprintf(message, MAX_API_COMMAND_SIZE, "C%d|", *sequence);
mpointer = message + len;
len += strlen(command) + 1;
strncat(mpointer, command, MAX_API_COMMAND_SIZE);
strncat(mpointer, "\n", MAX_API_COMMAND_SIZE);
errno = 0;
result = write(_socket, message, len);
*(message+len-1) = 0;
// output what we're sending as long as it is not a ping
if (strstr(message, "ping") == 0)
output(ANSI_GREEN "-> SmartSDR: \033[33m%s\033[m\n",command);
if (result == len)
{
ret_val = SUCCESS;
}
else
{
output(ANSI_RED "Traffic Cop: error writing to TCP API socket: %s\n",strerror(errno));
ret_val = SL_ERROR_BASE;
tc_abort();
}
safe_free(message);
return ret_val;
}
//! send a command to the SmartSDR API (radio) and wait for a response
//! this is a blocking call on the radio and will not return if the SmartSDR
//! process is not running or not responding
uint32 tc_sendSmartSDRcommand(char* command, BOOL block, char** response)
{
if (response) *response = NULL;
uint32 sequence = 0;
if (strcmp(command, "ping") != 0)
output(ANSI_GREEN "sending command: \033[m%s\n",command);
uint32 result = _sendAPIcommand(command, &sequence, block);
// if we're not waiting for a response, just return
if (!block) return SUCCESS;
// if the send wasn't successful, let's not wait for the result ;-)
if (result != SUCCESS && response) *response = NULL;
// wait for result here for sequence
if (response) *response = _tc_commandList_getResponse(sequence);
return SUCCESS;
}
static void* _keepalive_thread(void* param)
{
char* response;
// enable the keepalive mechanism in SmartSDR
uint32 ret_val = tc_sendSmartSDRcommand("keepalive enable", TRUE, &response);
if (ret_val != SUCCESS)
{
tc_abort();
return NULL;
}
if (response) free(response);
while (!_abort_keepalive)
{
// wait a second
usleep(1000000);
uint32 ret_val = tc_sendSmartSDRcommand("ping", FALSE, &response);
// must free the response if we got one
if (response) free (response);
// if we can't send a ping, all is lost and we must exit
if (ret_val != SUCCESS)
{
tc_abort();
break;
}
}
return NULL;
}
void tc_startKeepalive(void)
{
// Start the keepalive thread
pthread_create(&_keepalive_thread_id, NULL, &_keepalive_thread, NULL);
}
void tc_abort(void)
{
output(ANSI_RED "stopping Traffic Cop ...\n");
// stop the keepalive thread
_abort_keepalive = TRUE;
// stop the main TC thread
_abort = TRUE;
usleep(1000000);
exit(1);
}
void tc_Init(void)
{
_commandList_Init();
output("\033[32mStarting Traffic Cop...\n\033[m");
uint32 ret_val = pthread_create(&_tc_thread_id, NULL, &_tc_thread, NULL);
if (ret_val != 0) output("failed to start Traffic Cop thread\n");
}

View file

@ -0,0 +1,68 @@
///* \file traffic_cop.h
// * \brief TCP Communications Server
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef TRAFFIC_COP_H_
#define TRAFFIC_COP_H_
#include <semaphore.h>
#include "datatypes.h"
#include <time.h>
typedef struct _recieve
{
char* recv_buf;
char* read_ptr;
uint32 buf_len;
char* command;
BOOL keepalive_enabled;
struct timespec last_ping;
} receive_data;
typedef struct _cmd
{
uint32 sequence;
sem_t semaphore;
char* response;
struct _cmd *next;
struct _cmd *prev;
} command_type, *Command;
//! ask the TCP/IP command client to abort
void tc_Abort(void);
void tc_startKeepalive(void);
void tc_abort(void);
void tc_Init(void);
void SmartSDR_API_Init(void);
uint32 tc_sendSmartSDRcommand(char* command, BOOL block, char** response);
Command tc_commandList_respond(uint32 sequence, char* response);
#endif /* TRAFFIC_COP_H_ */

View file

@ -0,0 +1,142 @@
///* \file utils.c
// * \brief Utility Functions
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <unistd.h> // for usleep
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <pthread.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <inttypes.h>
#include <stdarg.h>
#include <semaphore.h>
#include "common.h"
static pthread_mutex_t _printf_mutex;
static pthread_mutex_t _malloc_mutex;
void lock_printf_init(void)
{
pthread_mutex_init(&_printf_mutex, NULL);
}
static void _output_stdio(const char *fmt, va_list args)
{
pthread_mutex_lock(&_printf_mutex);
vprintf(fmt, args);
pthread_mutex_unlock(&_printf_mutex);
}
void output(const char *fmt,...)
{
va_list args;
va_start(args, fmt);
_output_stdio(fmt, args);
va_end(args);
}
int32 tsSubtract(struct timespec time1, struct timespec time2)
{
int64 result;
result = (time1.tv_sec - time2.tv_sec) * 1000ll;
result += (time1.tv_nsec - time2.tv_nsec) / 1000000ll;
return (int32)result;
}
float tsfSubtract(struct timespec time1, struct timespec time2)
{
float result;
result = (time1.tv_sec - time2.tv_sec) * 1000.0;
result += (time1.tv_nsec - time2.tv_nsec) / 1000000.0;
return result;
}
//! get time since a certain time in microseconds
uint32 usSince(struct timespec time)
{
struct timespec delay;
clock_gettime(CLOCK_MONOTONIC, &delay);
uint32 diff_us = (uint32)(tsfSubtract(delay, time) * 1000.0);
return diff_us;
}
uint32 getIP(char* text)
{
uint32 ip;
int a,b,c,d;
// get IP address
sscanf(text, "%d.%d.%d.%d", &a,&b,&c,&d);
ip = (a << 24) + (b << 16) + (c << 8) + d;
return ip;
}
void lock_malloc_init(void)
{
pthread_mutex_init(&_malloc_mutex, NULL);
}
// thread-safe malloc
void* safe_malloc(size_t size)
{
void* pmem;
pthread_mutex_lock(&_malloc_mutex);
pmem = malloc(size);
pthread_mutex_unlock(&_malloc_mutex);
return pmem;
}
// thread-safe free
void safe_free(void* ptr)
{
pthread_mutex_lock(&_malloc_mutex);
if (ptr != NULL)
{
free(ptr);
}
else
{
output(ANSI_RED "Utils: attempt to free a NULL pointer\n");
}
pthread_mutex_unlock(&_malloc_mutex);
}
void printIP(uint32 ip)
{
output("%d.%d.%d.%d\n",((ip>>24)& 0xFF),((ip>>16)& 0xFF),((ip>>8)& 0xFF),(ip & 0xFF));
}

View file

@ -0,0 +1,49 @@
///* \file utils.h
// * \brief Utility Functions
// *
// * \copyright Copyright 2011-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 31-AUG-2014
// * \author Stephen Hicks, N5AC
// */
/* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef UTILS_H_
#define UTILS_H_
#include "common.h"
void lock_printf_init(void);
void output(const char *fmt,...);
void tsAdd(struct timespec* time1, struct timespec time2);
float tsfSubtract(struct timespec time1, struct timespec time2);
uint32 usSince(struct timespec time);
uint32 getIP(char* text);
void lock_malloc_init(void);
void* safe_malloc(size_t size);
void safe_free(void* ptr);
void printIP(uint32 ip);
#endif /* UTILS_H_ */

View file

@ -0,0 +1,138 @@
/* *****************************************************************************
* vita.h 2014 AUG 31
*
* Describes VITA 49 structures
*
* \date 2012-03-28
* \author Eric Wachsmann, KE5DTO
*
* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef _VITA_H
#define _VITA_H
#include <linux/if_ether.h>
#include "datatypes.h"
/* Packet Header Definitions */
#define VITA_HEADER_PACKET_TYPE_MASK 0xF0000000
#define VITA_PACKET_TYPE_IF_DATA 0x00000000
#define VITA_PACKET_TYPE_IF_DATA_WITH_STREAM_ID 0x10000000
#define VITA_PACKET_TYPE_EXT_DATA 0x20000000
#define VITA_PACKET_TYPE_EXT_DATA_WITH_STREAM_ID 0x30000000
#define VITA_PACKET_TYPE_CONTEXT 0x40000000
#define VITA_PACKET_TYPE_EXT_CONTEXT 0x50000000
#define VITA_HEADER_C_MASK 0x08000000
#define VITA_HEADER_CLASS_ID_PRESENT 0x08000000
#define VITA_HEADER_T_MASK 0x04000000
#define VITA_HEADER_TRAILER_PRESENT 0x04000000
#define VITA_HEADER_TSI_MASK 0x00C00000
#define VITA_TSI_NONE 0x00000000
#define VITA_TSI_UTC 0x00400000
#define VITA_TSI_GPS 0x00800000
#define VITA_TSI_OTHER 0x00C00000
#define VITA_HEADER_TSF_MASK 0x00300000
#define VITA_TSF_NONE 0x00000000
#define VITA_TSF_SAMPLE_COUNT 0x00100000
#define VITA_TSF_REAL_TIME 0x00200000
#define VITA_TSF_FREE_RUNNING 0x00300000
#define VITA_HEADER_PACKET_COUNT_MASK 0x000F0000
#define VITA_HEADER_PACKET_SIZE_MASK 0x0000FFFF
#define VITA_CLASS_ID_OUI_MASK 0x00FFFFFF
#define VITA_CLASS_ID_INFORMATION_CLASS_MASK 0xFFFF0000
#define VITA_CLASS_ID_PACKET_CLASS_MASK 0x0000FFFF
#pragma pack(4)
// 16 ip header
#define MAX_TCP_DATA_SIZE (ETH_DATA_LEN-16)
// 16 ip header, 6 udp header
#define MAX_UDP_DATA_SIZE (65535)
#define MAX_IF_DATA_PAYLOAD_SIZE (MAX_UDP_DATA_SIZE) //-28)
typedef struct _vita_if_data
{
uint32 header;
uint32 stream_id;
uint32 class_id_h;
uint32 class_id_l;
uint32 timestamp_int;
uint32 timestamp_frac_h;
uint32 timestamp_frac_l;
uint8 payload[MAX_IF_DATA_PAYLOAD_SIZE];
} vita_if_data, *VitaIFData;
#define MAX_METER_DATA_PAYLOAD_SIZE (MAX_UDP_DATA_SIZE) //-28)
typedef struct _vita_meter_data
{
uint32 header;
uint32 stream_id;
uint32 class_id_h;
uint32 class_id_l;
uint32 timestamp_int;
uint32 timestamp_frac_h;
uint32 timestamp_frac_l;
uint8 payload[MAX_METER_DATA_PAYLOAD_SIZE];
} vita_meter_data, *VitaMeterData;
#define MAX_METER_PAYLOAD_SIZE (MAX_UDP_DATA_SIZE) //-36)
typedef struct _vita_ext_data_meter
{
uint32 header;
uint32 streamID;
uint32 classID_1;
uint32 classID_2;
uint32 integer_seconds;
uint64 frac_seconds;
uint32 extended_packet_type; // = 1 is meter
uint32 number_of_meters;
uint8 payload[MAX_METER_PAYLOAD_SIZE];
} vita_ext_data_meter, *VitaExtDataMeter;
typedef struct _vita_timestamp
{
uint32 ts_int;
union
{
struct
{
uint32 ts_frac_h;
uint32 ts_frac_l;
};
uint64 ts_frac;
};
} vita_timestamp, *VitaTimestamp;
typedef uint32 vita_date;
#pragma pack()
#endif /* _VITA_H */

View file

@ -0,0 +1,127 @@
/* *****************************************************************************
* vita49_context.h
*
* VITA49 context
*
* \date 12-FEB-2011
* \author Stephen Hicks, N5AC
*
* *****************************************************************************
*
* Copyright (C) 2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef VITA49_CONTEXT_H_
#define VITA49_CONTEXT_H_
#include "../common.h"
#define VITA_C_CONTEXT_FIELD_CHG_INDICATOR 0x80000000
#define VITA_C_REFERENCE_POINT_IDENTIFIER 0x40000000
#define VITA_C_BANDWIDTH 0x20000000
#define VITA_C_IF_REFERENCE_FREQ 0x10000000
#define VITA_C_RF_REFERENCE_FREQ 0x08000000
#define VITA_C_RF_REFERENCE_FREQ_OFFSET 0x04000000
#define VITA_C_IF_BAND_OFFSET 0x02000000
#define VITA_C_REFERENCE_LEVEL 0x01000000
#define VITA_C_GAIN 0x00800000
#define VITA_C_OVER_RANGE_COUNT 0x00400000
#define VITA_C_SAMPLE_RATE 0x00200000
#define VITA_C_TIMESTAMP_ADJUSTMENT 0x00100000
#define VITA_C_TIMESTAMP_CALIBRATION_TIME 0x00080000
#define VITA_C_TEMPERATURE 0x00040000
#define VITA_C_DEVICE_IDENTIFIER 0x00020000
#define VITA_C_STATE_AND_EVENT_INDICATORS 0x00010000
#define VITA_C_DATA_PACKET_PAYLOAD_FORMAT 0x00008000
#define VITA_C_FORMATTED_GPS_GEOLOCATION 0x00004000
#define VITA_C_FORMATTED_INS_LOCATION 0x00002000
#define VITA_C_ECEF_EPHEMERIS 0x00001000
#define VITA_C_RELATIVE_EPHEMERIS 0x00000800
#define VITA_C_EPHEMERIS_REFERENCE_IND 0x00000400
#define VITA_C_GPS_ASCII 0x00000200
#define VITA_C_CONTEXT_ASSOCIATION_LISTS 0x00000100
#define VITA_C_RESERVED 0x000000FF
// bit positions for status and indicator fields
#define VITA_S_CALIBRATED_TIME_E 0x80000000
#define VITA_S_VALID_DATA_E 0x40000000
#define VITA_S_REFERENCE_LOCK_E 0x20000000
#define VITA_S_AGC_INDICATOR_E 0x10000000
#define VITA_S_DETECTED_SIGNAL_E 0x08000000
#define VITA_S_SPECTRAL_INVERSION_E 0x04000000
#define VITA_S_OVER_RANGE_E 0x02000000
#define VITA_S_SAMPLE_LOSS_E 0x01000000
#define VITA_S_CALIBRATED_TIME_I 0x00080000
#define VITA_S_VALID_DATA_I 0x00040000
#define VITA_S_REFERENCE_LOCK_I 0x00020000
#define VITA_S_AGC_INDICATOR_I 0x00010000
#define VITA_S_DETECTED_SIGNAL_I 0x00008000
#define VITA_S_SPECTRAL_INVERSION_I 0x00004000
#define VITA_S_OVER_RANGE_I 0x00002000
#define VITA_S_SAMPLE_LOSS_I 0x00001000
#define VITA_P_PACKING_METHOD 0x0 << 31 // we are processing efficient
#define VITA_P_REAL_COMPLEX 0x1 << 28 // complex cartesian
#define VITA_P_DATA_ITEM_FORMAT 0x00 << 24 // signed, fixed point
#define VITA_P_SAMPLE_REPEAT 0x0 << 23 // no sample-component repeating
#define VITA_P_EVENT_TAG_SIZE 0x0 << 20 // no event tags
#define VITA_P_CHANNEL_TAG_SIZE 0x0 << 18 // no channel tags
#define VITA_P_ITEM_PACKING_FIELD_SIZE 32 << 6 // 32-bit fields
#define VITA_P_DATA_ITEM_SIZE 24 // 24-bits per item
#define VITA_P_REPEAT_COUNT 0 << 16 // no repeating
#define VITA_P_VECTOR_SIZE 0 // no vectors
#define VITA_P_PACKING_H VITA_P_PACKING_METHOD | \
VITA_P_REAL_COMPLEX | \
VITA_P_DATA_ITEM_FORMAT | \
VITA_P_SAMPLE_REPEAT | \
VITA_P_EVENT_TAG_SIZE | \
VITA_P_CHANNEL_TAG_SIZE | \
VITA_P_ITEM_PACKING_FIELD_SIZE | \
VITA_P_DATA_ITEM_SIZE
#define VITA_P_PACKING_L VITA_P_REPEAT_COUNT | \
VITA_P_VECTOR_SIZE
#define VITA_PERIODIC 1000 // send out packets once per second even if no changes (in ms)
typedef struct _context
{
uint32 header;
uint32 streamID;
uint32 classID_H;
uint32 classID_L;
// uint32 timestamp_sec; // we'll add these later
// uint64 timestamp_frac;
uint32 context_indicator;
uint64 bandwidth;
uint64 if_reference;
uint64 rf_reference;
uint32 reference_level;
uint16 gain2;
uint16 gain1;
uint64 sample_rate;
uint32 state_event_ind;
uint32 packet_format_H;
uint32 packet_format_L;
} vitacontext_type, *VITACONTEXT;
#endif /* VITA49_CONTEXT_H_ */

View file

@ -0,0 +1,204 @@
///*! \file vita_output.c
// * \brief transmit vita packets to the Ethernet
// *
// * \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 2-APR-2012
// * \author Stephen Hicks, N5AC
// *
// */
/* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#include <sys/socket.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> // for write, usleep
#include <errno.h>
#include "vita_output.h"
#include "common.h"
#include "hal_listener.h"
extern int errno;
#define FORMAT_DBFS 0
#define FORMAT_DBM 1
#define VITA_CLASS_ID_1 (uint32)VITA_OUI
#define VITA_CLASS_ID_2 SL_VITA_INFO_CLASS << 16 | SL_VITA_IF_DATA_CLASS
#define MAX_SAMPLES_PER_PACKET (MAX_IF_DATA_PAYLOAD_SIZE/8)
#define MAX_BINS_PER_PACKET 700
// local variable declarations
static vita_if_data waveform_packet;
static int vita_sock;
static struct sockaddr_in vita_sLocalAddr, vita_sDestAddrIf;
static uint32 _local_ip_addr;
static uint16 _dest_port;
void vita_output_Init(void)
{
output("\033[32mInitializing VITA-49 output engine...\n\033[m");
vita_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (vita_sock < 0)
{
output(ANSI_RED " Failed to initialize VITA socket\n");
return;
}
bind(vita_sock, (struct sockaddr *)&vita_sLocalAddr, sizeof(vita_sLocalAddr));
if (errno)
{
output(ANSI_RED "error binding socket: errno=%d\n",errno);
}
memset((char *)&vita_sLocalAddr, 0, sizeof(vita_sLocalAddr));
memset((char *)&vita_sDestAddrIf, 0, sizeof(vita_sDestAddrIf));
// IF Destination
vita_sDestAddrIf.sin_family = AF_INET;
vita_sDestAddrIf.sin_addr.s_addr = htonl(0xC0A8145D); // 192.168.20.108, used to be 192.168.30.40
vita_sDestAddrIf.sin_port = htons(VITA_49_PORT);
memset(&vita_sDestAddrIf.sin_zero, 0, sizeof(vita_sDestAddrIf.sin_zero));
// Source
vita_sLocalAddr.sin_family = AF_INET;
vita_sLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
vita_sLocalAddr.sin_port = htons(VITA_49_SOURCE_PORT);
memset(&vita_sLocalAddr.sin_zero, 0, sizeof(vita_sLocalAddr.sin_zero));
struct in_addr addr;
if ( inet_aton("127.0.0.1", &addr) == 0) {
output(ANSI_RED "Could not convert local addr to binary\n");
} else {
_local_ip_addr = ntohl(addr.s_addr);
}
_dest_port = 4991;
// output("host = %d.%d.%d.%d : %d", ip>>24, (ip>>16)&0xFF, (ip>>8)&0xFF, ip&0xFF, _dest_port);
}
void UDPSendByIPandPort(void* packet, uint32 num_bytes, uint32 ip_address, uint16 udp_port)
{
struct sockaddr_in sock;
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = htonl(ip_address);
sock.sin_port = htons(udp_port);
errno = 0;
int32 ret_val = sendto(vita_sock, packet, num_bytes, 0, (struct sockaddr*)&sock, sizeof(sock));
if ( errno || ret_val < 0) {
output( "Error sending packet: errno%d \n", errno);
}
}
static void _vita_formatWaveformPacket(Complex* buffer, uint32 samples, uint32 stream_id, uint32 packet_count,
uint32 class_id_h, uint32 class_id_l, uint32 ip_addr, uint16 port)
{
waveform_packet.header = htonl(
VITA_PACKET_TYPE_IF_DATA_WITH_STREAM_ID |
VITA_HEADER_CLASS_ID_PRESENT |
VITA_TSI_OTHER |
VITA_TSF_SAMPLE_COUNT |
(packet_count << 16) |
(7+samples*2));
waveform_packet.stream_id = htonl(stream_id);
waveform_packet.class_id_h = htonl(class_id_h);
waveform_packet.class_id_l = htonl(class_id_l);
waveform_packet.timestamp_int = 0;
waveform_packet.timestamp_frac_h = 0;
waveform_packet.timestamp_frac_l = 0;
memcpy(waveform_packet.payload, buffer, samples * sizeof(Complex));
//HAL_update_count(stream_id, class_id_h, class_id_l, samples * 8 + 28, HAL_STATUS_OUTPUT_OK, OUTPUT, WFM, ip_addr, port);
}
static uint32 _waveform_packet_count = 0;
void emit_waveform_output(BufferDescriptor buf_desc_out)
{
int samples_sent, samples_to_send;
Complex * buf_pointer;
if (buf_desc_out == NULL)
{
output(ANSI_RED "buf_desc_out is NULL\n");
return;
}
if (buf_desc_out->buf_ptr == NULL)
{
output(ANSI_RED "buf_desc_out->buf_ptr is NULL\n");
return;
}
Complex* out_buffer = (Complex*)buf_desc_out->buf_ptr;
uint32 buf_size = buf_desc_out->num_samples;
// convert to big endian for network
int i;
for(i=0; i<buf_size; i++)
{
*(uint32*)&out_buffer[i].real = htonl(*(uint32*)&out_buffer[i].real);
*(uint32*)&out_buffer[i].imag = htonl(*(uint32*)&out_buffer[i].imag);
}
samples_sent = 0;
buf_pointer = out_buffer;
uint32 preferred_samples_per_packet = buf_size;
//output("samples_to_send: %d\n", preferred_samples_per_packet);
while (samples_sent < buf_size)
{
if ((buf_size - samples_sent) > preferred_samples_per_packet)
{
samples_to_send = preferred_samples_per_packet;
}
else
{
samples_to_send = buf_size - samples_sent;
}
//output("samples_to_send: %d\n", samples_to_send);
_vita_formatWaveformPacket(
buf_pointer,
samples_to_send,
buf_desc_out->stream_id,
_waveform_packet_count++ & 0xF,
(uint32) FLEXRADIO_OUI,
SL_VITA_SLICE_AUDIO_CLASS,
_local_ip_addr,
4991);
buf_pointer += samples_to_send;
samples_sent += samples_to_send;
vita_sLocalAddr.sin_port = htons(VITA_49_SOURCE_PORT);
UDPSendByIPandPort(&waveform_packet, samples_to_send * 8 + 28, _local_ip_addr, 4991);
}
}

View file

@ -0,0 +1,50 @@
///*! \file vita_output.h
// * \brief transmit vita packets to the Ethernet
// *
// * \copyright Copyright 2012-2013 FlexRadio Systems. All Rights Reserved.
// * Unauthorized use, duplication or distribution of this software is
// * strictly prohibited by law.
// *
// * \date 2-APR-2012
// * \author Stephen Hicks, N5AC
// *
// */
/* *****************************************************************************
*
* Copyright (C) 2012-2014 FlexRadio Systems.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact Information:
* email: gpl<at>flexradiosystems.com
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
*
* ************************************************************************** */
#ifndef VITA_OUTPUT_H_
#define VITA_OUTPUT_H_
#include <sys/socket.h>
#include <netinet/in.h>
#include "common.h"
#include "complex.h"
#include "hal_buffer.h"
void vita_output_Init();
void UDPSendByIPandPort(void* packet, uint32 num_bytes, uint32 ip_address, uint16 udp_port);
void emit_waveform_output(BufferDescriptor buf_desc_out);
#endif /* VITA_OUTPUT_H_ */