From 14f5a0faa91f221885c40bbadf0c8c889faa7f1e Mon Sep 17 00:00:00 2001
From: pa3gsb <pa3gsb@gmail.com>
Date: Tue, 7 Nov 2017 17:09:55 +0100
Subject: [PATCH] cw for radioberry

---
 Makefile      |  7 ++-----
 audio.c       | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 beep.c        |  3 ++-
 gpio.c        | 12 ++++++++++-
 iambic.c      | 30 ++++++++--------------------
 radio.c       |  5 ++++-
 transmitter.c | 39 +++++++++++++++++++++++++++++++++---
 transmitter.h |  2 ++
 8 files changed, 120 insertions(+), 33 deletions(-)

diff --git a/Makefile b/Makefile
index f6d25ab..f2bbea0 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ GPIO_INCLUDE=GPIO
 #SX1509_INCLUDE=sx1509
 
 # uncomment the line to below include support local CW keyer
-#LOCALCW_INCLUDE=LOCALCW
+LOCALCW_INCLUDE=LOCALCW
 
 # uncomment the line below to include MCP23017 I2C
 #I2C_INCLUDE=I2C
@@ -52,7 +52,7 @@ endif
 #LIMESDR_INCLUDE=LIMESDR
 
 # uncomment the line below when Radioberry radio cape is plugged in
-#RADIOBERRY_INCLUDE=RADIOBERRY
+RADIOBERRY_INCLUDE=RADIOBERRY
 
 ifeq ($(RADIOBERRY_INCLUDE),RADIOBERRY)
 RADIOBERRY_OPTIONS=-D RADIOBERRY
@@ -115,13 +115,10 @@ endif
 ifeq ($(LOCALCW_INCLUDE),LOCALCW)
 LOCALCW_OPTIONS=-D LOCALCW
 LOCALCW_SOURCES= \
-beep.c \
 iambic.c
 LOCALCW_HEADERS= \
-beep.h \
 iambic.h
 LOCALCW_OBJS= \
-beep.o \
 iambic.o
 endif
 
diff --git a/audio.c b/audio.c
index 0a0fab6..b563af1 100644
--- a/audio.c
+++ b/audio.c
@@ -76,6 +76,9 @@ char *output_devices[16];
 int n_output_devices=0;
 //int n_selected_output_device=-1;
 
+int playback_cw_offset = 0;
+unsigned char *playback_cw_buffer;
+
 int audio_open_output(RECEIVER *rx) {
   int err;
   snd_pcm_hw_params_t *hw_params;
@@ -156,6 +159,8 @@ fprintf(stderr,"audio_open_output: selected=%d:%s\n",rx->audio_device,selected);
 
   rx->playback_offset=0;
   rx->playback_buffer=(unsigned char *)malloc(OUTPUT_BUFFER_SIZE);
+  
+  playback_cw_buffer = (unsigned char *)malloc(OUTPUT_BUFFER_SIZE);
 
   return 0;
 }
@@ -288,6 +293,56 @@ void audio_close_input() {
     free(mic_buffer);
     mic_buffer=NULL;
   }
+  if (playback_cw_buffer!=NULL) {
+	  free(playback_cw_buffer);
+	  playback_cw_buffer=NULL;
+  }
+}
+
+//write side tone for cw...
+int cw_audio_write(double sample){
+	
+	snd_pcm_sframes_t delay;
+	int error;
+	long trim;
+	RECEIVER *rx = receiver[0];
+	//fprintf(stderr, "cw audio write \n");
+	if(rx->playback_handle!=NULL && playback_cw_buffer!=NULL) {
+	
+		// convert double sample to short and assign sample to L and R channel.
+		short ssample = (short)(sample*32767.0);
+		playback_cw_buffer[playback_cw_offset++] = ssample;
+		playback_cw_buffer[playback_cw_offset++] = ssample>>8;
+		playback_cw_buffer[playback_cw_offset++] = ssample;
+		playback_cw_buffer[playback_cw_offset++] = ssample>>8;
+		
+		if(playback_cw_offset==OUTPUT_BUFFER_SIZE) {
+			      trim=0;
+
+			if(snd_pcm_delay(rx->playback_handle,&delay)==0) {
+				if(delay>2048) {
+				  trim=delay-2048;
+				}
+			}
+
+			if ((error = snd_pcm_writei (rx->playback_handle, playback_cw_buffer, audio_buffer_size-trim)) != audio_buffer_size-trim) {
+				if(error==-EPIPE) {
+				  if ((error = snd_pcm_prepare (rx->playback_handle)) < 0) {
+					fprintf (stderr, "audio_write: cannot prepare audio interface for use (%s)\n",
+							snd_strerror (error));
+					return -1;
+				  }
+				  if ((error = snd_pcm_writei (rx->playback_handle, playback_cw_buffer, audio_buffer_size-trim)) != audio_buffer_size) {
+					fprintf (stderr, "audio_write: write to audio interface failed (%s)\n",
+							snd_strerror (error));
+					return -1;
+				  }
+				}
+			}
+			playback_cw_offset=0;
+		}
+	}
+	return 0;
 }
 
 int audio_write(RECEIVER *rx,short left_sample,short right_sample) {
diff --git a/beep.c b/beep.c
index 7fd9669..9178873 100644
--- a/beep.c
+++ b/beep.c
@@ -339,6 +339,7 @@ static void* beep_thread(void *arg) {
                 return 0;
         }
 
+		
         if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
                 printf("Playback open error: %s\n", snd_strerror(err));
                 return 0;
@@ -353,7 +354,7 @@ static void* beep_thread(void *arg) {
                 printf("Setting of swparams failed: %s\n", snd_strerror(err));
                 exit(EXIT_FAILURE);
         }
-
+		
         samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8);
         if (samples == NULL) {
                 printf("No enough memory\n");
diff --git a/gpio.c b/gpio.c
index d3ec303..8b16f11 100644
--- a/gpio.c
+++ b/gpio.c
@@ -382,8 +382,11 @@ static void lockAlert(int gpio, int level, uint32_t tick) {
 
 #ifdef LOCALCW
 static void cwAlert(int gpio, int level, uint32_t tick) {
-    if (cw_keyer_internal == 0 && (mode==modeCWL || mode==modeCWU))
+	fprintf(stderr,"init cwAlert\n");
+    if (cw_keyer_internal == 0 ){
+		fprintf(stderr,"call keyer_event...\n");
        keyer_event(gpio, cw_active_level == 0 ? level : (level==0));
+	}
 }
 #endif
 
@@ -781,6 +784,13 @@ int gpio_init() {
         fprintf(stderr,"Cannot initialize GPIO\n");
         return -1;
     }
+	
+// required for softtone in iambic.c 	
+//	if (wiringPiSetup () < 0) {
+//		printf ("Unable to setup wiringPi: %s\n", strerror (errno));
+//		return -1;
+//	}
+	
 
   if(ENABLE_FUNCTION_BUTTON) {
     setup_button(FUNCTION_BUTTON, functionAlert);
diff --git a/iambic.c b/iambic.c
index aa94ecf..36f5611 100644
--- a/iambic.c
+++ b/iambic.c
@@ -77,13 +77,13 @@
 #include "radio.h"
 #include "new_protocol.h"
 #include "iambic.h"
-#include "beep.h"
+#include "transmitter.h"
 
 static void* keyer_thread(void *arg);
 static pthread_t keyer_thread_id;
 
 // set to 0 to use the PI's hw:0 audio out for sidetone
-#define SIDETONE_GPIO 0 // this is in wiringPi notation
+#define SIDETONE_GPIO 0 // this is in wiringPi notation // tried 4 working great.
 
 #define MY_PRIORITY (90)
 #define MAX_SAFE_STACK (8*1024)
@@ -147,8 +147,7 @@ void keyer_update() {
         kdot = &kcwl;
         kdash = &kcwr;
     }
-    beep_vol(cw_keyer_sidetone_volume);
-    beep_freq = cw_keyer_sidetone_frequency;
+
 }
 
 void keyer_event(int gpio, int level) {
@@ -173,17 +172,18 @@ void set_keyer_out(int state) {
     if (keyer_out != state) {
         keyer_out = state;
         if(protocol==NEW_PROTOCOL) schedule_high_priority(9);
+		fprintf(stderr,"set_keyer_out keyer_out= %d\n", keyer_out);
         if (state)
             if (SIDETONE_GPIO)
                 softToneWrite (SIDETONE_GPIO, cw_keyer_sidetone_frequency);
             else {
-                beep_mute(1);
+				cw_sidetone_mute(1);
             }
         else
             if (SIDETONE_GPIO)
                 softToneWrite (SIDETONE_GPIO, 0);
             else  {
-                beep_mute(0);
+				cw_sidetone_mute(0);
             }
     }
 }
@@ -193,7 +193,7 @@ static void* keyer_thread(void *arg) {
     struct timespec loop_delay;
     int interval = 1000000; // 1 ms
 
-fprintf(stderr,"keyer_thread\n");
+fprintf(stderr,"keyer_thread  state running= %d\n", running);
     while(running) {
         sem_wait(&cw_event);
 
@@ -367,7 +367,6 @@ fprintf(stderr,"keyer_thread: EXIT\n");
 
 void keyer_close() {
     running=0;
-    beep_close();
 }
 
 int keyer_init() {
@@ -385,21 +384,8 @@ int keyer_init() {
             running = 0;
     }
 
-    //stack_prefault();
-
-
-/*
-    if (wiringPiSetup () < 0) {
-        fprintf(stderr,"pthread_create for keyer_thread failed %d\n", rc);
-        exit(-1);
-    }
-*/
-
-    if (SIDETONE_GPIO)
+    if (SIDETONE_GPIO){
         softToneCreate(SIDETONE_GPIO);
-    else {
-        beep_init();
-        beep_vol(cw_keyer_sidetone_volume);
     }
 
     rc = sem_init(&cw_event, 0, 0);
diff --git a/radio.c b/radio.c
index bf571a5..3be4121 100644
--- a/radio.c
+++ b/radio.c
@@ -442,13 +442,16 @@ fprintf(stderr,"receiver %d: height=%d y=%d\n",receiver[i]->id,rx_height,y);
 
   
   #ifdef GPIO
+  fprintf(stderr,"keyer.....\n");
   if(gpio_init()<0) {
     fprintf(stderr,"GPIO failed to initialize\n");
   }
 #ifdef LOCALCW
   // init local keyer if enabled
-  else if (cw_keyer_internal == 0)
+  else if (cw_keyer_internal == 0) {
+	fprintf(stderr,"Initialize keyer.....\n");
     keyer_update();
+  }
 #endif
 #endif
   
diff --git a/transmitter.c b/transmitter.c
index 51c8264..ea37b2e 100644
--- a/transmitter.c
+++ b/transmitter.c
@@ -42,9 +42,13 @@
 #define min(x,y) (x<y?x:y)
 #define max(x,y) (x<y?y:x)
 
+double getNextSideToneSample();
+
 static int filterLow;
 static int filterHigh;
 
+int key = 0;
+
 static gint update_out_of_band(gpointer data) {
   TRANSMITTER *tx=(TRANSMITTER *)data;
   tx->out_of_band=0;
@@ -639,13 +643,21 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) {
       break;
 #endif
     default:
-      if(mode==modeCWL || mode==modeCWU || tune) {
-        mic_sample_double=0.0;
+	  if (tune) {
+		  mic_sample_double=0.0;
+	  }
+      else if(mode==modeCWL || mode==modeCWU) {
+		if (isTransmitting()) {
+			if (key == 1) {
+				mic_sample_double = getNextSideToneSample();
+				cw_audio_write(mic_sample_double * cw_keyer_sidetone_volume/ 127.0);
+				mic_sample_double = mic_sample_double * 200000; //* amplitude 
+			} else mic_sample_double=0.0;
+		}
       } else {
         sample=mic_sample<<16;
         mic_sample_double=(1.0 / 2147483648.0) * (double)(sample);
       }
-//fprintf(stderr,"add_mic_sample: id=%d sample=%f (%d,%ld)\n",tx->id,mic_sample_double,mic_sample,sample);
       tx->mic_input_buffer[tx->samples*2]=mic_sample_double;
       tx->mic_input_buffer[(tx->samples*2)+1]=mic_sample_double;
       tx->samples++;
@@ -665,3 +677,24 @@ fprintf(stderr,"start tx display update timer: %d\n", 1000/tx->fps);
   }
 }
 
+void cw_sidetone_mute(int mute){
+	key = mute;
+}
+
+int asteps = 0;
+double timebase = 0.0;
+#define TIMESTEP (1.0 / 48000)
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+double getNextSideToneSample() {
+	double angle = cw_keyer_sidetone_frequency * 2 * M_PI * timebase;
+	timebase += TIMESTEP;
+	asteps++;
+	if (asteps == 48000) {
+		timebase = 0.0;
+		asteps = 0;
+	}
+	return sin(angle);
+}	
+
diff --git a/transmitter.h b/transmitter.h
index c4eeda2..6ff50aa 100644
--- a/transmitter.h
+++ b/transmitter.h
@@ -87,4 +87,6 @@ extern void add_mic_sample(TRANSMITTER *tx,short mic_sample);
 
 extern void transmitter_save_state(TRANSMITTER *tx);
 extern void transmitter_set_out_of_band(TRANSMITTER *tx);
+
+extern void cw_sidetone_mute(int mute);
 #endif
-- 
2.45.2