mirror of
https://github.com/n5ac/smartsdr-dsp.git
synced 2026-04-06 23:03:47 +00:00
Initial load of CODEC2/FreeDV software and wrapper
This commit is contained in:
parent
f524f31e45
commit
cea38b61ea
204 changed files with 41852 additions and 0 deletions
81
DSP_API/SmartSDR_Interface/cmd.h
Normal file
81
DSP_API/SmartSDR_Interface/cmd.h
Normal 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_ */
|
||||
282
DSP_API/SmartSDR_Interface/cmd_basics.c
Normal file
282
DSP_API/SmartSDR_Interface/cmd_basics.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
347
DSP_API/SmartSDR_Interface/cmd_engine.c
Normal file
347
DSP_API/SmartSDR_Interface/cmd_engine.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
61
DSP_API/SmartSDR_Interface/complex.h
Normal file
61
DSP_API/SmartSDR_Interface/complex.h
Normal 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_ */
|
||||
65
DSP_API/SmartSDR_Interface/datatypes.h
Normal file
65
DSP_API/SmartSDR_Interface/datatypes.h
Normal 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
|
||||
320
DSP_API/SmartSDR_Interface/discovery_client.c
Normal file
320
DSP_API/SmartSDR_Interface/discovery_client.c
Normal 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;
|
||||
}
|
||||
54
DSP_API/SmartSDR_Interface/discovery_client.h
Normal file
54
DSP_API/SmartSDR_Interface/discovery_client.h
Normal 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_
|
||||
133
DSP_API/SmartSDR_Interface/hal_buffer.c
Normal file
133
DSP_API/SmartSDR_Interface/hal_buffer.c
Normal 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;
|
||||
}
|
||||
83
DSP_API/SmartSDR_Interface/hal_buffer.h
Normal file
83
DSP_API/SmartSDR_Interface/hal_buffer.h
Normal 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
|
||||
568
DSP_API/SmartSDR_Interface/hal_listener.c
Normal file
568
DSP_API/SmartSDR_Interface/hal_listener.c
Normal 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);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
115
DSP_API/SmartSDR_Interface/hal_listener.h
Normal file
115
DSP_API/SmartSDR_Interface/hal_listener.h
Normal 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
|
||||
67
DSP_API/SmartSDR_Interface/hal_vita.c
Normal file
67
DSP_API/SmartSDR_Interface/hal_vita.c
Normal 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;
|
||||
}
|
||||
39
DSP_API/SmartSDR_Interface/hal_vita.h
Normal file
39
DSP_API/SmartSDR_Interface/hal_vita.h
Normal 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 */
|
||||
58
DSP_API/SmartSDR_Interface/io_utils.c
Normal file
58
DSP_API/SmartSDR_Interface/io_utils.c
Normal 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;
|
||||
}
|
||||
50
DSP_API/SmartSDR_Interface/io_utils.h
Normal file
50
DSP_API/SmartSDR_Interface/io_utils.h
Normal 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_ */
|
||||
703
DSP_API/SmartSDR_Interface/sched_waveform.c
Normal file
703
DSP_API/SmartSDR_Interface/sched_waveform.c
Normal 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);
|
||||
}
|
||||
45
DSP_API/SmartSDR_Interface/sched_waveform.h
Normal file
45
DSP_API/SmartSDR_Interface/sched_waveform.h
Normal 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_ */
|
||||
307
DSP_API/SmartSDR_Interface/smartsdr_dsp_api.c
Normal file
307
DSP_API/SmartSDR_Interface/smartsdr_dsp_api.c
Normal 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;
|
||||
}
|
||||
|
||||
52
DSP_API/SmartSDR_Interface/smartsdr_dsp_api.h
Normal file
52
DSP_API/SmartSDR_Interface/smartsdr_dsp_api.h
Normal 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_ */
|
||||
207
DSP_API/SmartSDR_Interface/status_processor.c
Normal file
207
DSP_API/SmartSDR_Interface/status_processor.c
Normal 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;
|
||||
}
|
||||
}
|
||||
40
DSP_API/SmartSDR_Interface/status_processor.h
Normal file
40
DSP_API/SmartSDR_Interface/status_processor.h
Normal 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_ */
|
||||
72
DSP_API/SmartSDR_Interface/stream.h
Normal file
72
DSP_API/SmartSDR_Interface/stream.h
Normal 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
|
||||
|
||||
|
||||
|
||||
612
DSP_API/SmartSDR_Interface/traffic_cop.c
Normal file
612
DSP_API/SmartSDR_Interface/traffic_cop.c
Normal 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");
|
||||
}
|
||||
68
DSP_API/SmartSDR_Interface/traffic_cop.h
Normal file
68
DSP_API/SmartSDR_Interface/traffic_cop.h
Normal 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_ */
|
||||
142
DSP_API/SmartSDR_Interface/utils.c
Normal file
142
DSP_API/SmartSDR_Interface/utils.c
Normal 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));
|
||||
}
|
||||
|
||||
49
DSP_API/SmartSDR_Interface/utils.h
Normal file
49
DSP_API/SmartSDR_Interface/utils.h
Normal 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_ */
|
||||
138
DSP_API/SmartSDR_Interface/vita.h
Normal file
138
DSP_API/SmartSDR_Interface/vita.h
Normal 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 */
|
||||
127
DSP_API/SmartSDR_Interface/vita49_context.h
Normal file
127
DSP_API/SmartSDR_Interface/vita49_context.h
Normal 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_ */
|
||||
204
DSP_API/SmartSDR_Interface/vita_output.c
Normal file
204
DSP_API/SmartSDR_Interface/vita_output.c
Normal 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);
|
||||
}
|
||||
}
|
||||
50
DSP_API/SmartSDR_Interface/vita_output.h
Normal file
50
DSP_API/SmartSDR_Interface/vita_output.h
Normal 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_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue