diff --git a/__init__.py b/__init__.py index 53ccd50..91e915f 100755 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -#Quisk version 4.1.52 +#Quisk version 4.1.52-upr1 diff --git a/gpiokeyer.c b/gpiokeyer.c index 2f7c2b2..52bc846 100644 --- a/gpiokeyer.c +++ b/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 #include @@ -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) { +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) { - keyer_out = state; -// write(1, &buf[state], 1); // write output to stdout for Pi-HFIQ - -// if (state) -// beep_mute = 0; -// else -// beep_mute = 1; -// } +static void set_keyer_out(int state) { + if (state && tr_switch_gpio) { + digitalWrite(tr_switch_gpio, 1); + } + keyer_out = state; + digitalWrite(keyer_out_gpio, keyer_out); } static void* keyer_thread(void *arg) { struct timespec loop_delay; int interval = 1000000; // 1 ms - - while(running) { + int hangtime_elapsed = 0; + + 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 CHECK: // check for key press + + 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 - set_keyer_out(1); - key_state = EXITLOOP; + if (!keyer_out) { + set_keyer_out(1); + key_state = HANGTIME; //EXITLOOP; + } } else if (*kdot) // and automatic dots key_state = PREDOT; - else { - set_keyer_out(0); + 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,11 +315,7 @@ 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; + dash_memory = 1; } break; @@ -314,11 +337,7 @@ 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; + 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,11 +354,7 @@ 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; + 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; + 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++; @@ -410,19 +417,23 @@ static void* keyer_thread(void *arg) { if (*kdot) dot_memory = 1; if (*kdash) dash_memory = 1; break; - + default: key_state = EXITLOOP; - } - clock_gettime(CLOCK_MONOTONIC, &loop_delay); - loop_delay.tv_nsec += interval; - while (loop_delay.tv_nsec >= NSEC_PER_SEC) { - loop_delay.tv_nsec -= NSEC_PER_SEC; - loop_delay.tv_sec++; + 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) { + loop_delay.tv_nsec -= NSEC_PER_SEC; + loop_delay.tv_sec++; + } + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL); } - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL); } } } @@ -431,23 +442,41 @@ 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(); } diff --git a/is_key_down.c b/is_key_down.c index df6c8a3..b955c28 100755 --- a/is_key_down.c +++ b/is_key_down.c @@ -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); }