From: c vw <dl1ycf@darc.de>
Date: Wed, 17 Jul 2019 14:29:48 +0000 (+0200)
Subject: HPSDR simulator extended to "New Protocol"
X-Git-Url: https://git.rkrishnan.org/pf/components/flags/frontends/%22file://%22%3C?a=commitdiff_plain;h=934cfb2144844357f1fda2997f1757c3e64381f6;p=pihpsdr.git

HPSDR simulator extended to "New Protocol"
---

diff --git a/Makefile b/Makefile
index ad0dbd8..652f9bb 100644
--- a/Makefile
+++ b/Makefile
@@ -475,7 +475,10 @@ release: $(PROGRAM)
 #############################################################################
 
 hpsdrsim.o:	hpsdrsim.c
-	$(CC) -c -O hpsdrsim.c
+	$(CC) -c -O -DALSASOUND hpsdrsim.c
 
-hpsdrsim:	hpsdrsim.o
-	$(LINK) -o hpsdrsim hpsdrsim.o $(AUDIO_LIBS) -lm -lpthread
+newhpsdrsim.o:	newhpsdrsim.c
+	$(CC) -c -O newhpsdrsim.c
+
+hpsdrsim:	hpsdrsim.o newhpsdrsim.o
+	$(LINK) -o hpsdrsim hpsdrsim.o newhpsdrsim.o -lasound -lm -lpthread
diff --git a/hpsdrsim.c b/hpsdrsim.c
index 0b73aef..358c74a 100644
--- a/hpsdrsim.c
+++ b/hpsdrsim.c
@@ -1,5 +1,3 @@
-//#define MICSAMPLES   // define to send microphone samples (triggered by attenuator slider)
-//#define TX_ENVELOPE  // define to dump TX envelope 1 sec after first PTT
 /*
  * HPSDR simulator, (C) Christoph van Wuellen, April/Mai 2019
  *
@@ -34,7 +32,7 @@
  * and the PURESIGNAL feedback signal is connected to the second ADC.
  *
  * Audio sent to the "radio" is played via the first available output channel.
- * This works on MacOS (PORTAUDIO) and Linux (ALSA).
+ * This works on MacOS (PORTAUDIO) and Linux (ALSASOUND).
  *
  * Additional feature include the recording of the TX envelope of the first second
  * of TXing, and the possiblity to read a file with mic samples and "send"
@@ -59,10 +57,15 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 
+#define NEED_DUMMY_AUDIO 1
+
 #ifdef PORTAUDIO
 #include "portaudio.h"
-#else
+#undef NEED_DUMMY_AUDIO
+#endif
+#ifdef ALSASOUND
 #include <alsa/asoundlib.h>
+#undef NEED_DUMMY_AUDIO
 #endif
 
 // Forward declarations for the audio functions
@@ -82,6 +85,18 @@ extern int clock_nanosleep(clockid_t __clock_id, int __flags,
 static int sock_TCP_Server = -1;
 static int sock_TCP_Client = -1;
 
+//
+// Forward declarations for new protocol stuff
+//
+void   new_protocol_general_packet(unsigned char *buffer);
+int    new_protocol_running(void);
+
+#define LENNOISE 192000
+#define NOISEDIV (RAND_MAX / 96000)
+
+double noiseItab[LENNOISE];
+double noiseQtab[LENNOISE];
+
 /*
  * These variables store the state of the SDR.
  * Whenevery they are changed, this is reported.
@@ -150,33 +165,12 @@ static double txdrv_dbl = 0.99;
 static double txatt_dbl = 1.0;
 static double rxatt_dbl[4] = {1.0, 1.0, 1.0, 1.0};   // this reflects both ATT and PREAMP
 
-#ifdef TX_ENVELOPE
-//
-// This records the size of the first MAXENV TX samples after the first RX-TX transition.
-// This can be used to detect whether RX/TX transitions are fast enough not to chop
-// the first part of an SSB transmission using VOX, or of the first CW element.
-//
-#define MAXENV 48000
-static float envelope[MAXENV];
-int          envptr=0;
-#endif
-
-#ifdef MICSAMPLES
-//
-// Raw audio data (48000 16-bit int words) is read from a file and stored.
-// As soon as the attenuation of RX1 goes above 20dB, these samples are
-// sent to the SDR (one shot), and when the attenuation goes below 10dB, this system
-// is reset, so playing with the ALEX ATT buttons or with the ATT slider you can
-// send mic samples to the SDR application and do some testing.
-//
-static int16_t micsamples[48000];
-int micsamples_ptr=-2;
-int micsamples_rate=0;
-#endif
-
-static int sock_ep2;
-
-static struct sockaddr_in addr_ep6;
+/*
+ * Socket for communicating with the "PC side"
+ */
+static int sock_udp;
+struct sockaddr_in addr_new; // shared by newhpsdrsim.c
+static struct sockaddr_in addr_old;
 
 /*
  * These two variables monitor whether the TX thread is active
@@ -197,23 +191,37 @@ void *handler_ep6(void *arg);
 // and two METIS packets per TCP/UDP packet,
 // and two/four/eight-fold up-sampling if the TX sample
 // rate is 96000/192000/384000
+//
+// In the new protocol, TX samples come in bunches of
+// 240 samples. So NEWRTXLEN is defined as a multiple of
+// 240 not exceeding RTXLEN
+//
 #define RTXLEN 64512
-static double  isample[RTXLEN];
-static double  qsample[RTXLEN];
+#define NEWRTXLEN 64320
+double  isample[RTXLEN];  // shared with newhpsdrsim
+double  qsample[RTXLEN];  // shared with newhpsdrsim
 static double  last_i_sample=0.0;
 static double  last_q_sample=0.0;
 static int  txptr=0;
 static int  rxptr=0;
 
-static int ismetis,isorion,ishermes,isc25;
+
+#define DEVICE_ATLAS      0
+#define DEVICE_HERMES     1
+#define DEVICE_HERMES2    2
+#define DEVICE_ANGELIA    3
+#define DEVICE_ORION      4
+#define DEVICE_ORION2     5
+#define DEVICE_HERMESLITE 6
+#define DEVICE_C25        100
+static int DEVICE=DEVICE_HERMES;
 
 int main(int argc, char *argv[])
 {
-	int j, size;
+	int i, j, size;
 	struct sched_param param;
 	pthread_attr_t attr;
 	pthread_t thread;
-        int DEVICE;
 
 	uint8_t reply[11] = { 0xef, 0xfe, 2, 0, 0, 0, 0, 0, 0, 32, 1 };
 
@@ -221,14 +229,15 @@ int main(int argc, char *argv[])
 	uint32_t code;
         int16_t  sample,l,r;
 
-	struct sockaddr_in addr_ep2, addr_from;
+	struct sockaddr_in addr_udp;
 	uint8_t buffer[1032];
-	struct iovec iovec;
-	struct msghdr msghdr;
 	struct timeval tv;
 	struct timespec ts;
 	int yes = 1;
         uint8_t *bp;
+        unsigned long checksum;
+        socklen_t lenaddr;
+        struct sockaddr_in addr_from;
 
 	uint32_t last_seqnum = 0xffffffff, seqnum;  // sequence number of received packet
 
@@ -236,17 +245,18 @@ int main(int argc, char *argv[])
 	int bytes_read, bytes_left;
 	uint32_t *code0 = (uint32_t *) buffer;  // fast access to code of first buffer
         int fd;
+        long cnt;
+
+        // Produce some noise
+        j=RAND_MAX / 2;
+        for (i=0; i<LENNOISE; i++) {
+          noiseItab[i]= ((double) rand() / j - 1.0) * 0.00003;
+          noiseQtab[i]= ((double) rand() / j - 1.0) * 0.00003;
+        }
+
+	memset (isample, 0, RTXLEN*sizeof(double));
+	memset (qsample, 0, RTXLEN*sizeof(double));
 
-#ifdef MICSAMPLES
-        fd=open("micsamples", O_RDONLY);
-        if (fd >= 0) {
-	  if (read(fd, micsamples, 48000*sizeof(int16_t)) == 48000*sizeof(int16_t)) {
-	    fprintf(stderr,"MIC SAMPLES available\n");
-	    micsamples_ptr=-1;
-	  }
-	}
-#endif
-        
 	audio_get_cards();
         audio_open_output();
 /*
@@ -257,25 +267,28 @@ int main(int argc, char *argv[])
  *	Examples for ORION2:	ANAN7000D, ANAN8000D
  */
 
-	DEVICE=1; // default is Hermes
         if (argc > 1) {
-	    if (!strncmp(argv[1],"-metis"  ,6))  DEVICE=0;
-	    if (!strncmp(argv[1],"-hermes" ,7))  DEVICE=1;
-	    if (!strncmp(argv[1],"-orion" , 6))  DEVICE=5;
-	    if (!strncmp(argv[1],"-orion2" ,7))  DEVICE=10;   // Anan7000 in old protocol
-	    if (!strncmp(argv[1],"-c25"    ,8))  DEVICE=100;  // the same as hermes
+	    if (!strncmp(argv[1],"-atlas"  ,      6))  DEVICE=DEVICE_ATLAS;
+	    if (!strncmp(argv[1],"-hermes" ,      7))  DEVICE=DEVICE_HERMES;
+	    if (!strncmp(argv[1],"-hermes2" ,     8))  DEVICE=DEVICE_HERMES2;
+	    if (!strncmp(argv[1],"-angelia" ,     8))  DEVICE=DEVICE_ANGELIA;
+	    if (!strncmp(argv[1],"-orion" ,       6))  DEVICE=DEVICE_ORION;
+	    if (!strncmp(argv[1],"-orion2" ,      7))  DEVICE=DEVICE_ORION2;
+	    if (!strncmp(argv[1],"-hermeslite" , 11))  DEVICE=DEVICE_ORION2;
+	    if (!strncmp(argv[1],"-c25"    ,      4))  DEVICE=DEVICE_C25;
         }
-	ismetis=ishermes=isorion=isc25=0;
 	switch (DEVICE) {
-	    case   0: fprintf(stderr,"DEVICE is METIS\n");   ismetis=1;  break;
-	    case   1: fprintf(stderr,"DEVICE is HERMES\n");  ishermes=1; break;
-	    case   5: fprintf(stderr,"DEVICE is ORION\n");   isorion=1;  break;
-	    case  10: fprintf(stderr,"DEVICE is ORION2\n");  isorion=1;  break;
-	    case 100: fprintf(stderr,"DEVICE is StemLab\n"); ishermes=1;  isc25=1; break;
+	    case   DEVICE_ATLAS:   fprintf(stderr,"DEVICE is ATLASS\n");      break;
+	    case   DEVICE_HERMES:  fprintf(stderr,"DEVICE is HERMES\n");      break;
+	    case   DEVICE_HERMES2: fprintf(stderr,"DEVICE is HERMES (2)\n");  break;
+	    case   DEVICE_ANGELIA: fprintf(stderr,"DEVICE is ANGELIA\n");     break;
+	    case   DEVICE_ORION:   fprintf(stderr,"DEVICE is ORION\n");       break;
+	    case   DEVICE_ORION2:  fprintf(stderr,"DEVICE is ORION-II\n");    break;
+	    case   DEVICE_C25:     fprintf(stderr,"DEVICE is STEMlab/C25\n"); break;
 	}
 	reply[10]=DEVICE;
 
-	if ((sock_ep2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	if ((sock_udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
 	{
 		perror("socket");
 		return EXIT_FAILURE;
@@ -289,18 +302,18 @@ int main(int argc, char *argv[])
 	reply[7]=0xEE;
 	reply[8]=0xFF;
 
-	setsockopt(sock_ep2, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+	setsockopt(sock_udp, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 
 	tv.tv_sec = 0;
 	tv.tv_usec = 1000;
-	setsockopt(sock_ep2, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+	setsockopt(sock_udp, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
 
-	memset(&addr_ep2, 0, sizeof(addr_ep2));
-	addr_ep2.sin_family = AF_INET;
-	addr_ep2.sin_addr.s_addr = htonl(INADDR_ANY);
-	addr_ep2.sin_port = htons(1024);
+	memset(&addr_udp, 0, sizeof(addr_udp));
+	addr_udp.sin_family = AF_INET;
+	addr_udp.sin_addr.s_addr = htonl(INADDR_ANY);
+	addr_udp.sin_port = htons(1024);
 
-	if (bind(sock_ep2, (struct sockaddr *)&addr_ep2, sizeof(addr_ep2)) < 0)
+	if (bind(sock_udp, (struct sockaddr *)&addr_udp, sizeof(addr_udp)) < 0)
 	{
 		perror("bind");
 		return EXIT_FAILURE;
@@ -325,7 +338,7 @@ int main(int argc, char *argv[])
 	tv.tv_usec = 1000;
 	setsockopt(sock_TCP_Server, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
 
-	if (bind(sock_TCP_Server, (struct sockaddr *)&addr_ep2, sizeof(addr_ep2)) < 0)
+	if (bind(sock_TCP_Server, (struct sockaddr *)&addr_udp, sizeof(addr_udp)) < 0)
 	{
 		perror("bind tcp");
 		return EXIT_FAILURE;
@@ -339,16 +352,7 @@ int main(int argc, char *argv[])
 
 	while (1)
 	{
-		memset(&iovec, 0, sizeof(iovec));
-		memset(&msghdr, 0, sizeof(msghdr));
-
 		memcpy(buffer, id, 4);
-		iovec.iov_base = buffer;
-		iovec.iov_len = 1032;
-		msghdr.msg_iov = &iovec;
-		msghdr.msg_iovlen = 1;
-		msghdr.msg_name = &addr_from;
-		msghdr.msg_namelen = sizeof(addr_from);
 
 		ts.tv_sec = 0;
 		ts.tv_nsec = 1000000;
@@ -405,7 +409,8 @@ int main(int argc, char *argv[])
 		}
 		else
 		{
-			bytes_read = recvmsg(sock_ep2, &msghdr, 0);
+			lenaddr=sizeof(addr_from);
+			bytes_read = recvfrom(sock_udp, buffer, 1032, 0, (struct sockaddr *)&addr_from, &lenaddr);
 			if (bytes_read > 0)
 			{
 				udp_retries=0;
@@ -439,8 +444,8 @@ int main(int argc, char *argv[])
 
 			switch (code)
 			{
-				// PC to Red Pitaya transmission via process_ep2
-				case 0x0201feef:
+			    // PC to Red Pitaya transmission via process_ep2
+			    case 0x0201feef:
 
 				// processing an invalid packet is too dangerous -- skip it!
 				if (bytes_read != 1032)
@@ -472,7 +477,9 @@ int main(int argc, char *argv[])
 				  // Note that this interpolation causes weak "sidebands" at 48/96/... kHz distance (the
 				  // strongest ones at 48 kHz).
 				  double disample,dqsample,idelta,qdelta;
+				  double sum;
                                   bp=buffer+16;  // skip 8 header and 8 SYNC/C&C bytes
+				  sum=0.0;
                                   for (j=0; j<126; j++) {
 					// write audio samples
 					r  = (int)((signed char) *bp++)<<8;
@@ -482,25 +489,12 @@ int main(int argc, char *argv[])
                                         audio_write(r,l);
 					sample  = (int)((signed char) *bp++)<<8;
 					sample |= (int) ((signed char) *bp++ & 0xFF);
-					disample=(double) sample / 32768.0;
+					disample=(double) sample * 0.000030517578125;  // division by 32768
 					sample  = (int)((signed char) *bp++)<<8;
 					sample |= (int) ((signed char) *bp++ & 0xFF);
-					dqsample=(double) sample / 32768.0;
-
-#ifdef TX_ENVELOPE
-					if (ptt || envptr > 0) {
-					  if (envptr < MAXENV) envelope[envptr++]=(disample*disample+dqsample*dqsample);
-					  if (envptr == MAXENV) {
-					    fd=open("dump.envelope", O_RDWR | O_CREAT | O_TRUNC, (mode_t) 0777);
-					    if (fd >= 0) {
-					      write (fd, envelope, MAXENV*sizeof(float));
-					      close (fd);
-					      fprintf(stderr,"TX ENV dumped\n");
-					    }
-					    envptr++;
-					  }
-					}
-#endif
+					dqsample=(double) sample * 0.000030517578125;
+					sum += (disample*disample+dqsample*dqsample);
+
 					switch (rate) {
 					    case 0:  // RX sample rate = TX sample rate = 48000
                                         	isample[txptr  ]=disample;
@@ -551,13 +545,14 @@ int main(int argc, char *argv[])
 					last_q_sample=dqsample;
 					if (j == 62) bp+=8; // skip 8 SYNC/C&C bytes of second block
                                  }
+				 fprintf(stderr,"LEVEL=%f\n", sum*0.007936508);
 				 // wrap-around of ring buffer
                                  if (txptr >= RTXLEN) txptr=0;
 				}
 				break;
 
-				// respond to an incoming Metis detection request
-				case 0x0002feef:
+			    // respond to an incoming Metis detection request
+			    case 0x0002feef:
 
 				fprintf(stderr, "Respond to an incoming Metis detection request / code: 0x%08x\n", code);
 
@@ -589,13 +584,13 @@ int main(int argc, char *argv[])
 				}
 				else
 				{
-					sendto(sock_ep2, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+					sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
 				}
 
 				break;
 
-				// stop the Red Pitaya to PC transmission via handler_ep6
-				case 0x0004feef:
+			    // stop the Red Pitaya to PC transmission via handler_ep6
+			    case 0x0004feef:
 
 				fprintf(stderr, "STOP the transmission via handler_ep6 / code: 0x%08x\n", code);
 
@@ -616,18 +611,16 @@ int main(int argc, char *argv[])
 				}
 				break;
 
-				// start the Red Pitaya to PC transmission via handler_ep6
-				case 0x1104feef:
-				//// This special code 0x11 is no longer needed, is does exactly the same thing
-				//// as the other start codes 0x01, 0x02, 0x03
+			    // start the Red Pitaya to PC transmission via handler_ep6
+			    case 0x1104feef:
 
 				fprintf(stderr, "TCP METIS-start message received / code: 0x%08x\n", code);
 
 				/* FALLTHROUGH */
 
-				case 0x0104feef:
-				case 0x0204feef:
-				case 0x0304feef:
+			    case 0x0104feef:
+			    case 0x0204feef:
+			    case 0x0304feef:
 
 				fprintf(stderr, "START the handler_ep6 thread / code: 0x%08x\n", code);
 
@@ -640,10 +633,10 @@ int main(int argc, char *argv[])
 
 				enable_thread = 0;
 				while (active_thread) usleep(1000);
-				memset(&addr_ep6, 0, sizeof(addr_ep6));
-				addr_ep6.sin_family = AF_INET;
-				addr_ep6.sin_addr.s_addr = addr_from.sin_addr.s_addr;
-				addr_ep6.sin_port = addr_from.sin_port;
+				memset(&addr_old, 0, sizeof(addr_old));
+				addr_old.sin_family = AF_INET;
+				addr_old.sin_addr.s_addr = addr_from.sin_addr.s_addr;
+				addr_old.sin_port = addr_from.sin_port;
 
 				//
 				// The initial value of txptr defines the delay between
@@ -659,27 +652,175 @@ int main(int argc, char *argv[])
 				CommonMercuryFreq = 0;
 				if (pthread_create(&thread, NULL, handler_ep6, NULL) < 0)
 				{
-					perror("pthread_create");
+					perror("create old protocol thread");
 					return EXIT_FAILURE;
 				}
 				pthread_detach(thread);
 				break;
 
-				default:
-				// Possibly a discovery packet of the New protocol, otherwise a severe error
-				if (bytes_read == 60 && code == 0 && buffer[4] == 0x02)
-				{
-					fprintf(stderr,"NewProtocol discovery packet received (we won't respond)\n");
+			    default:
+				/*
+				 * Here we end up with several possible packets from the new protocol
+				 * These are processed here.
+				 */
+				if (bytes_read == 264 && buffer[0] == 0xEF && buffer[1] == 0xFE && buffer[2] == 0x03 && buffer[3] == 0x01) {
+				  static long cnt=0;
+				  unsigned long blks=(buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7];
+				  fprintf(stderr,"OldProtocol Program blks=%lu count=%ld\r", blks, ++cnt);
+				  usleep(1000);
+				  memset(buffer, 0, 60);
+				  buffer[0]=0xEF;
+				  buffer[1]=0xFE;
+				  buffer[2]=0x04;
+				  buffer[3]=0xAA;
+				  buffer[4]=0xBB;
+				  buffer[5]=0xCC;
+				  buffer[6]=0xDD;
+				  buffer[7]=0xEE;
+				  buffer[8]=0xFF;
+				  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  if (blks == cnt) fprintf(stderr,"\n\n Programming Done!\n");
+				  break;
+				}
+				if (bytes_read == 64 && buffer[0] == 0xEF && buffer[1] == 0xFE && buffer[2] == 0x03 && buffer[3] == 0x02) {
+				  fprintf(stderr,"OldProtocol Erase packet received:\n");
+				  sleep(1);
+				  cnt=0;
+				  memset(buffer, 0, 60);
+				  buffer[0]=0xEF;
+				  buffer[1]=0xFE;
+				  buffer[2]=0x03;
+				  buffer[3]=0xAA;
+				  buffer[4]=0xBB;
+				  buffer[5]=0xCC;
+				  buffer[6]=0xDD;
+				  buffer[7]=0xEE;
+				  buffer[8]=0xFF;
+				  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  break;
+				
+				}
+				if (bytes_read == 63 && buffer[0] == 0xEF && buffer[1] == 0xFE && buffer[2] == 0x03) {
+				  fprintf(stderr,"OldProtocol SetIP packet received:\n");
+				  fprintf(stderr,"MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n", buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8]);
+				  fprintf(stderr,"IP  address is %03d:%03d:%03d:%03d\n", buffer[9], buffer[10], buffer[11], buffer[12]);
+ 				  buffer[2]=0x02;
+				  memset(buffer+9, 0, 54);
+				  sendto(sock_udp, buffer, 63, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  break;
+				}
+		   	    	if (code == 0 && buffer[4] == 0x02) {
+				  fprintf(stderr,"NewProtocol discovery packet received\n");
+				  // prepeare response
+				  memset(buffer, 0, 60);
+				  buffer [4]=0x02+new_protocol_running();
+				  buffer [5]=0xAA;
+				  buffer[ 6]=0xBB;
+				  buffer[ 7]=0xCC;
+				  buffer[ 8]=0xDD;
+				  buffer[ 9]=0xEE;
+				  buffer[10]=0xFF;
+				  buffer[11]=DEVICE;
+				  buffer[12]=38;
+				  buffer[13]=103;
+				  buffer[20]=2;
+				  buffer[21]=1;
+				  buffer[22]=3;
+				  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  break;
+				}
+		   	    	if (code == 0 && buffer[4] == 0x04) {
+				  fprintf(stderr,"NewProtocol erase packet received\n");
+                                  memset(buffer, 0, 60);
+                                  buffer [4]=0x02+active_thread;
+                                  buffer [5]=0xAA;
+                                  buffer[ 6]=0xBB;
+                                  buffer[ 7]=0xCC;
+                                  buffer[ 8]=0xDD;
+                                  buffer[ 9]=0xEE;
+                                  buffer[10]=0xFF;
+                                  buffer[11]=DEVICE;
+                                  buffer[12]=38;
+                                  buffer[13]=103;
+                                  buffer[20]=2;
+                                  buffer[21]=1;
+                                  buffer[22]=3;
+                                  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  sleep(5); // pretend erase takes 5 seconds
+                                  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  break;
+				}
+		   	    	if (bytes_read == 265 && buffer[4] == 0x05) {
+				  unsigned long seq, blk;
+				  seq=(buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+				  blk=(buffer[5] << 24) + (buffer[6] << 16) + (buffer[7] << 8) + buffer[8];
+				  fprintf(stderr,"NewProtocol Program packet received: seq=%lu blk=%lu\r",seq,blk);
+				  if (seq == 0) checksum=0;
+				  for (j=9; j<=264; j++) checksum += buffer[j];
+                                  memset(buffer+4, 0, 56); // keep seq. no
+				  buffer[4]=0x04;
+                                  buffer [5]=0xAA;
+                                  buffer[ 6]=0xBB;
+                                  buffer[ 7]=0xCC;
+                                  buffer[ 8]=0xDD;
+                                  buffer[ 9]=0xEE;
+                                  buffer[10]=0xFF;
+				  buffer[11]=103;
+				  buffer[12]=DEVICE;
+				  buffer[13]=(checksum >> 8) & 0xFF;
+				  buffer[14]=(checksum     ) & 0xFF;
+				  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  if (seq+1 == blk) fprintf(stderr,"\n\nProgramming Done!\n");
+				  break;
+				}
+		   	    	if (bytes_read == 60 && code == 0 && buffer[4] == 0x06) {
+				  fprintf(stderr,"NewProtocol SetIP packet received for MAC %2x:%2x:%2x:%2x%2x:%2x IP=%d:%d:%d:%d\n",
+                                          buffer[5],buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],
+					  buffer[11],buffer[12],buffer[13],buffer[14]);
+ 				  // only respond if this is for OUR device
+				  if (buffer[ 5] != 0xAA) break;
+				  if (buffer[ 6] != 0xBB) break;
+				  if (buffer[ 7] != 0xCC) break;
+				  if (buffer[ 8] != 0xDD) break;
+				  if (buffer[ 9] != 0xEE) break;
+				  if (buffer[10] != 0xFF) break;
+                                  memset(buffer, 0, 60);
+                                  buffer [4]=0x02+active_thread;
+                                  buffer [5]=0xAA;
+                                  buffer[ 6]=0xBB;
+                                  buffer[ 7]=0xCC;
+                                  buffer[ 8]=0xDD;
+                                  buffer[ 9]=0xEE;
+                                  buffer[10]=0xFF;
+                                  buffer[11]=DEVICE;
+                                  buffer[12]=38;
+                                  buffer[13]=103;
+                                  buffer[20]=2;
+                                  buffer[21]=1;
+                                  buffer[22]=3;
+                                  sendto(sock_udp, buffer, 60, 0, (struct sockaddr *)&addr_from, sizeof(addr_from));
+				  break;
+				}
+		   	    	if (bytes_read == 60 && buffer[4] == 0x00) {
+				  // handle general packet
+				  memset(&addr_new, 0, sizeof(addr_new));
+				  addr_new.sin_family = AF_INET;
+				  addr_new.sin_addr.s_addr = addr_from.sin_addr.s_addr;
+				  addr_new.sin_port = addr_from.sin_port;
+				  new_protocol_general_packet(buffer);
+				  break;
 				}
 				else
 				{
-					fprintf(stderr,"PackedInvalidCode: 0x%08x (Len=%d)\n", code, bytes_read);
+					fprintf(stderr,"Invalid packet (len=%d) detected: ",bytes_read);
+					for (i=0; i<16; i++) fprintf(stderr,"%02x ",buffer[i]);
+					fprintf(stderr,"\n");
 				}
 				break;
 			}
 	}
 
-	close(sock_ep2);
+	close(sock_udp);
 
 	if (sock_TCP_Client > -1)
 	{
@@ -728,7 +869,7 @@ void process_ep2(uint8_t *frame)
           chk_data(((frame[4] >> 6) & 1), MicTS, "TimeStampMic");
           chk_data(((frame[4] >> 7) & 1), CommonMercuryFreq,"Common Mercury Freq");
 
-	  if (isc25) {
+	  if (DEVICE == DEVICE_C25) {
               // Charly25: has two 18-dB preamps that are switched with "preamp" and "dither"
               //           and two attenuators encoded in Alex-ATT
 	      //           Both only applies to RX1!
@@ -793,7 +934,7 @@ void process_ep2(uint8_t *frame)
 	   chk_data(frame[3] & 0x80,alexTRdisable,"ALEX T/R disable");
 	   chk_data(frame[4],alex_lpf,"ALEX LPF");
            // reset TX level. Leve a little head-room for noise
-	   txdrv_dbl=(double) txdrive / 256.0;
+	   txdrv_dbl=(double) txdrive * 0.00390625;  // div. by. 256
 	   break;
 
 	case 20:
@@ -817,11 +958,7 @@ void process_ep2(uint8_t *frame)
    	   chk_data((frame[4] & 0x1F) >> 0, rx_att[0], "RX1 ATT");
    	   chk_data((frame[4] & 0x20) >> 5, rx1_attE, "RX1 ATT enable");
 
-#ifdef MICSAMPLES
-	  if (rx_att[0] > 20 && micsamples_ptr == -1) micsamples_ptr =  0;
-	  if (rx_att[0] < 10 && micsamples_ptr == 48000) micsamples_ptr = -1;
-#endif
-	   if (!isc25) {
+	   if (DEVICE != DEVICE_C25) {
 	     // Set RX amplification factors. No switchable preamps available normally.
              rxatt_dbl[0]=pow(10.0, -0.05*(10*AlexAtt+rx_att[0]));
              rxatt_dbl[1]=pow(10.0, -0.05*(rx_att[1]));
@@ -861,7 +998,7 @@ void process_ep2(uint8_t *frame)
             chk_data((frame[2] & 0x30) >> 4, rx_adc[6], "RX7 ADC");
 	    chk_data((frame[3] & 0x1f), txatt, "TX ATT");
 	    txatt_dbl=pow(10.0, -0.05*(double) txatt);
-	    if (isc25) {
+	    if (DEVICE == DEVICE_C25) {
 		// RedPitaya: Hard-wired ADC settings.
 		rx_adc[0]=0;
 		rx_adc[1]=1;
@@ -885,15 +1022,6 @@ void process_ep2(uint8_t *frame)
 	}
 }
 
-//
-// The "RX" signal. This is some noise, and some frequencies
-//
-#define LENNOISE 48000
-#define NOISEDIV (RAND_MAX / 24000)
-
-static double noiseItab[LENNOISE];
-static double noiseQtab[LENNOISE];
-
 static double T0800Itab[480];
 static double T0800Qtab[480];
 static double T2000Itab[192];
@@ -904,11 +1032,8 @@ void *handler_ep6(void *arg)
 	int i, j, k, n, size;
 	int data_offset, header_offset;
 	uint32_t counter;
-	uint16_t audio[512];
 	uint8_t buffer[1032];
 	uint8_t *pointer;
-	struct iovec iovec;
-	struct msghdr msghdr;
 	uint8_t id[4] = { 0xef, 0xfe, 1, 6 };
 	uint8_t header[40] =
 	{
@@ -936,17 +1061,7 @@ void *handler_ep6(void *arg)
         double run,inc;
         double i1,q1,fac;
 
-	memset(audio, 0, sizeof(audio));
-	memset(&iovec, 0, sizeof(iovec));
-	memset(&msghdr, 0, sizeof(msghdr));
-
-	memcpy(buffer + i * 1032, id, 4);
-	iovec.iov_base = buffer;
-	iovec.iov_len = 1032;
-	msghdr.msg_iov = &iovec;
-	msghdr.msg_iovlen = 1;
-	msghdr.msg_name = &addr_ep6;
-	msghdr.msg_namelen = sizeof(addr_ep6);
+	memcpy(buffer, id, 4);
 
 	header_offset = 0;
 	counter = 0;
@@ -954,13 +1069,6 @@ void *handler_ep6(void *arg)
         //
         // Produce RX data
         //
-        // a) noise from a 16-bit ADC
-        //
-        k=RAND_MAX / 2;
-        for (i=0; i<LENNOISE; i++) {
-	  noiseItab[i]= ((double) rand() / k - 1.0) * 0.00003;
-	  noiseQtab[i]= ((double) rand() / k - 1.0) * 0.00003;
-        }
 	noiseIQpt=0;
 	//
 	// b) some tones in the upper side band (one wave)
@@ -1021,7 +1129,7 @@ void *handler_ep6(void *arg)
 		    memset(pointer, 0, 504);
 		    for (j=0; j<n; j++) {
 			// ADC1: noise + weak tone on RX, feedback sig. on TX (except STEMlab)
-		        if (ptt && !isc25) {
+		        if (ptt && (DEVICE != DEVICE_C25)) {
 			  i1=isample[rxptr]*txdrv_dbl;
 			  q1=qsample[rxptr]*txdrv_dbl;
 			  fac=IM3a+IM3b*(i1*i1+q1*q1);
@@ -1034,7 +1142,7 @@ void *handler_ep6(void *arg)
 			  adc1qsample += T0800Qtab[pt0800] * 83.886070 *rxatt_dbl[0];
 			}
 			// ADC2: noise + stronger tone on RX, feedback sig. on TX (only STEMlab)
-			if (ptt && isc25) {
+			if (ptt && (DEVICE == DEVICE_C25)) {
 			  i1=isample[rxptr]*txdrv_dbl;
 			  q1=qsample[rxptr]*txdrv_dbl;
 			  fac=IM3a+IM3b*(i1*i1+q1*q1);
@@ -1069,17 +1177,17 @@ void *handler_ep6(void *arg)
 				myqsample=0;
 				break;
 			    }
-			    if (ismetis && ptt && (k==1)) {
+			    if (DEVICE == DEVICE_ATLAS && ptt && (k==1)) {
 				// METIS: TX DAC signal goes to RX2 when TXing
 				myisample=dacisample;
 				myqsample=dacqsample;
 			    }
-			    if (ishermes && ptt && (k==3)) {
+			    if ((DEVICE==DEVICE_HERMES || DEVICE==DEVICE_HERMES2 || DEVICE==DEVICE_C25) && ptt && (k==3)) {
 				// HERMES: TX DAC signal goes to RX4 when TXing
 				myisample=dacisample;
 				myqsample=dacqsample;
 			    }
-			    if (isorion && ptt && (k==4)) {
+			    if ((DEVICE==DEVICE_ANGELIA || DEVICE == DEVICE_ORION || DEVICE== DEVICE_ORION2) && ptt && (k==4)) {
 				// ANGELIA and beyond: TX DAC signal goes to RX5 when TXing
 				myisample=dacisample;
 				myqsample=dacqsample;
@@ -1091,24 +1199,8 @@ void *handler_ep6(void *arg)
 			    *pointer++ = (myqsample >>  8) & 0xFF;
 			    *pointer++ = (myqsample >>  0) & 0xFF;
 		        }
-#ifdef MICSAMPLES
-			if (micsamples_ptr >= 0 && micsamples_ptr < 48000) {
-			  ssample=micsamples[micsamples_ptr];
-			  *pointer++ = (ssample >> 8) & 0xFF;
-			  *pointer++ = (ssample     ) & 0xFF;
-			  micsamples_rate++;
-			  if (micsamples_rate == 1 << rate) {
-				micsamples_rate=0;
-				micsamples_ptr++;
-			  }
-			} else {
-			  *pointer++ = 0;
-			  *pointer++ = 0;
-			}
-#else
 			// Microphone samples: silence
 			pointer += 2;
-#endif
 			rxptr++;     if (rxptr >= RTXLEN) rxptr=0;
 			noiseIQpt++; if (noiseIQpt == LENNOISE) noiseIQpt=rand() / NOISEDIV;
 			pt2000++;    if (pt2000 == len2000) pt2000=0;
@@ -1144,14 +1236,14 @@ void *handler_ep6(void *arg)
 
 		if (sock_TCP_Client > -1)
 		{
-			if (sendmsg(sock_TCP_Client, &msghdr, 0) < 0)
+			if (sendto(sock_TCP_Client, buffer, 1032, 0, (struct sockaddr *)&addr_old, sizeof(addr_old)) < 0)
 			{
 				fprintf(stderr, "TCP sendmsg error occurred at sequence number: %u !\n", counter);
 			}
 		}
 		else
 		{
-			sendmsg(sock_ep2, &msghdr, 0);
+			sendto(sock_udp, buffer, 1032, 0, (struct sockaddr *)&addr_old, sizeof(addr_old));
 		}
 
 	}
@@ -1251,8 +1343,8 @@ void audio_write (int16_t l, int16_t r)
     }
   }
 }
-
-#else
+#endif
+#ifdef ALSASOUND
 //
 // Audio functions based on LINUX ALSA
 //
@@ -1460,3 +1552,18 @@ void audio_write(int16_t left_sample,int16_t right_sample) {
   }
 }
 #endif
+
+//
+// Dummy audio functions if this is compiled without audio support
+//
+#ifdef NEED_DUMMY_AUDIO
+void audio_get_cards()
+{
+}
+void audio_open_output()
+{
+}
+void audio_write (int16_t l, int16_t r)
+{
+}
+#endif
diff --git a/newhpsdrsim.c b/newhpsdrsim.c
new file mode 100644
index 0000000..cf96e73
--- /dev/null
+++ b/newhpsdrsim.c
@@ -0,0 +1,1247 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <math.h>
+
+extern struct sockaddr_in addr_new;
+extern void audio_write(int16_t r, int16_t l);
+
+#define NUMRECEIVERS 8
+
+#define LENNOISE 192000
+#define NOISEDIV (RAND_MAX / 96000)
+
+extern double noiseItab[LENNOISE];
+extern double noiseQtab[LENNOISE];
+
+#define IM3a  0.60
+#define IM3b  0.20
+
+#define RTXLEN 64512
+#define NEWRTXLEN 64320
+extern double  isample[RTXLEN];  // shared with newhpsdrsim
+extern double  qsample[RTXLEN];  // shared with newhpsdrsim
+static int txptr = 10000;
+
+/*
+ * These variables represent the state of the machine
+ */
+// data from general packet
+static int ddc_port = 0;
+static int duc_port = 0;
+static int hp_port = 0;
+static int shp_port = 0;
+static int audio_port = 0;
+static int duc0_port = 0;
+static int ddc0_port = 0;
+static int mic_port = 0;
+static int wide_port = 0;
+static int wide_enable = 0;
+static int wide_len = 0;
+static int wide_size = 0;
+static int wide_rate = 0;
+static int wide_ppf = 0;
+static int port_mm = 0;
+static int port_smm = 0;
+static int pwm_min = 0;
+static int pwm_max = 0;
+static int bits = 0;
+static int hwtim = 0;
+static int pa_enable = 0;
+static int alex0_enable = 0;
+static int alex1_enable = 0;
+static int mm_port = 0;
+static int smm_port = 0;
+static int iqform = 0;
+
+// data from rx specific packet
+static int adc=0;
+static int adcdither[8];
+static int adcrandom[8];
+static int ddcenable[NUMRECEIVERS];
+static int adcmap[NUMRECEIVERS];
+static int rxrate[NUMRECEIVERS];
+static int syncddc[NUMRECEIVERS];
+
+//data from tx specific packet
+static int dac=0;
+static int cwmode=0;
+static int sidelevel=0;
+static int sidefreq=0;
+static int speed=0;
+static int weight=0;
+static int hang=0;
+static int delay=0;
+static int txrate=0;
+static int ducbits=0;
+static int orion=0;
+static int gain=0;
+static int txatt=0;
+
+//stat from high-priority packet
+static int run=0;
+static int ptt[4];
+static int cwx=0;
+static int dot=0;
+static int dash=0;
+static unsigned long rxfreq[NUMRECEIVERS];
+static unsigned long txfreq=0;
+static int txdrive=0;
+static int w1400=0;  // Xvtr and Audio enable
+static int ocout=0;
+static int db9=0;
+static int mercury_atts=0;
+static int alex0[32];
+static int alex1[32];
+static int stepatt0=0;
+static int stepatt1=0;
+
+//
+// floating point representation of TX-Drive and ADC0-Attenuator
+//
+static double rxatt0_dbl=1.0;
+static double rxatt1_dbl=1.0;
+static double txatt_dbl=1.0;
+static double txdrv_dbl = 0.0;
+
+// End of state variables
+
+static pthread_t ddc_specific_thread_id;
+static pthread_t duc_specific_thread_id;
+static pthread_t rx_thread_id[NUMRECEIVERS];
+static pthread_t tx_thread_id;
+static pthread_t mic_thread_id;
+static pthread_t audio_thread_id;
+static pthread_t highprio_thread_id = 0;
+static pthread_t send_highprio_thread_id;
+
+void   *ddc_specific_thread(void*);
+void   *duc_specific_thread(void*);
+void   *highprio_thread(void*);
+void   *send_highprio_thread(void*);
+void   *rx_thread(void *);
+void   *tx_thread(void *);
+void   *mic_thread(void *);
+void   *audio_thread(void *);
+
+static double txlevel;
+
+int new_protocol_running() {
+  if (run) return 1; else return 0;
+}
+
+void new_protocol_general_packet(unsigned char *buffer) {
+  static unsigned long seqnum=0;
+  unsigned long seqold;
+  int rc;
+
+  seqold = seqnum;
+  seqnum = (buffer[0] >> 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+  if (seqnum != 0 && seqnum != seqold+1 ) {
+    fprintf(stderr,"GP: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+  }
+
+  rc=(buffer[5] << 8) + buffer[6];
+  if (rc == 0) rc=1025;
+  if (rc != ddc_port) {
+    ddc_port=rc;
+    fprintf(stderr,"GP: RX specific rcv        port is  %4d\n", rc);
+  }
+  rc=(buffer[7] << 8) + buffer[8];
+  if (rc == 0) rc=1026;
+  if (rc != duc_port) {
+    duc_port=rc;
+    fprintf(stderr,"GP: TX specific rcv        port is  %4d\n", rc);
+  }
+  rc=(buffer[9] << 8) + buffer[10];
+  if (rc == 0) rc=1027;
+  if (rc != hp_port) {
+    hp_port=rc;
+    fprintf(stderr,"GP: HighPrio Port rcv      port is  %4d\n", rc);
+  }
+  rc=(buffer[11] << 8) + buffer[12];
+  if (rc == 0) rc=1025;
+  if (rc != shp_port) {
+    shp_port=rc;
+    fprintf(stderr,"GP: HighPrio Port snd      port is  %4d\n", rc);
+  }
+  rc=(buffer[13] << 8) + buffer[14];
+  if (rc == 0) rc=1028;
+  if (rc != audio_port) {
+    audio_port=rc;
+    fprintf(stderr,"GP: Audio rcv              port is  %4d\n", rc);
+  }
+  rc=(buffer[15] << 8) + buffer[16];
+  if (rc == 0) rc=1029;
+  if (rc != duc0_port) {
+    duc0_port=rc;
+    fprintf(stderr,"GP: TX data rcv base       port is  %4d\n", rc);
+  }
+  rc=(buffer[17] << 8) + buffer[18];
+  if (rc == 0) rc=1035;
+  if (rc != ddc0_port) {
+    ddc0_port=rc;
+    fprintf(stderr,"GP: RX data snd base       port is  %4d\n", rc);
+  }
+  rc=(buffer[19] << 8) + buffer[20];
+  if (rc == 0) rc=1026;
+  if (rc != mic_port) {
+    mic_port=rc;
+    fprintf(stderr,"GP: Microphone data snd    port is  %4d\n", rc);
+  }
+  rc=(buffer[21] << 8) + buffer[22];
+  if (rc == 0) rc=1027;
+  if (rc != wide_port) {
+    wide_port=rc;
+    fprintf(stderr,"GP: Wideband data snd       port is  %4d\n", rc);
+  }
+  rc=buffer[23]; 
+  if (rc != wide_enable) {
+    wide_enable = rc;
+    fprintf(stderr,"GP: Wideband Enable Flag is %d\n", rc);
+  }
+  rc=(buffer[24] << 8) + buffer[25]; if (rc == 0) rc=512;
+  if (rc != wide_len) {
+    wide_len=rc;
+    fprintf(stderr,"GP: WideBand Length is %d\n", rc);
+  }
+  rc=buffer[26]; if (rc == 0) rc=16;
+  if (rc != wide_size) {
+    wide_size=rc;
+    fprintf(stderr,"GP: Wideband sample size is %d\n", rc);
+  }
+  rc=buffer[27];
+  if (rc != wide_rate) {
+    wide_rate=rc;
+    fprintf(stderr,"GP: Wideband sample rate is %d\n", rc);
+  }
+  rc=buffer[28];
+  if (rc != wide_ppf) {
+    wide_ppf = rc;
+    fprintf(stderr,"GP: Wideband PPF is %d\n", rc);
+  }
+  rc = (buffer[29] << 8) + buffer[30];
+  if (rc != port_mm) {
+    port_mm=rc;
+    fprintf(stderr,"MemMapped Registers rcv port is %d\n", rc);
+  }
+  rc = (buffer[31] << 8) + buffer[32];
+  if (rc != port_smm) {
+    port_smm=rc;
+    fprintf(stderr,"MemMapped Registers snd port is %d\n", rc);
+  }
+  rc = (buffer[33] << 8) + buffer[34];
+  if (rc != pwm_min) {
+    pwm_min=rc;
+    fprintf(stderr,"GP: PWM Min value is %d\n", rc);
+  }
+  rc = (buffer[35] << 8) + buffer[36];
+  if (rc != pwm_max) {
+    pwm_max=rc;
+    fprintf(stderr,"GP: PWM Max value is %d\n", rc);
+  }
+  rc=buffer[37];
+  if (rc != bits) {
+    bits=rc;
+    fprintf(stderr,"GP: ModeBits=x%02x\n", rc);
+  }
+  rc=buffer[38];
+  if (rc != hwtim) {
+    hwtim=rc;
+    fprintf(stderr,"GP: Hardware Watchdog enabled=%d\n", rc);
+  }
+
+  iqform = buffer[39];				if (iqform == 0) iqform=3;
+  if (iqform != 3) fprintf(stderr,"GP: Wrong IQ Format requested: %d\n",iqform);
+
+  rc = (buffer[58] & 0x01);
+  if (rc != pa_enable) {
+    pa_enable=rc;
+    fprintf(stderr,"GP: PA enabled=%d\n", rc);
+  }
+
+  rc=buffer[59] & 0x01;
+  if (rc != alex0_enable) {
+    alex0_enable=rc;
+    fprintf(stderr,"GP: ALEX0 register enable=%d\n", rc);
+  }
+  rc=(buffer[59] & 0x02) >> 1;
+  if (rc != alex1_enable) {
+    alex1_enable=rc;
+    fprintf(stderr,"GP: ALEX1 register enable=%d\n", rc);
+  }
+  //
+  // Start HighPrio thread if we arrive here for the first time
+  // The HighPrio thread keeps running all the time.
+  //
+  if (!highprio_thread_id) {
+	if (pthread_create(&highprio_thread_id, NULL, highprio_thread, NULL) < 0) {
+	  perror("***** ERROR: Create HighPrio thread");
+	}
+	pthread_detach(highprio_thread_id);
+
+  //
+  // init state arrays to zero for the first time
+  //
+  memset(adcdither, 0, 8*sizeof(int));
+  memset(adcrandom, 0, 8*sizeof(int));
+  memset(ddcenable, 0, NUMRECEIVERS*sizeof(int));
+  memset(adcmap, 0, NUMRECEIVERS*sizeof(int));
+  memset(syncddc, 0, NUMRECEIVERS*sizeof(int));
+
+  memset(rxfreq, 0, NUMRECEIVERS*sizeof(unsigned long));
+  memset(alex0, 0, 32*sizeof(int));
+  memset(alex1, 0, 32*sizeof(int));
+  memset(ptt  , 0, 4*sizeof(int));
+  }
+}
+
+void *ddc_specific_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  socklen_t lenaddr = sizeof(addr);
+  unsigned long seqnum,seqold;
+  struct timeval tv;
+  unsigned char buffer[2000];
+  int yes = 1;
+  int rc;
+  int i,j;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: RX specific: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+  tv.tv_sec = 0;
+  tv.tv_usec = 10000;
+  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(ddc_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: RX specific: bind");
+    return NULL;
+  }
+
+  while(run) {
+     rc = recvfrom(sock, buffer, 1444, 0,(struct sockaddr *)&addr, &lenaddr);
+     if (rc < 0 && errno != EAGAIN) {
+       perror("***** ERROR: DDC specific thread: recvmsg");
+       break;
+     }
+     if (rc < 0) continue;
+     if (rc != 1444) {
+       fprintf(stderr,"RX: Received DDC specific packet with incorrect length");
+       break;
+     }
+     seqold = seqnum;
+     seqnum = (buffer[0] >> 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+     if (seqnum != 0 &&seqnum != seqold+1 ) {
+       fprintf(stderr,"GP: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+     }
+     if (adc != buffer[4]) {
+       adc=buffer[4];
+       fprintf(stderr,"RX: Number of ADCs: %d\n",adc);
+     }
+     for (i=0; i<8; i++) {
+       rc=(buffer[5] >> i) & 0x01;
+       if (rc != adcdither[i]) {
+         adcdither[i]=rc;
+	 fprintf(stderr,"RX: ADC%d dither=%d\n",i,rc);
+       }
+     }
+     for (i=0; i<8; i++) {
+       rc=(buffer[6] >> i) & 0x01;
+       if (rc != adcrandom[i]) {
+         adcrandom[i]=rc;
+	 fprintf(stderr,"RX: ADC%d random=%d\n",i,rc);
+       }
+     }
+
+     for (i=0; i<NUMRECEIVERS; i++) {
+       int modified=0;
+
+       rc=(buffer[7 + (i/8)] >> (i % 8)) & 0x01;
+       if (rc != ddcenable[i]) {
+	 modified=1;
+	 ddcenable[i]=rc;
+       }
+       
+       rc=buffer[17+6*i];
+       if (rc != adcmap[i]) {
+	 modified=1;
+	 adcmap[i]=rc;
+       }
+
+       rc=(buffer[18+6*i] << 8) + buffer[19+6*i];
+       if (rc != rxrate[i]) {
+	 modified=1;
+	 rxrate[i]=rc;
+         modified=1;
+       }
+
+       if (syncddc[i] != buffer[1363+i]) {
+	 syncddc[i]=buffer[1363+i];
+         modified=1;
+       }
+       rc=(buffer[7 + (i/8)] >> (i % 8)) & 0x01;
+       if (rc != ddcenable[i]) {
+	 modified=1;
+	 ddcenable[i]=rc;
+       }
+       if (modified) {
+	 fprintf(stderr,"RX: DDC%d Enable=%d ADC%d Rate=%d SyncMap=%02x\n",
+		i,ddcenable[i], adcmap[i], rxrate[i], syncddc[i]);
+       }
+     }
+  }
+  close(sock);
+  return NULL;
+}
+
+void *duc_specific_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  socklen_t lenaddr=sizeof(addr);
+  unsigned long seqnum,seqold;
+  struct timeval tv;
+  unsigned char buffer[100];
+  int yes = 1;
+  int rc;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: TX specific: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+  tv.tv_sec = 0;
+  tv.tv_usec = 10000;
+  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(duc_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: TX specific: bind");
+    return NULL;
+  }
+
+  while(run) {
+     rc = recvfrom(sock, buffer, 60, 0,(struct sockaddr *)&addr, &lenaddr);
+     if (rc < 0 && errno != EAGAIN) {
+       perror("***** ERROR: DUC specific thread: recvmsg");
+       break;
+     }
+     if (rc < 0) continue;
+     if (rc != 60) {
+	fprintf(stderr,"TX: DUC Specific: wrong length\n");
+        break;
+     }
+     seqold = seqnum;
+     seqnum = (buffer[0] >> 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+     if (seqnum != 0 &&seqnum != seqold+1 ) {
+       fprintf(stderr,"GP: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+     }
+     if (dac != buffer[4]) {
+	dac=buffer[4];
+	fprintf(stderr,"TX: Number of DACs: %d\n", dac);
+     }
+     if (cwmode != buffer[5]) {
+	cwmode=buffer[5];
+	fprintf(stderr,"TX: CW mode bits = %x\n",cwmode);
+     }
+     if (sidelevel != buffer[6]) {
+	sidelevel=buffer[6];
+	fprintf(stderr,"TX: CW side tone level: %d\n", sidelevel);
+     }
+     rc=(buffer[7] << 8) + buffer[8];
+     if (rc != sidefreq) {
+	sidefreq = rc;
+	fprintf(stderr,"TX: CW sidetone freq: %d\n", sidefreq);
+     }
+     if (speed != buffer[9]) {
+	speed = buffer[9];
+	fprintf(stderr,"TX: CW keyer speed: %d wpm\n", speed);
+     }
+     if (weight != buffer[10]) {
+	weight=buffer[10];
+	fprintf(stderr,"TX: CW weight: %d\n", weight);
+     }
+     rc=(buffer[11] << 8) + buffer[12];
+     if (hang != rc) {
+	hang = rc;
+	fprintf(stderr,"TX: CW hang time: %d msec\n", hang);
+     }
+     if (delay != buffer[13]) {
+	delay=buffer[13];
+	fprintf(stderr,"TX: RF delay: %d msec\n", delay);
+     }
+     rc=(buffer[14] << 8) + buffer[15];
+     if (txrate != rc) {
+	txrate = rc;
+	fprintf(stderr,"TX: DUC sample rate: %d\n", rc);
+     }
+     if (ducbits != buffer[16]) {
+	ducbits=buffer[16];
+	fprintf(stderr,"TX: DUC sample width: %d bits\n", ducbits);
+     }
+     if (orion != buffer[50]) {
+	orion=buffer[50];
+	fprintf(stderr,"TX: ORION bits (mic etc): %x\n", orion);
+     }
+     if (gain != buffer[51]) {
+	gain= buffer[51];
+	fprintf(stderr,"TX: LineIn Gain (dB): %f\n", 12.0 - 1.5*gain);
+     }
+     if (txatt != buffer[59]) {
+	txatt = buffer[59];
+	txatt_dbl=pow(10.0, -0.05*txatt);
+	fprintf(stderr,"TX: ATT DUC0/ADC0: %d\n", txatt);
+     }
+  }
+  close(sock);
+  return NULL;
+}
+
+void *highprio_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  socklen_t lenaddr=sizeof(addr);
+  unsigned long seqnum,seqold;
+  unsigned char buffer[2000];
+  struct timeval tv;
+  int yes = 1;
+  int rc;
+  unsigned long freq;
+  int i;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: HP: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+  tv.tv_sec = 0;
+  tv.tv_usec = 10000;
+  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(hp_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: HP: bind");
+    return NULL;
+  }
+
+  while(1) {
+     rc = recvfrom(sock, buffer, 1444, 0,(struct sockaddr *)&addr, &lenaddr);
+     if (rc < 0 && errno != EAGAIN) {
+       perror("***** ERROR: HighPrio thread: recvmsg");
+       break;
+     }
+     if (rc < 0) continue;
+     if (rc != 1444) {
+       fprintf(stderr,"Received HighPrio packet with incorrect length");
+       break;
+     }
+     seqold = seqnum;
+     seqnum = (buffer[0] >> 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+     if (seqnum != 0 &&seqnum != seqold+1 ) {
+       fprintf(stderr,"GP: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+     }
+     rc=(buffer[4] >> 0) & 0x01;
+     if (rc != run) {
+	run=rc;
+	fprintf(stderr,"HP: Run=%d\n", rc);
+        // if run=0, wait for threads to complete, otherwise spawn them off
+        if (run) {
+          if (pthread_create(&ddc_specific_thread_id, NULL, ddc_specific_thread, NULL) < 0) {
+            perror("***** ERROR: Create DDC specific thread");
+          }
+          if (pthread_create(&duc_specific_thread_id, NULL, duc_specific_thread, NULL) < 0) {
+            perror("***** ERROR: Create DUC specific thread");
+          }
+          for (i=0; i< NUMRECEIVERS; i++) {
+            if (pthread_create(&rx_thread_id[i], NULL, rx_thread, (void *) (uintptr_t) i) < 0) {
+              perror("***** ERROR: Create RX thread");
+            }
+	  }
+          if (pthread_create(&tx_thread_id, NULL, tx_thread, NULL) < 0) {
+            perror("***** ERROR: Create TX thread");
+          }
+          if (pthread_create(&send_highprio_thread_id, NULL, send_highprio_thread, NULL) < 0) {
+            perror("***** ERROR: Create SendHighPrio thread");
+          }
+          if (pthread_create(&mic_thread_id, NULL, mic_thread, NULL) < 0) {
+            perror("***** ERROR: Create Mic thread");
+          }
+          if (pthread_create(&audio_thread_id, NULL, audio_thread, NULL) < 0) {
+            perror("***** ERROR: Create Audio thread");
+          }
+        } else {
+          pthread_join(ddc_specific_thread_id, NULL);
+          pthread_join(duc_specific_thread_id, NULL);
+          for (i=0; i<NUMRECEIVERS; i++) {
+            pthread_join(rx_thread_id[i], NULL);
+          }
+          pthread_join(send_highprio_thread_id, NULL);
+          pthread_join(tx_thread_id, NULL);
+          pthread_join(mic_thread_id, NULL);
+          pthread_join(audio_thread_id, NULL);
+        }
+     }
+     for (i=0; i<4; i++) {
+       rc=(buffer[4] >> (i+1)) & 0x01;
+       if (rc != ptt[i]) {
+	ptt[i]=rc;
+	fprintf(stderr,"HP: PTT%d=%d\n", i, rc);
+      }
+     }
+     rc=(buffer[5] >> 0) & 0x01;
+     if (rc != cwx) {
+	cwx=rc;
+	fprintf(stderr,"HP: CWX=%d\n", rc);
+     }
+     rc=(buffer[5] >> 1) & 0x01;
+     if (rc != dot) {
+	dot=rc;
+	fprintf(stderr,"HP: DOT=%d\n", rc);
+     }
+     rc=(buffer[5] >> 2) & 0x01;
+     if (rc != dash) {
+	dash=rc;
+	fprintf(stderr,"HP: DASH=%d\n", rc);
+     }
+     for (i=0; i<NUMRECEIVERS; i++) {
+	freq=(buffer[ 9+4*i] << 24) + (buffer[10+4*i] << 16) + (buffer[11+4*i] << 8) + buffer[12+4*i];
+        if (bits & 0x08) {
+	  freq=round(122880000.0*(double) freq / 4294967296.0);
+	}
+        if (freq != rxfreq[i]) {
+	  rxfreq[i]=freq;
+	  fprintf(stderr,"HP: DDC%d freq: %lu\n", i, freq);
+	}
+     }
+     freq=(buffer[329] << 24) + (buffer[330] << 16) + (buffer[331] << 8) + buffer[332];
+     if (bits & 0x08) {
+	freq=round(122880000.0*(double) freq / 4294967296.0);
+     }
+     if (freq != txfreq) {
+	txfreq=freq;
+	fprintf(stderr,"HP: DUC freq: %lu\n", freq);
+     }
+     rc=buffer[345];
+     if (rc != txdrive) {
+	txdrive=rc;
+	txdrv_dbl=(double) txdrive * 0.003921568627;
+	fprintf(stderr,"HP: TX drive= %d (%f)\n", txdrive,txdrv_dbl);
+     }
+     rc=buffer[1400];
+     if (rc != w1400) {
+	w1400=rc;
+	fprintf(stderr,"HP: Xvtr/Audio enable=%x\n", rc);
+     }
+     rc=buffer[1401];
+     if (rc != ocout) {
+	ocout=rc;
+	fprintf(stderr,"HP: OC outputs=%x\n", rc);
+     }
+     rc=buffer[1402];
+     if (rc != db9) {
+	db9=rc;
+	fprintf(stderr,"HP: Outputs DB9=%x\n", rc);
+     }
+     rc=buffer[1403];
+     if (rc != mercury_atts) {
+	mercury_atts=rc;
+	fprintf(stderr,"HP: MercuryAtts=%x\n", rc);
+     }
+     // Store Alex0 and Alex1 bits in separate ints
+     freq=(buffer[1428] << 24) + (buffer[1429] << 16) + (buffer[1430] << 8) + buffer[1431];
+     for (i=0; i<32; i++) {
+	rc=(freq >> i) & 0x01;
+	if (rc != alex1[i]) {
+	    alex1[i]=rc;
+	    fprintf(stderr,"HP: ALEX1 bit%d set to %d\n", i, rc);
+	}
+     }
+     freq=(buffer[1432] << 24) + (buffer[1433] << 16) + (buffer[1434] << 8) + buffer[1435];
+     for (i=0; i<32; i++) {
+	rc=(freq >> i) & 0x01;
+	if (rc != alex0[i]) {
+	    alex0[i]=rc;
+	    fprintf(stderr,"HP: ALEX0 bit%d set to %d\n", i, rc);
+	}
+     }
+     rc=buffer[1442];
+     if (rc != stepatt1) {
+	stepatt1=rc;
+	rxatt1_dbl=pow(10.0, -0.05*stepatt1);
+	fprintf(stderr,"HP: StepAtt1 = %d\n", rc);
+     }
+     rc=buffer[1443];
+     if (rc != stepatt0) {
+	stepatt0=rc;
+	rxatt0_dbl=pow(10.0, -0.05*stepatt0);
+	fprintf(stderr,"HP: StepAtt0 = %d\n", stepatt0);
+     }
+  }
+  return NULL;
+}
+
+void *rx_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  // One instance of this thread is started for each DDC
+  unsigned long seqnum;
+  unsigned char buffer[1444];
+  int yes = 1;
+  int rc;
+  int ddc;
+  int i;
+  unsigned long time;
+  long wait;
+  double i0sample,q0sample;
+  double i1sample,q1sample;
+  double irsample,qrsample;
+  double fac;
+  int sample;
+  unsigned char *p;
+  int noisept;
+  int myddc;
+  long myrate;
+  int sync,size;
+  int myadc, syncadc;
+  int ps=0;
+  int rxptr;
+  
+  struct timespec delay;
+#ifdef __APPLE__
+  struct timespec now;
+#endif
+
+  myddc=(int) (uintptr_t) data;
+  if (myddc < 0 || myddc >= NUMRECEIVERS) return NULL;
+  seqnum=0;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: RXthread: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(ddc0_port+myddc);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: RXthread: bind");
+    return NULL;
+  }
+
+  noisept=0;
+  clock_gettime(CLOCK_MONOTONIC, &delay);
+  fprintf(stderr,"RX thread %d, enabled=%d\n", myddc, ddcenable[myddc]);
+  rxptr=txptr-5000;  
+  if (rxptr < 0) rxptr += NEWRTXLEN;
+  while (run) {
+	if (!ddcenable[myddc] || rxrate[myddc] == 0 || rxfreq[myddc] == 0) {
+	  usleep(5000);
+          clock_gettime(CLOCK_MONOTONIC, &delay);
+	  rxptr=txptr-5000;  
+	  if (rxptr < 0) rxptr += NEWRTXLEN;
+          continue;
+        }
+	myadc=adcmap[myddc];
+        // for simplicity, we only allow for a single "synchronized" DDC,
+        // this well covers the PURESIGNAL and DIVERSITY cases
+	sync=0;
+	i=syncddc[myddc];
+	while (i) {
+	  sync++;
+	  i = i >> 1;
+	}
+	// sync == 0 means no synchronizatsion
+        // sync == 1,2,3  means synchronization with DDC0,1,2
+	// Usually we send 238 samples per buffer, but with synchronization
+	// we send 119 sample *pairs*.
+        if (sync) {
+	  size=119;
+          wait=119000000L/rxrate[myddc]; // time for these samples in nano-secs
+	  syncadc=adcmap[sync-1];
+	} else {
+	  size=238;
+          wait=238000000L/rxrate[myddc]; // time for these samples in nano-secs
+	}
+	//
+	// ADC0: noise   (+ distorted TX signal upon TXing)
+	// ADC1: noise   20 dB stronger
+	// ADC2:         original TX signal (ADC1 on HERMES)
+	//
+	  
+        ps=(sync && (rxrate[myadc]==192) && ptt[0] && (syncadc == adc));
+        p=buffer;
+        *p++ =(seqnum >> 24) & 0xFF;
+        *p++ =(seqnum >> 16) & 0xFF;
+        *p++ =(seqnum >>  8) & 0xFF;
+        *p++ =(seqnum >>  0) & 0xFF;
+        seqnum += 1;
+        // do not use time stamps
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	// 24 bits per sample *ALWAYS*
+	*p++ = 0;
+	*p++ = 24;
+	*p++ = 0;
+	*p++ = sync ? 2*size : size;  // should be 238 in either case
+	for (i=0; i<size; i++) {
+	  //
+	  // produce noise depending on the ADC
+	  //
+	  i1sample=i0sample=noiseItab[noisept];
+	  q1sample=q0sample=noiseItab[noisept++];
+          if (noisept == LENNOISE) noisept=rand() / NOISEDIV;
+	  if (myadc == 1) {
+	    i0sample=i0sample*10.0;   // 20 dB more noise on ADC1
+	    q0sample=q0sample*10.0;
+          }
+	  //
+	  // PS: produce sample PAIRS,
+	  // a) distorted TX data (with Drive and Attenuation) 
+	  // b) original TX data (normalized)
+	  //
+	  if (ps) {
+	    irsample = isample[rxptr];
+	    qrsample = qsample[rxptr++];
+	    if (rxptr >= NEWRTXLEN) rxptr=0;
+	    fac=txatt_dbl*txdrv_dbl*(IM3a+IM3b*(irsample*irsample+qrsample*qrsample)*txdrv_dbl*txdrv_dbl);
+	    if (myadc == 0) {
+	      i0sample += irsample*fac;
+	      q0sample += qrsample*fac;
+	    }
+	  }
+	  if (sync) {
+	    if (ps) {
+	      // synchronized stream: undistorted TX signal with constant max. amplitude
+	      i1sample = irsample * 0.329;
+	      q1sample = qrsample * 0.329;
+	    }
+	    sample=i0sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	    sample=q0sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	    sample=i1sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	    sample=q1sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	  } else {
+	    sample=i0sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	    sample=q0sample * 8388607.0;
+	    *p++=(sample >> 16) & 0xFF;
+	    *p++=(sample >>  8) & 0xFF;
+	    *p++=(sample >>  0) & 0xFF;
+	  }
+        }
+        delay.tv_nsec += wait;
+        while (delay.tv_nsec >= 1000000000) {
+          delay.tv_nsec -= 1000000000;
+          delay.tv_sec++;
+	}
+#ifdef __APPLE__
+        //
+        // The (so-called) operating system for Mac does not have clock_nanosleep(),
+        // but is has clock_gettime as well as nanosleep.
+        // So, to circumvent this problem, we look at the watch and determine
+        // how long we should sleep now.
+        //
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        now.tv_sec =delay.tv_sec  - now.tv_sec;
+        now.tv_nsec=delay.tv_nsec - now.tv_nsec;
+        while (now.tv_nsec < 0) {
+         now.tv_nsec += 1000000000;
+         now.tv_sec--;
+        }
+        nanosleep(&now, NULL);
+#else
+        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &delay, NULL);
+#endif
+        if (sendto(sock, buffer, 1444, 0, (struct sockaddr*)&addr_new, sizeof(addr_new)) < 0) {
+          perror("***** ERROR: RX thread sendto");
+          break;
+	}
+  }
+  close(sock);
+  return NULL;
+}
+
+//
+// This thread receives data (TX samples) from the PC
+//
+void *tx_thread(void * data) {
+  int sock;
+  struct sockaddr_in addr;
+  socklen_t lenaddr=sizeof(addr);
+  unsigned long seqnum, seqold;
+  unsigned char buffer[1444];
+  int yes = 1;
+  int rc;
+  int i;
+  unsigned char *p;
+  int noisept;
+  int sample;
+  double di,dq;
+  double sum;
+  struct timeval tv;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: TX: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+  tv.tv_sec = 0;
+  tv.tv_usec = 10000;
+  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(duc0_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: TX: bind");
+    return NULL;
+  }
+
+  seqnum=0; 
+  while(run) {
+     rc = recvfrom(sock, buffer, 1444, 0,(struct sockaddr *)&addr, &lenaddr);
+     if (rc < 0 && errno != EAGAIN) {
+       perror("***** ERROR: TX thread: recvmsg");
+       break;
+     }
+     if (rc < 0) continue;
+     if (rc != 1444) {
+       fprintf(stderr,"Received TX packet with incorrect length");
+       break;
+     }
+     seqold = seqnum;
+     seqnum = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+     if (seqnum != 0 &&seqnum != seqold+1 ) {
+       fprintf(stderr,"TXthread: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+     }
+     p=buffer+4;
+     sum=0.0;
+     for (i=0; i<240; i++) {
+	// process 240 TX iq samples
+        sample  = (int)((signed char) (*p++))<<16;
+        sample |= (int)((((unsigned char)(*p++))<<8)&0xFF00);
+        sample |= (int)((unsigned char)(*p++)&0xFF);
+	di = (double) sample / 8388608.0;
+        sample  = (int)((signed char) (*p++))<<16;
+        sample |= (int)((((unsigned char)(*p++))<<8)&0xFF00);
+        sample |= (int)((unsigned char)(*p++)&0xFF);
+	dq = (double) sample / 8388608.0;
+//
+//      put TX samples into ring buffer
+//
+	isample[txptr]=di;
+	qsample[txptr++]=dq;
+	if (txptr >= NEWRTXLEN) txptr=0;
+//
+//      accumulate TX power
+//
+        sum += (di*di+dq*dq);
+     }
+     txlevel=sum * txdrv_dbl * txdrv_dbl * 0.0041667;
+     fprintf(stderr,"LEV1=%f LEV2=%f\n", sum*0.0041667, txlevel);
+  }
+  return NULL;
+}
+
+void *send_highprio_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  unsigned long seqnum;
+  unsigned char buffer[60];
+  int yes = 1;
+  int rc;
+  int i;
+  unsigned char *p;
+
+
+  seqnum=0;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: SendHighPrio thread: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(shp_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: SendHighPrio thread: bind");
+    return NULL;
+  }
+
+  seqnum=0;
+  while (1) {
+    if (!run) {
+	close(sock);
+	break;
+    }
+    // prepare buffer
+    memset(buffer, 0, 60);
+    p=buffer;
+    *p++ = (seqnum >> 24) & 0xFF;
+    *p++ = (seqnum >> 16) & 0xFF;
+    *p++ = (seqnum >>  8) & 0xFF;
+    *p++ = (seqnum >>  0) & 0xFF;
+    *p++ = 0;    // no PTT and CW attached
+    *p++ = 0;    // no ADC overload
+    *p++ = 1;
+    *p++ = 126;    // 1 W exciter power
+ 
+    p +=6;
+
+    rc=(int) (800.0*sqrt(10*txlevel));    
+    *p++ = (rc >> 8) & 0xFF;
+    *p++ = (rc     ) & 0xFF;
+
+    buffer[49]=63;   // about 13 volts supply 
+
+    if (sendto(sock, buffer, 60, 0, (struct sockaddr*)&addr_new, sizeof(addr_new)) < 0) {
+       perror("***** ERROR: HP send thread sendto");
+       break;
+    }
+    seqnum++;
+    usleep(50000); // wait 50 msec
+  }
+  close(sock);
+  return NULL;
+}
+
+//
+// This thread receives the audio samples and plays them
+//
+void *audio_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  socklen_t lenaddr=sizeof(addr);
+  unsigned long seqnum, seqold;
+  unsigned char buffer[260];
+  int yes = 1;
+  int rc;
+  int i;
+  unsigned char *p;
+  int16_t lsample,rsample;
+  struct timeval tv;
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: Audio: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+  tv.tv_sec = 0;
+  tv.tv_usec = 10000;
+  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(audio_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: Audio: bind");
+    return NULL;
+  }
+
+  seqnum=0;
+  while(run) {
+     rc = recvfrom(sock, buffer, 260, 0,(struct sockaddr *)&addr, &lenaddr);
+     if (rc < 0 && errno != EAGAIN) {
+       perror("***** ERROR: Audio thread: recvmsg");
+       break;
+     }
+     if (rc < 0) continue;
+     if (rc != 260) {
+       fprintf(stderr,"Received Audio packet with incorrect length");
+       break;
+     }
+     seqold = seqnum;
+     seqnum = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+     if (seqnum != 0 &&seqnum != seqold+1 ) {
+       fprintf(stderr,"Audio thread: SEQ ERROR, old=%lu new=%lu\n", seqold, seqnum);
+     }
+     p=buffer+4;
+     for (i=0; i<64; i++) {
+       lsample  = ((signed char) *p++) << 8;	
+       lsample |= (*p++ & 0xff); 
+       rsample  = ((signed char) *p++) << 8;	
+       rsample |= (*p++ & 0xff); 
+       audio_write(lsample,rsample);
+    }
+  }
+  close (sock);
+  return NULL;
+}
+
+//
+// The microphone thread generates
+// a two-tone signal
+//
+void *mic_thread(void *data) {
+  int sock;
+  struct sockaddr_in addr;
+  unsigned long seqnum;
+  unsigned char buffer[132];
+  unsigned char *p;
+  int yes = 1;
+  int rc;
+  int i;
+  double arg1,arg2;
+  int sintab[480];  // microphone data
+  int sinptr = 0;
+  struct timespec delay;
+#ifdef __APPLE__
+  struct timespec now;
+#endif
+
+#define FREQ900  0.11780972450961724644234912687298
+#define FREQ1700 0.22252947962927702105777057298230
+
+  seqnum=0;
+  arg1=0.0;
+  arg2=0.0;
+  for (i=0; i<480; i++) {
+    sintab[i]=(int) round((sin(arg1)+sin(arg2)) * 5000.0);
+    arg1 += FREQ900;
+    arg2 += FREQ1700;
+  }
+
+  sock=socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    perror("***** ERROR: Mic thread: socket");
+    return NULL;
+  }
+
+  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(mic_port);
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("***** ERROR: Mic thread: bind");
+    return NULL;
+  }
+
+  seqnum=0;
+  memset(buffer, 0, 132);
+  clock_gettime(CLOCK_MONOTONIC, &delay);
+  while (run) {
+    // update seq number
+    p=buffer;
+    *p++ = (seqnum >> 24) & 0xFF;
+    *p++ = (seqnum >> 16) & 0xFF;
+    *p++ = (seqnum >>  8) & 0xFF;
+    *p++ = (seqnum >>  0) & 0xFF;
+    seqnum++;
+    // take periodic data from sintab as "microphone samples"
+    for (i=0; i< 64; i++) {
+	rc=sintab[sinptr++];
+        if (sinptr == 480) sinptr=0;
+        *p++ = (rc >> 8)  & 0xff;
+        *p++ = (rc & 0xff);
+    }
+    // 64 samples with 48000 kHz, makes 1333333 nsec
+    delay.tv_nsec += 1333333;
+    while (delay.tv_nsec >= 1000000000) {
+      delay.tv_nsec -= 1000000000;
+      delay.tv_sec++;
+    }
+#ifdef __APPLE__
+    //
+    // The (so-called) operating system for Mac does not have clock_nanosleep(),
+    // but is has clock_gettime as well as nanosleep.
+    // So, to circumvent this problem, we look at the watch and determine
+    // how long we should sleep now.
+    //
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    now.tv_sec =delay.tv_sec  - now.tv_sec;
+    now.tv_nsec=delay.tv_nsec - now.tv_nsec;
+    while (now.tv_nsec < 0) {
+     now.tv_nsec += 1000000000;
+     now.tv_sec--;
+    }
+    nanosleep(&now, NULL);
+#else
+    clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &delay, NULL);
+#endif
+    if (sendto(sock, buffer, 132, 0, (struct sockaddr*)&addr_new, sizeof(addr_new)) < 0) {
+      perror("***** ERROR: Mic thread sendto");
+      break;
+    }
+  }
+  close(sock);
+  return NULL;
+}
+  
+