Removed Ultimatic keyer mode. Added digital outputs for keyer and PTT (T/R switch) lines. Streamlined the code for the semaphores. Made it more configurable / less #defines.
This commit is contained in:
parent
9892ccb1a4
commit
1b4775f452
|
@ -1 +1 @@
|
|||
#Quisk version 4.1.52
|
||||
#Quisk version 4.1.52-upr1
|
||||
|
|
220
gpiokeyer.c
220
gpiokeyer.c
|
@ -68,7 +68,7 @@ Boston, MA 02110-1301, USA.
|
|||
Speed calculation - Using standard PARIS timing, dot_period(mS) = 1200/WPM
|
||||
*/
|
||||
|
||||
//#define DEBUG
|
||||
#define DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -90,16 +90,20 @@ static void* keyer_thread(void *arg);
|
|||
static pthread_t keyer_thread_id;
|
||||
|
||||
// GPIO pins
|
||||
#define KEYER_OUT_GPIO 26
|
||||
#define LEFT_PADDLE_GPIO 22
|
||||
#define RIGHT_PADDLE_GPIO 27
|
||||
//#define LEFT_PADDLE_GPIO 22
|
||||
//#define RIGHT_PADDLE_GPIO 27
|
||||
//#define KEY_OUT_GPIO 23
|
||||
//#define PTT_OUT_GPIO 24
|
||||
static int left_paddle_gpio = 22;
|
||||
static int right_paddle_gpio = 27;
|
||||
static int keyer_out_gpio = 23;
|
||||
static int tr_switch_gpio = 24;
|
||||
|
||||
// Keyer modes
|
||||
#define KEYER_STRAIGHT 0
|
||||
#define KEYER_MODE_A 1
|
||||
#define KEYER_MODE_B 2
|
||||
#define KEYER_ULTIMATIC 3
|
||||
#define NUM_KEYER_MODES 4
|
||||
#define NUM_KEYER_MODES 3
|
||||
|
||||
#define NSEC_PER_SEC (1000000000)
|
||||
|
||||
|
@ -114,42 +118,45 @@ enum {
|
|||
DOTHELD,
|
||||
DASHHELD,
|
||||
LETTERSPACE,
|
||||
HANGTIME,
|
||||
EXITLOOP
|
||||
};
|
||||
|
||||
enum {
|
||||
NONE = 0,
|
||||
DOT = 1,
|
||||
DASH = 2
|
||||
};
|
||||
|
||||
static int dot_memory = 0;
|
||||
static int dash_memory = 0;
|
||||
static int key_state = 0;
|
||||
static int kdelay = 0;
|
||||
static int dot_delay = 0;
|
||||
static int dash_delay = 0;
|
||||
static int kcwl = 0;
|
||||
static int kcwr = 0;
|
||||
static volatile int kcwl = 0;
|
||||
static volatile int kcwr = 0;
|
||||
static int *kdot;
|
||||
static int *kdash;
|
||||
static int cw_keyer_speed = 20;
|
||||
static int cw_keyer_weight = 55;
|
||||
static int cw_keys_reversed = 0;
|
||||
static int cw_keyer_mode = KEYER_MODE_B;
|
||||
static int cw_keyer_mode = KEYER_MODE_A;
|
||||
static int cw_keyer_spacing = 0;
|
||||
static int cw_active_state = 0;
|
||||
static sem_t cw_event;
|
||||
|
||||
static int last_pressed = NONE;
|
||||
#if defined(DEBUG)
|
||||
static int cw_event_value;
|
||||
#endif
|
||||
static int cw_hangtime_msec = 250;
|
||||
|
||||
static int running, keyer_out = 0;
|
||||
|
||||
static inline int kstate() {
|
||||
return (*kdash<<1)&(*kdot);
|
||||
}
|
||||
// Function prototypes
|
||||
|
||||
static int prev_state = 0;
|
||||
void keyer_update(void);
|
||||
void keyer_event(int, int, uint32_t);
|
||||
void keyer_event_left(void);
|
||||
void keyer_event_right(void);
|
||||
void clear_memory(void);
|
||||
static void set_keyer_out(int);
|
||||
static void* keyer_thread(void*);
|
||||
|
||||
/////
|
||||
|
||||
void keyer_update() {
|
||||
dot_delay = 1200 / cw_keyer_speed;
|
||||
|
@ -163,49 +170,42 @@ void keyer_update() {
|
|||
kdot = &kcwl;
|
||||
kdash = &kcwr;
|
||||
}
|
||||
|
||||
// need to actually dynamically set this at some point...
|
||||
cw_hangtime_msec = (int)(0.25f * 1000.0f);
|
||||
}
|
||||
|
||||
void keyer_event(int gpio, int level, uint32_t tick) {
|
||||
int state = (cw_active_state == 0) ? (level == 0) : (level != 0);
|
||||
int okdash = *kdash;
|
||||
int okdot = *kdot;
|
||||
int new_state;
|
||||
|
||||
if (gpio == LEFT_PADDLE_GPIO)
|
||||
if (gpio == left_paddle_gpio)
|
||||
kcwl = state;
|
||||
else // RIGHT_PADDLE_GPIO
|
||||
kcwr = state;
|
||||
|
||||
if (*kdash > okdash)
|
||||
last_pressed = DASH;
|
||||
else if (*kdot > okdot)
|
||||
last_pressed = DOT;
|
||||
else {
|
||||
new_state = kstate();
|
||||
last_pressed = new_state & prev_state;
|
||||
}
|
||||
|
||||
if (state || cw_keyer_mode == KEYER_STRAIGHT)
|
||||
if (state) // || cw_keyer_mode == KEYER_STRAIGHT)
|
||||
sem_post(&cw_event);
|
||||
}
|
||||
|
||||
// Added to support WiringPi, which uses a different type of callback.
|
||||
void keyer_event_left()
|
||||
{
|
||||
int level = digitalRead(LEFT_PADDLE_GPIO);
|
||||
keyer_event(LEFT_PADDLE_GPIO, level, 0);
|
||||
int level = digitalRead(left_paddle_gpio);
|
||||
keyer_event(left_paddle_gpio, level, 0);
|
||||
#if defined(DEBUG)
|
||||
printf("Left Paddle Pressed\n");
|
||||
sem_getvalue(&cw_event, &cw_event_value);
|
||||
fprintf(stdout, "left paddle pressed - %d\n", cw_event_value);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Added to support WiringPi, which uses a different type of callback.
|
||||
void keyer_event_right()
|
||||
{
|
||||
int level = digitalRead(RIGHT_PADDLE_GPIO);
|
||||
keyer_event(RIGHT_PADDLE_GPIO, level, 0);
|
||||
int level = digitalRead(right_paddle_gpio);
|
||||
keyer_event(right_paddle_gpio, level, 0);
|
||||
#if defined(DEBUG)
|
||||
printf("Right Paddle Pressed\n");
|
||||
sem_getvalue(&cw_event, &cw_event_value);
|
||||
fprintf(stdout, "right paddle pressed - %d\n", cw_event_value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -215,38 +215,62 @@ void clear_memory() {
|
|||
}
|
||||
|
||||
|
||||
static inline void set_keyer_out(int state) {
|
||||
// if (keyer_out != state) {
|
||||
static void set_keyer_out(int state) {
|
||||
if (state && tr_switch_gpio) {
|
||||
digitalWrite(tr_switch_gpio, 1);
|
||||
}
|
||||
keyer_out = state;
|
||||
// write(1, &buf[state], 1); // write output to stdout for Pi-HFIQ
|
||||
|
||||
// if (state)
|
||||
// beep_mute = 0;
|
||||
// else
|
||||
// beep_mute = 1;
|
||||
// }
|
||||
digitalWrite(keyer_out_gpio, keyer_out);
|
||||
}
|
||||
|
||||
static void* keyer_thread(void *arg) {
|
||||
struct timespec loop_delay;
|
||||
int interval = 1000000; // 1 ms
|
||||
int hangtime_elapsed = 0;
|
||||
|
||||
while(running) {
|
||||
while (running) {
|
||||
#if defined(DEBUG)
|
||||
sem_getvalue(&cw_event, &cw_event_value);
|
||||
fprintf(stdout, "waiting - %d\n", cw_event_value);
|
||||
#endif
|
||||
sem_wait(&cw_event);
|
||||
key_state = CHECK;
|
||||
|
||||
while (key_state != EXITLOOP) {
|
||||
if (keyer_out)
|
||||
hangtime_elapsed = 0;
|
||||
|
||||
switch(key_state) {
|
||||
|
||||
case HANGTIME:
|
||||
if (hangtime_elapsed >= cw_hangtime_msec) {
|
||||
if (tr_switch_gpio) {
|
||||
#if defined(DEBUG)
|
||||
sem_getvalue(&cw_event, &cw_event_value);
|
||||
fprintf(stdout, "hangtime complete, %d msec - %d\n", cw_hangtime_msec, cw_event_value);
|
||||
#endif
|
||||
digitalWrite(tr_switch_gpio, 0);
|
||||
key_state = EXITLOOP;
|
||||
}
|
||||
}
|
||||
// INTENTIONALLY FALLING THROUGH TO 'CHECK' STATE (no 'break')
|
||||
|
||||
case CHECK: // check for key press
|
||||
if (cw_keyer_mode == KEYER_STRAIGHT) { // Straight/External key or bug
|
||||
if (*kdash) { // send manual dashes
|
||||
if (!keyer_out) {
|
||||
set_keyer_out(1);
|
||||
key_state = EXITLOOP;
|
||||
key_state = HANGTIME; //EXITLOOP;
|
||||
}
|
||||
}
|
||||
else if (*kdot) // and automatic dots
|
||||
key_state = PREDOT;
|
||||
else {
|
||||
else if (key_state == HANGTIME) {
|
||||
if (keyer_out)
|
||||
set_keyer_out(0);
|
||||
} else {
|
||||
// NOTE: not working right
|
||||
//set_keyer_out(0);
|
||||
key_state = EXITLOOP;
|
||||
}
|
||||
}
|
||||
|
@ -255,16 +279,19 @@ static void* keyer_thread(void *arg) {
|
|||
key_state = PREDOT;
|
||||
else if (*kdash)
|
||||
key_state = PREDASH;
|
||||
else {
|
||||
set_keyer_out(0);
|
||||
else if (key_state != HANGTIME) {
|
||||
// Do we really need to do this? Aren't these covered in other states?
|
||||
//set_keyer_out(0);
|
||||
key_state = EXITLOOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PREDOT: // need to clear any pending dots or dashes
|
||||
clear_memory();
|
||||
key_state = SENDDOT;
|
||||
break;
|
||||
|
||||
case PREDASH:
|
||||
clear_memory();
|
||||
key_state = SENDDASH;
|
||||
|
@ -288,10 +315,6 @@ static void* keyer_thread(void *arg) {
|
|||
}
|
||||
|
||||
if (*kdash) { // set dash memory
|
||||
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||
if (last_pressed == DASH)
|
||||
dash_memory = 1;
|
||||
} else
|
||||
dash_memory = 1;
|
||||
}
|
||||
break;
|
||||
|
@ -314,10 +337,6 @@ static void* keyer_thread(void *arg) {
|
|||
}
|
||||
|
||||
if (*kdot) { // set dot memory
|
||||
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||
if (last_pressed == DOT)
|
||||
dot_memory = 1;
|
||||
} else
|
||||
dot_memory = 1;
|
||||
}
|
||||
break;
|
||||
|
@ -327,7 +346,7 @@ static void* keyer_thread(void *arg) {
|
|||
if (kdelay == dot_delay) {
|
||||
kdelay = 0;
|
||||
if(!*kdot && cw_keyer_mode == KEYER_STRAIGHT) // just return if in bug mode
|
||||
key_state = EXITLOOP;
|
||||
key_state = HANGTIME;
|
||||
else if (dash_memory) // dash has been set during the dot so service
|
||||
key_state = PREDASH;
|
||||
else key_state = DOTHELD; // dot is still active so service
|
||||
|
@ -335,10 +354,6 @@ static void* keyer_thread(void *arg) {
|
|||
else kdelay++;
|
||||
|
||||
if (*kdash) { // set dash memory
|
||||
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||
if (last_pressed == DASH)
|
||||
dash_memory = 1;
|
||||
} else
|
||||
dash_memory = 1;
|
||||
}
|
||||
break;
|
||||
|
@ -355,19 +370,13 @@ static void* keyer_thread(void *arg) {
|
|||
else kdelay++;
|
||||
|
||||
if (*kdot) { // set dot memory
|
||||
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||
if (last_pressed == DOT)
|
||||
dot_memory = 1;
|
||||
} else
|
||||
dot_memory = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// check if dot paddle is still held, if so repeat the dot. Else check if Letter space is required
|
||||
case DOTHELD:
|
||||
if ((cw_keyer_mode == KEYER_ULTIMATIC) && (last_pressed == DASH))
|
||||
key_state = PREDASH;
|
||||
else if (*kdot) // dot has been set during the dash so service
|
||||
if (*kdot) // dot has been set during the dash so service
|
||||
key_state = PREDOT;
|
||||
else if (*kdash) // has dash paddle been pressed
|
||||
key_state = PREDASH;
|
||||
|
@ -375,14 +384,12 @@ static void* keyer_thread(void *arg) {
|
|||
clear_memory();
|
||||
key_state = LETTERSPACE;
|
||||
}
|
||||
else key_state = EXITLOOP;
|
||||
else key_state = HANGTIME;
|
||||
break;
|
||||
|
||||
// check if dash paddle is still held, if so repeat the dash. Else check if Letter space is required
|
||||
case DASHHELD:
|
||||
if ((cw_keyer_mode == KEYER_ULTIMATIC) && (last_pressed == DOT))
|
||||
key_state = PREDOT;
|
||||
else if (*kdash) // dash has been set during the dot so service
|
||||
if (*kdash) // dash has been set during the dot so service
|
||||
key_state = PREDASH;
|
||||
else if (*kdot) // has dot paddle been pressed
|
||||
key_state = PREDOT;
|
||||
|
@ -390,7 +397,7 @@ static void* keyer_thread(void *arg) {
|
|||
clear_memory();
|
||||
key_state = LETTERSPACE;
|
||||
}
|
||||
else key_state = EXITLOOP;
|
||||
else key_state = HANGTIME;
|
||||
break;
|
||||
|
||||
// Add letter space (3 x dot delay) to end of character and check if a paddle is pressed during this time.
|
||||
|
@ -402,7 +409,7 @@ static void* keyer_thread(void *arg) {
|
|||
key_state = PREDOT;
|
||||
else if (dash_memory)
|
||||
key_state = PREDASH;
|
||||
else key_state = EXITLOOP; // no memories set so restart
|
||||
else key_state = HANGTIME; // no memories set so restart
|
||||
}
|
||||
else kdelay++;
|
||||
|
||||
|
@ -413,9 +420,12 @@ static void* keyer_thread(void *arg) {
|
|||
|
||||
default:
|
||||
key_state = EXITLOOP;
|
||||
|
||||
}
|
||||
|
||||
if (!keyer_out)
|
||||
hangtime_elapsed++;
|
||||
|
||||
if (key_state != EXITLOOP) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &loop_delay);
|
||||
loop_delay.tv_nsec += interval;
|
||||
while (loop_delay.tv_nsec >= NSEC_PER_SEC) {
|
||||
|
@ -425,29 +435,48 @@ static void* keyer_thread(void *arg) {
|
|||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int open_key_gpiokeyer(const char * name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sscanf(name, "gpio:%d,%d,%d,%d", &left_paddle_gpio, &right_paddle_gpio, &keyer_out_gpio, &tr_switch_gpio) < 4) {
|
||||
fprintf(stderr, "Insufficient parameters for GPIO Keyer: %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
fprintf(stdout, "GPIO Keyer selected:\n - left paddle GPIO: %d\n - right paddle GPIO: %d\n - keyer out GPIO: %d\n - T/R switch GPIO: %d\n",
|
||||
left_paddle_gpio, right_paddle_gpio, keyer_out_gpio, tr_switch_gpio);
|
||||
#endif
|
||||
|
||||
|
||||
if (wiringPiSetupGpio () < 0) {
|
||||
fprintf(stderr, "Unable to setup wiringPi: %s\n", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pinMode(RIGHT_PADDLE_GPIO, INPUT);
|
||||
pullUpDnControl(RIGHT_PADDLE_GPIO, PUD_UP);
|
||||
pinMode(right_paddle_gpio, INPUT);
|
||||
pullUpDnControl(right_paddle_gpio, PUD_UP);
|
||||
usleep(100000);
|
||||
wiringPiISR(RIGHT_PADDLE_GPIO, INT_EDGE_BOTH, keyer_event_right);
|
||||
wiringPiISR(right_paddle_gpio, INT_EDGE_BOTH, keyer_event_right);
|
||||
|
||||
pinMode(LEFT_PADDLE_GPIO, INPUT);
|
||||
pullUpDnControl(LEFT_PADDLE_GPIO, PUD_UP);
|
||||
pinMode(left_paddle_gpio, INPUT);
|
||||
pullUpDnControl(left_paddle_gpio, PUD_UP);
|
||||
usleep(100000);
|
||||
wiringPiISR(LEFT_PADDLE_GPIO, INT_EDGE_BOTH, keyer_event_left);
|
||||
wiringPiISR(left_paddle_gpio, INT_EDGE_BOTH, keyer_event_left);
|
||||
|
||||
pinMode(KEYER_OUT_GPIO, OUTPUT);
|
||||
digitalWrite(KEYER_OUT_GPIO, 0);
|
||||
if (keyer_out_gpio) {
|
||||
pinMode(keyer_out_gpio, OUTPUT);
|
||||
digitalWrite(keyer_out_gpio, 0);
|
||||
}
|
||||
|
||||
if (tr_switch_gpio) {
|
||||
pinMode(tr_switch_gpio, OUTPUT);
|
||||
digitalWrite(tr_switch_gpio, 0);
|
||||
}
|
||||
|
||||
keyer_update();
|
||||
|
||||
|
@ -473,23 +502,24 @@ void close_key_gpiokeyer(void)
|
|||
int is_key_down_gpiokeyer(void)
|
||||
{
|
||||
static int retval;
|
||||
// sem_wait(&cw_event);
|
||||
retval = keyer_out;
|
||||
// sem_post(&cw_event);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void quisk_set_gpio_keyer_mode(int mode)
|
||||
{
|
||||
fprintf(stderr, "MODE CHANGE\n");
|
||||
#if defined(DEBUG)
|
||||
fprintf(stdout, "MODE CHANGE\n");
|
||||
#endif
|
||||
if ((mode > -1) && (mode < NUM_KEYER_MODES))
|
||||
cw_keyer_mode = mode;
|
||||
}
|
||||
|
||||
|
||||
void quisk_set_gpio_keyer_speed(int wpm)
|
||||
{
|
||||
fprintf(stderr, "SPEED CHANGE\n");
|
||||
#if defined(DEBUG)
|
||||
fprintf(stdout, "SPEED CHANGE\n");
|
||||
#endif
|
||||
cw_keyer_speed = wpm;
|
||||
keyer_update();
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ int quisk_open_key(const char * name)
|
|||
ret = open_key_enet(name);
|
||||
}
|
||||
#if defined(ENABLE_GPIO_KEYER)
|
||||
else if (!strncmp(name, "GPIO", 4)){ // Raspberry Pi GPIO keyer
|
||||
else if (!strncmp(name, "gpio", 4)){ // Raspberry Pi GPIO keyer
|
||||
key_method = GpioKeyer;
|
||||
ret = open_key_gpiokeyer(name);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user