kopia lustrzana https://github.com/pa3gsb/Radioberry-2.x
796 wiersze
23 KiB
C
796 wiersze
23 KiB
C
/*
|
|
* Copyright (C)
|
|
* 2018 - Johan Maas, PA3GSB
|
|
*
|
|
* 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
*
|
|
* Hermes Lite Emulator.
|
|
*
|
|
* By using this emulator you have the possibility to connect to SDR programs like:
|
|
* - linHPSDR
|
|
* - pihpsdr
|
|
* - Thetis
|
|
*
|
|
* SDR software packages supporting the 'HPSDR protocol-2' should be connected to the emulator.
|
|
*
|
|
* This emulator works with the Radioberry radiocard plugged into a rpi-3.
|
|
*
|
|
* http://www.pa3gsb.nl
|
|
*
|
|
* 2018 Johan PA3GSB
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <net/if_arp.h>
|
|
#include <net/if.h>
|
|
#include <ifaddrs.h>
|
|
#include <semaphore.h>
|
|
#include <math.h>
|
|
#include <malloc.h>
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <linux/if_packet.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/if_ether.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/udp.h>
|
|
#include <netinet/tcp.h>
|
|
#include <sys/time.h>
|
|
#include "udp.h"
|
|
#include <pigpio.h>
|
|
#include <getopt.h>
|
|
|
|
#include "hermeslite.h"
|
|
#include "local_audio_discovery.h"
|
|
#include "audio.h"
|
|
#include "mic.h"
|
|
|
|
static long rx1_sequence = 0;
|
|
static long rx2_sequence = 0;
|
|
static char sdr_client_addr[20];
|
|
static char radioberry_addr[20];
|
|
static long status_sequence = 0;
|
|
static long mic_sequence = 0;
|
|
static long mic_count=4;
|
|
|
|
static struct sockaddr_in src_addr[8];
|
|
static struct sockaddr_in dst_addr;
|
|
|
|
static struct sockaddr_in high_priority_addr;
|
|
static int high_priority_addr_length;
|
|
|
|
static struct sockaddr_in mic_line_addr;
|
|
static int mic_line_addr_length;
|
|
|
|
int radioberry_socket=-1;
|
|
int discover_socket=-1;
|
|
int remote_port =0;
|
|
|
|
unsigned char broadcastReply[60];
|
|
|
|
static int rx1_spi_handler;
|
|
static int rx2_spi_handler;
|
|
|
|
int use_local_audio_in = 0;
|
|
int use_local_audio_out = 0;
|
|
|
|
static int running = 0;
|
|
static int nrx = 1;
|
|
static int sampleSpeed[MAX_RECEIVERS];
|
|
static int ddc[MAX_RECEIVERS];
|
|
static int ptt = 0;
|
|
static int gain = 0;
|
|
static int dither = 1;
|
|
|
|
static int rxfreq1 = 4706000;
|
|
static int rxfreq2 = 1008000;
|
|
static int txfreq = 3630000;
|
|
|
|
unsigned char drive_level;
|
|
unsigned char prev_drive_level = -1;
|
|
|
|
sem_t mutex;
|
|
sem_t mic_sample;
|
|
static sem_t high_priority_mutex;
|
|
|
|
struct timeval t1;
|
|
struct timeval t2;
|
|
struct timeval t1a;
|
|
struct timeval t2a;
|
|
|
|
static int lcount=0;
|
|
static int lcounta=0;
|
|
static int lseq=-1;
|
|
|
|
static int cw = 0;
|
|
static int cw_keyer_speed = 0;
|
|
static int cw_keyer_weight = 0;
|
|
static int cw_iambic_mode = 0;
|
|
static int cw_keyer_reverse = 0;
|
|
static int cw_break_in = 0;
|
|
static int cw_ptt = 0;
|
|
|
|
#define SHORT_OPTIONS "lha:m:v"
|
|
#define HST_SHRT_OPTS ""
|
|
|
|
static struct option long_options[] =
|
|
{
|
|
{"list-audio-devices", 0, 0, 'l'},
|
|
{"audio-out", 1, 0, 'a'},
|
|
{"audio-in", 1, 0, 'm'},
|
|
{"help", 0, 0, 'h'},
|
|
{"version", 0, 0, 'v'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
const char *version = "Radioberry hermeslite emulator version 08-28-2018";
|
|
const char *copyright =
|
|
"Copyright (C) 2018 Johan Maas, PA3GSB\n"
|
|
"This is free software; see the source for copying conditions. There is NO\n"
|
|
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.";
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
printIntroScreen();
|
|
if (argc == 1) usage();
|
|
|
|
audio_get_cards();
|
|
|
|
while (1)
|
|
{
|
|
int c;
|
|
int option_index = 0;
|
|
c = getopt_long(argc,
|
|
argv,
|
|
SHORT_OPTIONS HST_SHRT_OPTS,
|
|
long_options,
|
|
&option_index);
|
|
if (c == -1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (c)
|
|
{
|
|
case 'h':
|
|
usage();
|
|
exit(0);
|
|
case 'v':
|
|
print_version();
|
|
exit(0);
|
|
case 'l':
|
|
discover_audio_cards();
|
|
exit(0);
|
|
case 'a':
|
|
if (!optarg)
|
|
{
|
|
usage(); /* wrong arg count */
|
|
exit(1);
|
|
}
|
|
use_local_audio_out = 1;
|
|
audio_open_output(selectAudioOutputDevice(atoi(optarg)));
|
|
break;
|
|
case 'm':
|
|
if (!optarg)
|
|
{
|
|
usage(); /* wrong arg count */
|
|
exit(1);
|
|
}
|
|
use_local_audio_in = 1;
|
|
audio_open_input(selectAudioInputDevice(atoi(optarg)));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
sem_init(&mutex, 0, 1);
|
|
sem_init(&mic_sample, 0, 0);
|
|
sem_init(&high_priority_mutex, 0, 0);
|
|
|
|
initialize_gpio();
|
|
|
|
fprintf(stderr, "\n\nhermeslite protocol-2 emulator started \n\n");
|
|
|
|
pthread_t pid1;
|
|
pthread_create(&pid1, NULL, send_rx_iq_to_host, NULL);
|
|
|
|
pthread_t pid2;
|
|
pthread_create(&pid2, NULL, send_high_priority_status_to_host, NULL);
|
|
|
|
gettimeofday(&t1a, 0);
|
|
if (use_local_audio_in==0) start_dummy_mic_thread(); else start_mic_thread();
|
|
|
|
gettimeofday(&t1, 0);
|
|
|
|
handle_data_from_sdr_program();
|
|
|
|
audio_close_output();
|
|
|
|
fprintf(stderr, "hermeslite protocol-2 emulator stopped. \n");
|
|
}
|
|
|
|
void setup_isr_handler(int pin, gpioAlertFunc_t pAlert) {
|
|
gpioSetMode(pin, PI_INPUT);
|
|
gpioSetPullUpDown(pin,PI_PUD_UP);
|
|
usleep(10000); // give time to settle to avoid false triggers
|
|
gpioSetAlertFunc(pin, pAlert);
|
|
gpioGlitchFilter(pin, HANDLER_STEADY_TIME_US);
|
|
}
|
|
|
|
void cw_ptt_alert(int gpio, int level, uint32_t tick) {
|
|
fprintf(stderr, "cw - alert; cw_break_in = %d and cw-mode = %d\n", cw_break_in, cw);
|
|
if (running && cw_break_in && cw){
|
|
cw_ptt = level;
|
|
sem_post(&high_priority_mutex);
|
|
}
|
|
}
|
|
|
|
float timedifference_msec(struct timeval t0, struct timeval t1)
|
|
{
|
|
return (t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec - t0.tv_usec) / 1000.0f;
|
|
}
|
|
|
|
int handle_data_from_sdr_program() {
|
|
int emulator_socket = -1;
|
|
int saddr_len,buflen;
|
|
struct sockaddr_in saddr;
|
|
unsigned char* buffer = (unsigned char *)malloc(65536);
|
|
memset(buffer,0,65536);
|
|
|
|
emulator_socket=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
|
|
if(emulator_socket<0)
|
|
{
|
|
printf("error in socket\n");
|
|
return -1;
|
|
}
|
|
while(1)
|
|
{
|
|
saddr_len=sizeof saddr;
|
|
buflen=recvfrom(emulator_socket,buffer,65536,0,(struct sockaddr *) &saddr,(socklen_t *)&saddr_len);
|
|
if(buflen<0)
|
|
{
|
|
perror("hermeslite protocol-2 emulator stops unexpectedly");
|
|
return -1;
|
|
}
|
|
handle_packets_from_sdr_program(buffer,buflen);
|
|
}
|
|
close(emulator_socket);
|
|
}
|
|
|
|
int initialize_gpio() {
|
|
if (gpioInitialise() < 0) {
|
|
perror("hpsdr protocol-2: gpio could not be initialized. \n");
|
|
exit(-1);
|
|
}
|
|
gpioSetMode(13, PI_INPUT); //rx1 samples
|
|
gpioSetMode(16, PI_INPUT); //rx2 samples
|
|
gpioSetMode(20, PI_INPUT);
|
|
gpioSetMode(21, PI_OUTPUT);
|
|
|
|
rx1_spi_handler = spiOpen(0, 15625000, 49155); //channel 0
|
|
if (rx1_spi_handler < 0) {
|
|
perror("radioberry_protocol: spi bus rx1 could not be initialized. \n");
|
|
exit(-1);
|
|
}
|
|
rx2_spi_handler = spiOpen(1, 15625000, 49155); //channel 1
|
|
if (rx2_spi_handler < 0) {
|
|
perror("radioberry_protocol: spi bus rx2 could not be initialized. \n");
|
|
exit(-1);
|
|
}
|
|
//setup cw interrupt service routine;
|
|
//keyer attached to fpga is touched=> set radioberry in tx mode.
|
|
setup_isr_handler(17, cw_ptt_alert);
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned char l_mic_buffer[132];
|
|
void process_local_mic(unsigned char *mic_buffer){
|
|
int i=0;
|
|
|
|
if (running) {
|
|
for(i=0;i<MIC_SAMPLES;i++) {
|
|
l_mic_buffer[mic_count++] = mic_buffer[i*2+1]; //msb
|
|
l_mic_buffer[mic_count++] = mic_buffer[i*2];
|
|
|
|
/* making verbose function.....
|
|
lcounta ++;
|
|
if (lcounta == 48000) {
|
|
lcounta = 0;
|
|
gettimeofday(&t2a, 0);
|
|
float elapsd = timedifference_msec(t1a, t2a);
|
|
printf("Audio line-in executed in %f milliseconds.\n", elapsd);
|
|
gettimeofday(&t1a, 0);
|
|
}
|
|
*/
|
|
|
|
}
|
|
l_mic_buffer[0]=mic_sequence>>24;
|
|
l_mic_buffer[1]=mic_sequence>>16;
|
|
l_mic_buffer[2]=mic_sequence>>8;
|
|
l_mic_buffer[3]=mic_sequence;
|
|
send_udp_packet(radioberry_socket, mic_line_addr, dst_addr, l_mic_buffer, 132);
|
|
mic_sequence++;
|
|
mic_count = 4;
|
|
}
|
|
}
|
|
|
|
void *send_high_priority_status_to_host(void *arg) {
|
|
unsigned char* status_buffer = (unsigned char *)malloc(60);
|
|
memset(status_buffer,0,60);
|
|
|
|
while(1) {
|
|
if (running) {
|
|
sem_wait(&high_priority_mutex);
|
|
|
|
fprintf(stderr, "send high priority status to host. \n");
|
|
|
|
status_buffer[0]=status_sequence>>24;
|
|
status_buffer[1]=status_sequence>>16;
|
|
status_buffer[2]=status_sequence>>8;
|
|
status_buffer[3]=status_sequence;
|
|
status_buffer[4]= (cw_ptt & 0x01);
|
|
send_udp_packet(radioberry_socket, high_priority_addr, dst_addr, status_buffer, 60);
|
|
status_sequence++;
|
|
} else {usleep(20000);}
|
|
}
|
|
}
|
|
|
|
void *send_rx_iq_to_host(void *arg) {
|
|
unsigned char* iqbuffer_rx1 = (unsigned char *)malloc(2048);
|
|
memset(iqbuffer_rx1,0,2048);
|
|
unsigned char* iqbuffer_rx2 = (unsigned char *)malloc(2048);
|
|
memset(iqbuffer_rx2,0,2048);
|
|
unsigned char iqdata[6];
|
|
unsigned int index_rx1 = 16;
|
|
unsigned int index_rx2 = 16;
|
|
|
|
iqbuffer_rx1[12] = 0x00; iqbuffer_rx2[12] = 0x00; //MSB bitspersample
|
|
iqbuffer_rx1[13] = 0x18; iqbuffer_rx2[13] = 0x18; //LSB bitspersample 24 bits / sample.
|
|
iqbuffer_rx1[14] = 0x00; iqbuffer_rx2[14] = 0x00; //MSB samplesperframe
|
|
iqbuffer_rx1[15] = 0xEE; iqbuffer_rx2[15] = 0xEE; //LSB samplesperframe 144-16 / 6 = 238 IQ samples
|
|
|
|
while(1) {
|
|
if (running) {
|
|
|
|
while (ptt) {usleep(20000);}
|
|
|
|
sem_wait(&mutex);
|
|
|
|
gpioWrite(21, 0); // ptt off
|
|
|
|
if (gpioRead(13) == 1) {
|
|
int i =0;
|
|
for (i; i< 64; i++){
|
|
rx1_spiReader(iqdata);
|
|
int j =0;
|
|
for (j; j< 6; j++){
|
|
iqbuffer_rx1[index_rx1++] = iqdata[j];
|
|
}
|
|
sem_post(&mic_sample); //sync mic stream
|
|
if (index_rx1 >= 1444) {
|
|
iqbuffer_rx1[0]=rx1_sequence>>24;
|
|
iqbuffer_rx1[1]=rx1_sequence>>16;
|
|
iqbuffer_rx1[2]=rx1_sequence>>8;
|
|
iqbuffer_rx1[3]=rx1_sequence;
|
|
|
|
send_udp_packet(radioberry_socket, src_addr[ddc[0]], dst_addr, iqbuffer_rx1, 1444);
|
|
|
|
index_rx1 = 16;
|
|
rx1_sequence++;
|
|
}
|
|
}
|
|
}
|
|
if (nrx == 2) {
|
|
if (gpioRead(16) == 1) {
|
|
int i =0;
|
|
for (i; i< 64; i++){
|
|
//rx2_spiReader(iqdata);
|
|
int j =0;
|
|
for (j; j< 6; j++){
|
|
iqbuffer_rx2[index_rx2++] = 0;//iqdata[j];
|
|
}
|
|
}
|
|
if (index_rx2 >= 1444) {
|
|
iqbuffer_rx2[0]=rx2_sequence>>24;
|
|
iqbuffer_rx2[1]=rx2_sequence>>16;
|
|
iqbuffer_rx2[2]=rx2_sequence>>8;
|
|
iqbuffer_rx2[3]=rx2_sequence;
|
|
|
|
send_udp_packet(radioberry_socket, src_addr[ddc[1]], dst_addr, iqbuffer_rx2, 1444);
|
|
|
|
index_rx2 = 16;
|
|
rx2_sequence++;
|
|
}
|
|
}
|
|
}
|
|
sem_post(&mutex);
|
|
} else {usleep(20000);}
|
|
}
|
|
}
|
|
|
|
void rx1_spiReader(unsigned char iqdata[]) {
|
|
iqdata[0] = (sampleSpeed[0] & 0x03);
|
|
iqdata[1] = (~(gain & 0x2F)) | 0x40; // set cw@fpga
|
|
iqdata[2] = ((rxfreq1 >> 24) & 0xFF);
|
|
iqdata[3] = ((rxfreq1 >> 16) & 0xFF);
|
|
iqdata[4] = ((rxfreq1 >> 8) & 0xFF);
|
|
iqdata[5] = (rxfreq1 & 0xFF);
|
|
|
|
spiXfer(rx1_spi_handler, iqdata, iqdata, 6);
|
|
}
|
|
|
|
void rx2_spiReader(unsigned char iqdata[]) {
|
|
iqdata[0] = (sampleSpeed[0] & 0x03);
|
|
iqdata[1] = (~(gain & 0x2F));
|
|
iqdata[2] = ((rxfreq2 >> 24) & 0xFF);
|
|
iqdata[3] = ((rxfreq2 >> 16) & 0xFF);
|
|
iqdata[4] = ((rxfreq2 >> 8) & 0xFF);
|
|
iqdata[5] = (rxfreq2 & 0xFF);
|
|
|
|
spiXfer(rx2_spi_handler, iqdata, iqdata, 6);
|
|
}
|
|
|
|
void handle_packets_from_sdr_program(unsigned char* buffer,int buflen) {
|
|
int iphdrlen;
|
|
struct iphdr *ip = (struct iphdr*)(buffer + sizeof (struct ethhdr));
|
|
|
|
if (ip->protocol == 17) {
|
|
iphdrlen =ip->ihl*4;
|
|
struct udphdr *udp = (struct udphdr*)(buffer + iphdrlen + sizeof(struct ethhdr));
|
|
unsigned char * data = (buffer + iphdrlen + sizeof(struct ethhdr) + sizeof(struct udphdr));
|
|
int remaining_data = buflen - (iphdrlen + sizeof(struct ethhdr) + sizeof(struct udphdr));
|
|
|
|
switch (ntohs(udp->dest)) {
|
|
case GENERAL_REGISTERS_FROM_HOST_PORT:
|
|
if (radioberry_socket == -1) {
|
|
struct sockaddr_in remaddr;
|
|
memset((char *)&remaddr, 0, sizeof(remaddr));
|
|
remaddr.sin_addr.s_addr = ip->daddr;
|
|
strcpy(radioberry_addr, inet_ntoa(remaddr.sin_addr));
|
|
remote_port = udp->source;
|
|
}
|
|
if (data[4] == 2) {
|
|
handleDiscovery(buffer);
|
|
} //else if (data[0] != 0xEF & data[1] != 0xFE && data[2] != 0x02 && data[4] == 0) {
|
|
//fprintf(stderr,"GENERAL PACKET FROM HOST --- which info is important?\n");}
|
|
break;
|
|
case RECEIVER_SPECIFIC_REGISTERS_FROM_HOST_PORT:
|
|
receiver_specific_registers_from_host_port(data);
|
|
break;
|
|
case TRANSMITTER_SPECIFIC_REGISTERS_FROM_HOST_PORT:
|
|
transmitter_specific_registers_from_host_port(data);
|
|
break;
|
|
case HIGH_PRIORITY_FROM_HOST_PORT:
|
|
high_priority_from_host_port(data);
|
|
break;
|
|
case AUDIO_FROM_HOST_PORT:
|
|
audio_write(data);
|
|
break;
|
|
case TX_IQ_FROM_HOST_PORT:
|
|
tx_iq_from_host_port(data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void receiver_specific_registers_from_host_port(unsigned char* data) {
|
|
// the radioberry suports 2 ddc.
|
|
int i = 0, ddc_no = 0, speed = 0, lnrx = 0;
|
|
for (i=0; i <8; i++){
|
|
if ( (data[7] >> i) & 1){
|
|
ddc[ddc_no++] = i; lnrx++;
|
|
//fprintf(stderr, "ddc no %d \n", i);
|
|
}
|
|
}
|
|
//fprintf(stderr,"Numer of receivers: %d \n", lnrx);
|
|
speed = data[18+(ddc[0]*6)] << 8 | data[19+(ddc[0]*6)];
|
|
sampleSpeed[0] = speed/48==1?0x00:speed/48==2?0x01:speed/48==4?0x02:speed/48==8?0x03:0x04;
|
|
//fprintf(stderr,"sample speed receiver[0] = %d \n", sampleSpeed[0]);
|
|
if (lnrx == 2){
|
|
speed = data[18+(ddc[1]*6)] << 8 | data[19+(ddc[1]*6)];
|
|
sampleSpeed[1] = speed/48==1?0x00:speed/48==2?0x01:speed/48==4?0x02:speed/48==8?0x03:0x04;
|
|
//fprintf(stderr,"sample speed receiver[1] = %d \n", sampleSpeed[1]);
|
|
}
|
|
nrx = lnrx;
|
|
}
|
|
|
|
void transmitter_specific_registers_from_host_port(unsigned char* buffer) {
|
|
cw = ((buffer[5] & 0x02) == 0x02)? 1: 0;
|
|
cw_iambic_mode = ((buffer[5] & 0x28) == 0x28)? 2: ((buffer[5] & 0x08)==0x08)? 1: 0;
|
|
cw_keyer_reverse= ((buffer[5] & 0x04) == 0x04)? 1:0;
|
|
cw_break_in = ((buffer[5] & 0x80) == 0x80)? 1:0;
|
|
cw_keyer_speed = buffer[9];
|
|
cw_keyer_weight = buffer[10];
|
|
}
|
|
|
|
void high_priority_from_host_port(unsigned char* data) {
|
|
|
|
create_radioberry_socket();
|
|
|
|
running = ((data[4] & 0x01) == 0x01)? 1:0;
|
|
//fprintf(stderr," running %.2X %d \n",data[4], running);
|
|
ptt = ((data[4] & 0x02) == 0x02) ? 1:0;
|
|
//fprintf(stderr," ptt %d \n",ptt);
|
|
//data[5] [0] = CWX, [1] = Dot, [2] = Dash CW TODO!!
|
|
int rxphase1, rxphase2, txphase;
|
|
//rx
|
|
rxphase1 = data[9+(ddc[0]*4)] << 24 | data[10+(ddc[0]*4)] << 16 | data[11+(ddc[0]*4)] << 8 | data[12+(ddc[0]*4)] ;
|
|
rxphase2 = data[9+(ddc[1]*4)] << 24 | data[10+(ddc[1]*4)] << 16 | data[11+(ddc[1]*4)] << 8 | data[12+(ddc[1]*4)] ;
|
|
rxfreq1 = (long) (((double) rxphase1 * 122880000.0) / 4294967296.0);
|
|
//fprintf(stderr,"rxfreq1 %d \n", rxfreq1);
|
|
rxfreq2 = (long) (((double) rxphase2 * 122880000.0) / 4294967296.0);
|
|
//fprintf(stderr,"rxfreq2 %d \n", rxfreq2);
|
|
//tx
|
|
txphase = ( data[329] << 24 | data[330] << 16 | data[331] << 8 | data[332] );
|
|
txfreq = (long) (((double) txphase * 122880000.0) / 4294967296.0);
|
|
//fprintf(stderr,"txfreq %d \n", txfreq);
|
|
drive_level = data[345] & 0xFF;
|
|
//if (prev_drive_level != drive_level) {
|
|
// prev_drive_level = drive_level;
|
|
// fprintf(stderr,"drive_level %d \n", drive_level);
|
|
//}
|
|
gain = ((int) ((signed char) data[1443])) + 12;
|
|
//fprintf(stderr, "ad9866 gain = %d rx-gain = %d \n", gain, (gain -12));
|
|
}
|
|
|
|
void create_radioberry_socket() {
|
|
if (radioberry_socket == -1) {
|
|
int i = 0;
|
|
for(i; i < 8; i++) {
|
|
src_addr[i].sin_family = PF_INET;
|
|
src_addr[i].sin_port = htons(RX_IQ_TO_HOST_PORT_0 + i);
|
|
inet_aton(radioberry_addr, &src_addr[i].sin_addr);
|
|
}
|
|
dst_addr.sin_family = PF_INET;
|
|
dst_addr.sin_port = htons(ntohs(remote_port));
|
|
inet_aton(sdr_client_addr, &dst_addr.sin_addr);
|
|
|
|
high_priority_addr.sin_family = PF_INET;
|
|
high_priority_addr.sin_port = htons(HIGH_PRIORITY_TO_HOST_PORT);
|
|
inet_aton(radioberry_addr, &high_priority_addr.sin_addr);
|
|
|
|
mic_line_addr.sin_family = PF_INET;
|
|
mic_line_addr.sin_port = htons(MIC_LINE_TO_HOST_PORT);
|
|
inet_aton(radioberry_addr, &mic_line_addr.sin_addr);
|
|
|
|
if((radioberry_socket = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0){
|
|
perror("socket");
|
|
exit(-1);
|
|
}
|
|
int optval = 1;
|
|
if (setsockopt(radioberry_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
|
|
fprintf (stderr, "Warning: no reuse\n");
|
|
}
|
|
if (setsockopt(radioberry_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0) {
|
|
fprintf (stderr, "Warning: no port reuse\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void tx_iq_from_host_port(unsigned char* buffer) {
|
|
|
|
unsigned char tx_iqdata[6];
|
|
|
|
// protocol-2 the rate is 192ksps (radioberry uses 48K; downsampling required!)
|
|
// i and q (msb first using 24b/sample, radioberry uses only 16b/sample; using 2 msb bytes.) from index 4 to 1443 (240 i and q samples)
|
|
if (!ptt) return;
|
|
|
|
//getting the udp packages sometimes twice...?
|
|
int seq = buffer[0] << 24 | buffer[1] << 16 | buffer[2]<< 8 | buffer[3] ;
|
|
if (lseq == seq) return;
|
|
lseq = seq;
|
|
|
|
sem_wait(&mutex);
|
|
|
|
gpioWrite(21, 1); ; // ptt on
|
|
|
|
//set the tx freq; we are doing this per block of data.
|
|
tx_iqdata[0] = cw_keyer_speed | (cw_iambic_mode<<6);
|
|
tx_iqdata[1] = cw_keyer_weight | (cw_keyer_reverse<<7);
|
|
tx_iqdata[2] = ((txfreq >> 24) & 0xFF);
|
|
tx_iqdata[3] = ((txfreq >> 16) & 0xFF);
|
|
tx_iqdata[4] = ((txfreq >> 8) & 0xFF);
|
|
tx_iqdata[5] = (txfreq & 0xFF);
|
|
spiXfer(rx2_spi_handler, tx_iqdata, tx_iqdata, 6);
|
|
|
|
// possible improvement; only in cw and no change in drive level; no need to inform firmware!
|
|
int index = 4;
|
|
int sample = 0;
|
|
for (sample=0; sample < 60; sample++) {
|
|
if (gpioRead(20) == 1) {}; //avoiding overruns
|
|
|
|
tx_iqdata[0] = 0;
|
|
tx_iqdata[1] = drive_level / 6.4; // convert drive level from 0-255 to 0-39 ) tx_gain <= spi_recv[37:32];
|
|
tx_iqdata[2] = ((buffer[index++]) & 0xFF);
|
|
tx_iqdata[3] = ((buffer[index++]) & 0xFF);
|
|
tx_iqdata[4] = ((buffer[++index]) & 0xFF);
|
|
tx_iqdata[5] = ((buffer[++index]) & 0xFF);
|
|
spiXfer(rx1_spi_handler, tx_iqdata, tx_iqdata, 6);
|
|
index = index + 20; //decimation by 4
|
|
|
|
lcount ++;
|
|
if (lcount == 48000) {
|
|
lcount = 0;
|
|
gettimeofday(&t2, 0);
|
|
float elapsd = timedifference_msec(t1, t2);
|
|
printf("Code tx mode spi executed in %f milliseconds.\n", elapsd);
|
|
gettimeofday(&t1, 0);
|
|
}
|
|
}
|
|
sem_post(&mutex);
|
|
}
|
|
|
|
int createUDPSocket() {
|
|
struct sockaddr_in myaddr;
|
|
if ((discover_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
perror("cannot create discover socket\n");
|
|
return -1;
|
|
}
|
|
struct timeval timeout;
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = TIMEOUT_MS;
|
|
|
|
if (setsockopt(discover_socket, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout,sizeof(timeout)) < 0) {
|
|
perror("setsockopt failed\n");
|
|
return -1;
|
|
}
|
|
int optval = 1;
|
|
setsockopt(discover_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
|
setsockopt(discover_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
|
|
|
memset((char *)&myaddr, 0, sizeof(myaddr));
|
|
myaddr.sin_family = PF_INET;
|
|
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
myaddr.sin_port = htons(SERVICE_PORT);
|
|
|
|
if (bind(discover_socket, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
|
|
perror("bind to discover socket failed");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void fillDiscoveryReplyMessage() {
|
|
memset(broadcastReply, 0, sizeof(broadcastReply));
|
|
int i = 5;
|
|
for (i; i < 11; i++) broadcastReply[i] = i - 5; //MAC 00-01-02-03-04-05
|
|
broadcastReply[4] = 0x02;
|
|
broadcastReply[11] = HERMESLITE;
|
|
broadcastReply[13] = FIRMWARE_VERSION;
|
|
broadcastReply[20] = MAX_RECEIVERS;
|
|
}
|
|
|
|
int handleDiscovery(unsigned char* buffer) {
|
|
int iphdrlen;
|
|
struct sockaddr_in remaddr;
|
|
socklen_t addrlen = sizeof(remaddr);
|
|
if (running == 0) {
|
|
if (radioberry_socket != -1) close(radioberry_socket);
|
|
radioberry_socket = -1;
|
|
} else return 0;
|
|
|
|
struct iphdr *ip = (struct iphdr*)(buffer + sizeof(struct ethhdr));
|
|
iphdrlen =ip->ihl*4;
|
|
struct udphdr *udp = (struct udphdr*)(buffer + iphdrlen + sizeof(struct ethhdr));
|
|
struct sockaddr_in source,dest;
|
|
memset(&source, 0, sizeof(source));
|
|
source.sin_addr.s_addr = ip->saddr;
|
|
memset(&dest, 0, sizeof(dest));
|
|
dest.sin_addr.s_addr = ip->daddr;
|
|
memset((char *)&remaddr, 0, sizeof(remaddr));
|
|
remaddr.sin_family = PF_INET;
|
|
remaddr.sin_addr.s_addr = ip->saddr;
|
|
remaddr.sin_port = udp->source;
|
|
|
|
fprintf(stderr,"Discovery packet received \n");
|
|
fprintf(stderr,"SDR Program IP-address %s \n", inet_ntoa(remaddr.sin_addr));
|
|
fprintf(stderr,"Discovery Port %d \n", ntohs(remaddr.sin_port));
|
|
|
|
strcpy(sdr_client_addr, inet_ntoa(remaddr.sin_addr));
|
|
fillDiscoveryReplyMessage();
|
|
createUDPSocket();
|
|
if (sendto(discover_socket, broadcastReply, sizeof(broadcastReply), 0, (struct sockaddr *)&remaddr, addrlen) < 0) {
|
|
perror("Discovery reply sendto error");
|
|
return -1;
|
|
}
|
|
close(discover_socket);
|
|
return 0;
|
|
}
|
|
|
|
void usage(void)
|
|
{
|
|
printf("Usage: radioberry [OPTION]... [COMMAND]...\n"
|
|
"COMMANDs to initialize the radioberry firmware.\n\n");
|
|
|
|
printf(
|
|
" -a, --audio-out=ID\t select audio output device number. See model list\n"
|
|
" -m, --audio-in=ID\t select audio input device. See model list\n"
|
|
" -l, --list \t\t list all audio device and exit\n"
|
|
" -h, --help \t\t display this help and exit\n"
|
|
" -v, --version \t\t output version information and exit\n\n"
|
|
);
|
|
|
|
printf("\nReport bugs to <pa3gsb@gmail.com>.\n");
|
|
}
|
|
|
|
|
|
void print_version(void){
|
|
printf("Version information: \n%s \n\n", version);
|
|
printf("%s \n", copyright);
|
|
}
|
|
|
|
void printIntroScreen() {
|
|
fprintf(stderr,"\n");
|
|
fprintf(stderr, "====================================================================\n");
|
|
fprintf(stderr, "====================================================================\n");
|
|
fprintf(stderr, "\t\t\tRadioberry V2.0 beta 2.\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "\t\t\tEmulator Protocol-2 \n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "\t\t\tHave fune Johan PA3GSB\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "====================================================================\n");
|
|
fprintf(stderr, "====================================================================\n");
|
|
}
|
|
|
|
void *mic_dummy_thread(void *arg) {
|
|
|
|
int i=0;
|
|
unsigned char l_mic_buffer[132];
|
|
|
|
while(1) {
|
|
|
|
sem_wait(&mic_sample);
|
|
|
|
l_mic_buffer[mic_count++] = 0; //msb
|
|
l_mic_buffer[mic_count++] = 0;
|
|
|
|
if (mic_count == 132) {
|
|
l_mic_buffer[0]=mic_sequence>>24;
|
|
l_mic_buffer[1]=mic_sequence>>16;
|
|
l_mic_buffer[2]=mic_sequence>>8;
|
|
l_mic_buffer[3]=mic_sequence;
|
|
send_udp_packet(radioberry_socket, mic_line_addr, dst_addr, l_mic_buffer, 132);
|
|
mic_sequence++;
|
|
mic_count = 4;
|
|
}
|
|
}
|
|
fprintf(stderr,"mic_dummy_thread: exiting\n");
|
|
return NULL;
|
|
}
|
|
|
|
void start_dummy_mic_thread() {
|
|
pthread_t pid1;
|
|
pthread_create(&pid1, NULL, mic_dummy_thread, NULL);
|
|
}
|
|
|
|
// end of source.
|