Successfully merged in N1GP keyer code! It appears to transmit correctly! No controls implemented yet (i.e. can't modify keyer parameters). Also, I'm not sure about the threading/semaphores aspect.
I think there is some further work to be done there to be technically correct.
This commit is contained in:
parent
91aa2689ce
commit
4b1207c31f
482
gpiokeyer.c
Normal file
482
gpiokeyer.c
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
// NEED TO FIGURE OUT A SIMPLER WAY TO DO THIS... THIS IS JUST TO GET ENABLE_GPIO_KEYER!
|
||||||
|
#include <Python.h> // used by quisk.h
|
||||||
|
#include <complex.h> // Used by quisk.h
|
||||||
|
#include "quisk.h"
|
||||||
|
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
|
||||||
|
// gcc iambic.c -o iambic -l pigpio -lpthread
|
||||||
|
// or make, to run sudo ./iambic [options]
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
10/12/2016, Rick Koch / N1GP, I adapted Phil's verilog code from
|
||||||
|
the openHPSDR Hermes iambic.v implementation to build
|
||||||
|
and run on a raspberry PI 3.
|
||||||
|
|
||||||
|
1/7/2017, N1GP, adapted to work with Jack Audio, much better timing.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
Copywrite (C) Phil Harman VK6PH May 2014
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The code implements an Iambic CW keyer. The following features are supported:
|
||||||
|
|
||||||
|
* Variable speed control from 1 to 60 WPM
|
||||||
|
* Dot and Dash memory
|
||||||
|
* Straight, Bug, Iambic Mode A or B Modes
|
||||||
|
* Variable character weighting
|
||||||
|
* Automatic Letter spacing
|
||||||
|
* Paddle swap
|
||||||
|
|
||||||
|
Dot and Dash memory works by registering an alternative paddle closure whilst a paddle is pressed.
|
||||||
|
The alternate paddle closure can occur at any time during a paddle closure and is not limited to being
|
||||||
|
half way through the current dot or dash. This feature could be added if required.
|
||||||
|
|
||||||
|
In Straight mode, closing the DASH paddle will result in the output following the input state. This enables a
|
||||||
|
straight morse key or external Iambic keyer to be connected.
|
||||||
|
|
||||||
|
In Bug mode closing the dot paddle will send repeated dots.
|
||||||
|
|
||||||
|
The difference between Iambic Mode A and B lies in what the keyer does when both paddles are released. In Mode A the
|
||||||
|
keyer completes the element being sent when both paddles are released. In Mode B the keyer sends an additional
|
||||||
|
element opposite to the one being sent when the paddles are released.
|
||||||
|
|
||||||
|
This only effects letters and characters like C, period or AR.
|
||||||
|
|
||||||
|
Automatic Letter Space works as follows: When enabled, if you pause for more than one dot time between a dot or dash
|
||||||
|
the keyer will interpret this as a letter-space and will not send the next dot or dash until the letter-space time has been met.
|
||||||
|
The normal letter-space is 3 dot periods. The keyer has a paddle event memory so that you can enter dots or dashes during the
|
||||||
|
inter-letter space and the keyer will send them as they were entered.
|
||||||
|
|
||||||
|
Speed calculation - Using standard PARIS timing, dot_period(mS) = 1200/WPM
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <wiringPi.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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 NSEC_PER_SEC (1000000000)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CHECK = 0,
|
||||||
|
PREDOT,
|
||||||
|
PREDASH,
|
||||||
|
SENDDOT,
|
||||||
|
SENDDASH,
|
||||||
|
DOTDELAY,
|
||||||
|
DASHDELAY,
|
||||||
|
DOTHELD,
|
||||||
|
DASHHELD,
|
||||||
|
LETTERSPACE,
|
||||||
|
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 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_spacing = 0;
|
||||||
|
static int cw_active_state = 0;
|
||||||
|
static sem_t cw_event;
|
||||||
|
|
||||||
|
static int last_pressed = NONE;
|
||||||
|
|
||||||
|
static int running, keyer_out = 0;
|
||||||
|
|
||||||
|
static inline int kstate() {
|
||||||
|
return (*kdash<<1)&(*kdot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int prev_state = 0;
|
||||||
|
|
||||||
|
void keyer_update() {
|
||||||
|
dot_delay = 1200 / cw_keyer_speed;
|
||||||
|
// will be 3 * dot length at standard weight
|
||||||
|
dash_delay = (dot_delay * 3 * cw_keyer_weight) / 50;
|
||||||
|
|
||||||
|
if (cw_keys_reversed) {
|
||||||
|
kdot = &kcwr;
|
||||||
|
kdash = &kcwl;
|
||||||
|
} else {
|
||||||
|
kdot = &kcwl;
|
||||||
|
kdash = &kcwr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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);
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("Left Paddle Pressed\n");
|
||||||
|
#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);
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("Right Paddle Pressed\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_memory() {
|
||||||
|
dot_memory = 0;
|
||||||
|
dash_memory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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* keyer_thread(void *arg) {
|
||||||
|
struct timespec loop_delay;
|
||||||
|
int interval = 1000000; // 1 ms
|
||||||
|
|
||||||
|
while(running) {
|
||||||
|
sem_wait(&cw_event);
|
||||||
|
key_state = CHECK;
|
||||||
|
|
||||||
|
while (key_state != EXITLOOP) {
|
||||||
|
switch(key_state) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else if (*kdot) // and automatic dots
|
||||||
|
key_state = PREDOT;
|
||||||
|
else {
|
||||||
|
set_keyer_out(0);
|
||||||
|
key_state = EXITLOOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*kdot)
|
||||||
|
key_state = PREDOT;
|
||||||
|
else if (*kdash)
|
||||||
|
key_state = PREDASH;
|
||||||
|
else {
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// dot paddle pressed so set keyer_out high for time dependant on speed
|
||||||
|
// also check if dash paddle is pressed during this time
|
||||||
|
case SENDDOT:
|
||||||
|
set_keyer_out(1);
|
||||||
|
if (kdelay == dot_delay) {
|
||||||
|
kdelay = 0;
|
||||||
|
set_keyer_out(0);
|
||||||
|
key_state = DOTDELAY; // add inter-character spacing of one dot length
|
||||||
|
}
|
||||||
|
else kdelay++;
|
||||||
|
|
||||||
|
// if Mode A and both paddels are relesed then clear dash memory
|
||||||
|
if (cw_keyer_mode == KEYER_MODE_A) {
|
||||||
|
if (!*kdot & !*kdash)
|
||||||
|
dash_memory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*kdash) { // set dash memory
|
||||||
|
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||||
|
if (last_pressed == DASH)
|
||||||
|
dash_memory = 1;
|
||||||
|
} else
|
||||||
|
dash_memory = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// dash paddle pressed so set keyer_out high for time dependant on 3 x dot delay and weight
|
||||||
|
// also check if dot paddle is pressed during this time
|
||||||
|
case SENDDASH:
|
||||||
|
set_keyer_out(1);
|
||||||
|
if (kdelay == dash_delay) {
|
||||||
|
kdelay = 0;
|
||||||
|
set_keyer_out(0);
|
||||||
|
key_state = DASHDELAY; // add inter-character spacing of one dot length
|
||||||
|
}
|
||||||
|
else kdelay++;
|
||||||
|
|
||||||
|
// if Mode A and both padles are relesed then clear dot memory
|
||||||
|
if (cw_keyer_mode == KEYER_MODE_A) {
|
||||||
|
if (!*kdot & !*kdash)
|
||||||
|
dot_memory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*kdot) { // set dot memory
|
||||||
|
if (cw_keyer_mode == KEYER_ULTIMATIC) {
|
||||||
|
if (last_pressed == DOT)
|
||||||
|
dot_memory = 1;
|
||||||
|
} else
|
||||||
|
dot_memory = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// add dot delay at end of the dot and check for dash memory, then check if paddle still held
|
||||||
|
case DOTDELAY:
|
||||||
|
if (kdelay == dot_delay) {
|
||||||
|
kdelay = 0;
|
||||||
|
if(!*kdot && cw_keyer_mode == KEYER_STRAIGHT) // just return if in bug mode
|
||||||
|
key_state = EXITLOOP;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
// add dot delay at end of the dash and check for dot memory, then check if paddle still held
|
||||||
|
case DASHDELAY:
|
||||||
|
if (kdelay == dot_delay) {
|
||||||
|
kdelay = 0;
|
||||||
|
|
||||||
|
if (dot_memory) // dot has been set during the dash so service
|
||||||
|
key_state = PREDOT;
|
||||||
|
else key_state = DASHHELD; // dash is still active so service
|
||||||
|
}
|
||||||
|
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
|
||||||
|
key_state = PREDOT;
|
||||||
|
else if (*kdash) // has dash paddle been pressed
|
||||||
|
key_state = PREDASH;
|
||||||
|
else if (cw_keyer_spacing) { // Letter space enabled so clear any pending dots or dashes
|
||||||
|
clear_memory();
|
||||||
|
key_state = LETTERSPACE;
|
||||||
|
}
|
||||||
|
else key_state = EXITLOOP;
|
||||||
|
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
|
||||||
|
key_state = PREDASH;
|
||||||
|
else if (*kdot) // has dot paddle been pressed
|
||||||
|
key_state = PREDOT;
|
||||||
|
else if (cw_keyer_spacing) { // Letter space enabled so clear any pending dots or dashes
|
||||||
|
clear_memory();
|
||||||
|
key_state = LETTERSPACE;
|
||||||
|
}
|
||||||
|
else key_state = EXITLOOP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Add letter space (3 x dot delay) to end of character and check if a paddle is pressed during this time.
|
||||||
|
// Actually add 2 x dot_delay since we already have a dot delay at the end of the character.
|
||||||
|
case LETTERSPACE:
|
||||||
|
if (kdelay == 2 * dot_delay) {
|
||||||
|
kdelay = 0;
|
||||||
|
if (dot_memory) // check if a dot or dash paddle was pressed during the delay.
|
||||||
|
key_state = PREDOT;
|
||||||
|
else if (dash_memory)
|
||||||
|
key_state = PREDASH;
|
||||||
|
else key_state = EXITLOOP; // no memories set so restart
|
||||||
|
}
|
||||||
|
else kdelay++;
|
||||||
|
|
||||||
|
// save any key presses during the letter space delay
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_key_gpiokeyer(const char * name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
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);
|
||||||
|
usleep(100000);
|
||||||
|
wiringPiISR(RIGHT_PADDLE_GPIO, INT_EDGE_BOTH, keyer_event_right);
|
||||||
|
|
||||||
|
pinMode(LEFT_PADDLE_GPIO, INPUT);
|
||||||
|
pullUpDnControl(LEFT_PADDLE_GPIO, PUD_UP);
|
||||||
|
usleep(100000);
|
||||||
|
wiringPiISR(LEFT_PADDLE_GPIO, INT_EDGE_BOTH, keyer_event_left);
|
||||||
|
|
||||||
|
pinMode(KEYER_OUT_GPIO, OUTPUT);
|
||||||
|
digitalWrite(KEYER_OUT_GPIO, 0);
|
||||||
|
|
||||||
|
keyer_update();
|
||||||
|
|
||||||
|
i = sem_init(&cw_event, 0, 0);
|
||||||
|
running = 1;
|
||||||
|
i |= pthread_create(&keyer_thread_id, NULL, keyer_thread, NULL);
|
||||||
|
if(i < 0) {
|
||||||
|
fprintf(stderr,"pthread_create for keyer_thread failed %d\n", i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_key_gpiokeyer(void)
|
||||||
|
{
|
||||||
|
running = 0;
|
||||||
|
sem_post(&cw_event);
|
||||||
|
pthread_join(keyer_thread_id, 0);
|
||||||
|
sem_destroy(&cw_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_key_down_gpiokeyer(void)
|
||||||
|
{
|
||||||
|
static int retval;
|
||||||
|
// sem_wait(&cw_event);
|
||||||
|
retval = keyer_out;
|
||||||
|
// sem_post(&cw_event);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -59,12 +59,20 @@ static void close_key_enet(void);
|
|||||||
static int is_key_down_pport(void);
|
static int is_key_down_pport(void);
|
||||||
static int is_key_down_serport(void);
|
static int is_key_down_serport(void);
|
||||||
static int is_key_down_enet(void);
|
static int is_key_down_enet(void);
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
int open_key_gpiokeyer(const char * name);
|
||||||
|
void close_key_gpiokeyer(void);
|
||||||
|
int is_key_down_gpiokeyer(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
static enum { // The key access method
|
static enum { // The key access method
|
||||||
None, // Return the internal state; default key is always up
|
None, // Return the internal state; default key is always up
|
||||||
ParPort, // Use the parallel port
|
ParPort, // Use the parallel port
|
||||||
SerPort, // Use the serial port
|
SerPort, // Use the serial port
|
||||||
Udp // Use UDP Ethernet
|
Udp // Use UDP Ethernet
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
, GpioKeyer // Use Raspberry Pi GPIO keyer based on N1GP code
|
||||||
|
#endif
|
||||||
} key_method = None;
|
} key_method = None;
|
||||||
|
|
||||||
static int fd = -1; // File descriptor to read the parallel or serial port
|
static int fd = -1; // File descriptor to read the parallel or serial port
|
||||||
@ -91,6 +99,12 @@ int quisk_open_key(const char * name)
|
|||||||
key_method = Udp;
|
key_method = Udp;
|
||||||
ret = open_key_enet(name);
|
ret = open_key_enet(name);
|
||||||
}
|
}
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
else if (!strncmp(name, "GPIO", 4)){ // Raspberry Pi GPIO keyer
|
||||||
|
key_method = GpioKeyer;
|
||||||
|
ret = open_key_gpiokeyer(name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else {
|
else {
|
||||||
ret = 5;
|
ret = 5;
|
||||||
}
|
}
|
||||||
@ -111,6 +125,11 @@ void quisk_close_key(void)
|
|||||||
case Udp:
|
case Udp:
|
||||||
close_key_enet();
|
close_key_enet();
|
||||||
break;
|
break;
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
case GpioKeyer:
|
||||||
|
close_key_gpiokeyer();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -126,6 +145,10 @@ int quisk_is_key_down(void)
|
|||||||
return is_key_down_pport();
|
return is_key_down_pport();
|
||||||
case Udp:
|
case Udp:
|
||||||
return is_key_down_enet();
|
return is_key_down_enet();
|
||||||
|
#if defined(ENABLE_GPIO_KEYER)
|
||||||
|
case GpioKeyer:
|
||||||
|
return is_key_down_gpiokeyer();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -320,4 +343,5 @@ static int is_key_down_serport(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
1
quisk.h
1
quisk.h
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#define DEBUG_IO 0
|
#define DEBUG_IO 0
|
||||||
#define DEBUG_MIC 0
|
#define DEBUG_MIC 0
|
||||||
|
#define ENABLE_GPIO_KEYER 1
|
||||||
|
|
||||||
// Sound parameters
|
// Sound parameters
|
||||||
//
|
//
|
||||||
|
4
setup.py
4
setup.py
@ -31,10 +31,10 @@ if sys.platform != "win32":
|
|||||||
print ("please install the package libpulse-dev")
|
print ("please install the package libpulse-dev")
|
||||||
|
|
||||||
module1 = Extension ('quisk._quisk',
|
module1 = Extension ('quisk._quisk',
|
||||||
libraries = ['asound', 'portaudio', 'pulse', 'fftw3', 'm'],
|
libraries = ['asound', 'portaudio', 'pulse', 'fftw3', 'm', 'pthread', 'rt', 'wiringPi'],
|
||||||
sources = ['quisk.c', 'sound.c', 'sound_alsa.c', 'sound_portaudio.c', 'sound_pulseaudio.c',
|
sources = ['quisk.c', 'sound.c', 'sound_alsa.c', 'sound_portaudio.c', 'sound_pulseaudio.c',
|
||||||
'is_key_down.c', 'microphone.c', 'utility.c',
|
'is_key_down.c', 'microphone.c', 'utility.c',
|
||||||
'filter.c', 'extdemod.c', 'freedv.c'],
|
'filter.c', 'extdemod.c', 'freedv.c', 'gpiokeyer.c'],
|
||||||
)
|
)
|
||||||
|
|
||||||
module2 = Extension ('quisk.sdriqpkg.sdriq',
|
module2 = Extension ('quisk.sdriqpkg.sdriq',
|
||||||
|
Loading…
Reference in New Issue
Block a user