* add Pi gpio PTT capability
This commit is contained in:
David Freese 2020-09-25 19:07:07 -05:00
parent 11a01f2773
commit c046bd5f16
14 changed files with 457 additions and 5 deletions

View file

@ -214,6 +214,7 @@ flrig_SOURCES += \
rigs/Xiegu-G90.cxx \
support/debug.cxx \
support/dialogs.cxx \
support/gpio_ptt.cxx \
support/ptt.cxx \
support/rig_io.cxx \
support/serial.cxx \
@ -246,6 +247,7 @@ EXTRA_DIST = \
config.h \
flrig_icon.cxx \
UI/ui_bitmaps.cxx \
UI/gpio.cxx \
UI/ui_wide.cxx \
UI/ui_small.cxx \
UI/ui_touch.cxx \
@ -256,6 +258,8 @@ EXTRA_DIST = \
UI/power_meter_setup.cxx \
include/cwio.h \
include/cwioUI.h \
include/gpio.h \
include/gpio_ptt.h \
include/morse.h \
include/debug.h \
include/dialogs.h \

171
src/UI/gpio.cxx Normal file
View file

@ -0,0 +1,171 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2020
// David Freese, W1HKJ
//
// This file is part of flrig.
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// flrig 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "gpio.h"
#include "gpio_ptt.h"
static const char *gpio_label[] = {
" 17 00 11",
" 18 01 12",
" 27 02 13",
" 22 03 15",
" 23 04 16",
" 24 05 18",
" 25 06 22",
" 4 07 7",
" 5 21 29",
" 6 22 31",
" 13 23 33",
" 19 24 35",
" 26 25 37",
" 12 26 32",
" 16 27 36",
" 20 28 38",
" 21 29 40"
};
static void show_pins()
{
printf("%05x | %05x\n", progStatus.enable_gpio, progStatus.gpio_on);
}
void cb_btn_enable_gpio(Fl_Check_Button* btn, void *val)
{
size_t n = (size_t)(val);
if (btn->value()) {
progStatus.enable_gpio |= (1 << n);
} else {
progStatus.enable_gpio &= ~(1 << n);
}
show_pins();
}
static void cb_btn_gpio_on(Fl_Check_Button* btn, void *val)
{
size_t n = (size_t)(val);
if (btn->value()) {
progStatus.gpio_on |= (1 << n);
} else {
progStatus.gpio_on &= ~(1 << n);
}
show_pins();
}
static void cb_cnt_gpio_pulse_width(Fl_Counter* o, void*)
{
progStatus.gpio_pulse_width = (int)o->value();
}
static void cb_btn_use_gpio(Fl_Check_Button* btn, void *)
{
if (btn->value()) {
progStatus.gpio_ptt = true;
open_gpio();
} else {
progStatus.gpio_ptt = false;
close_gpio();
}
}
Fl_Group *createGPIO(int X, int Y, int W, int H, const char *label)
{
tabGPIO = new Fl_Group(X, Y, W, H, label);
size_t w = (W - 20)/4;
size_t h = 18;
size_t hd = (H - 4)/ 11;
size_t y = Y + 2 + hd;
size_t col1 = X + 20;
size_t col2 = col1 + w;
size_t col3 = col2 + w;
size_t col4 = col3 + w;
Fl_Check_Button * btn_use_gpio = new Fl_Check_Button (col2 + w/2, Y + 2, w, h, "Use GPIO PTT");
btn_use_gpio->down_box(FL_DOWN_BOX);
btn_use_gpio->labelfont(FL_COURIER);
btn_use_gpio->labelsize(12);
btn_use_gpio->value(progStatus.gpio_ptt);
btn_use_gpio->callback((Fl_Callback*)cb_btn_use_gpio);
Fl_Box* bx1 = new Fl_Box(col1, y, w, h, " BCM GPIO Pin ON");
bx1->labelfont(FL_COURIER);
bx1->labelsize(12);
bx1->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE));
Fl_Box* bx3 = new Fl_Box(col3, y, w, h, " BCM GPIO Pin ON");
bx3->labelfont(FL_COURIER);
bx3->labelsize(12);
bx3->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE));
for (size_t n = 0; n < 8; n++) {
btn_enable_gpio[n] = new Fl_Check_Button(col1, y + hd * (n + 1), w, h, gpio_label[n]);
btn_enable_gpio[n]->tooltip(_("Select pin number"));
btn_enable_gpio[n]->down_box(FL_DOWN_BOX);
btn_enable_gpio[n]->labelfont(FL_COURIER);
btn_enable_gpio[n]->labelsize(12);
btn_enable_gpio[n]->callback((Fl_Callback*)cb_btn_enable_gpio, (void *)n);
btn_enable_gpio[n]->value((progStatus.enable_gpio >> n)& 0x01);
}
for (size_t n = 8; n < 17; n++) {
btn_enable_gpio[n] = new Fl_Check_Button(col3, y + hd * (n - 7), w, h, gpio_label[n]);
btn_enable_gpio[n]->tooltip(_("Select pin number"));
btn_enable_gpio[n]->down_box(FL_DOWN_BOX);
btn_enable_gpio[n]->labelfont(FL_COURIER);
btn_enable_gpio[n]->labelsize(12);
btn_enable_gpio[n]->callback((Fl_Callback*)cb_btn_enable_gpio, (void *)n);
btn_enable_gpio[n]->value((progStatus.enable_gpio >> n)& 0x01);
}
for (size_t n = 0; n < 8; n++) {
btn_gpio_on[n] = new Fl_Check_Button(col2, y + hd * (n + 1), w, h, "");
btn_gpio_on[n]->tooltip(_("Select PTT on state"));
btn_gpio_on[n]->down_box(FL_DOWN_BOX);
btn_gpio_on[n]->labelfont(FL_COURIER);
btn_gpio_on[n]->labelsize(12);
btn_gpio_on[n]->callback((Fl_Callback*)cb_btn_gpio_on, (void *)n);
btn_gpio_on[n]->value((progStatus.gpio_on >> n) & 0x01);
}
for (size_t n = 8; n < 17; n++) {
btn_gpio_on[n] = new Fl_Check_Button(col4, y + hd * (n - 7), w, h, "");
btn_gpio_on[n]->tooltip(_("Select PTT on state"));
btn_gpio_on[n]->down_box(FL_DOWN_BOX);
btn_gpio_on[n]->labelfont(FL_COURIER);
btn_gpio_on[n]->labelsize(12);
btn_gpio_on[n]->callback((Fl_Callback*)cb_btn_gpio_on, (void *)n);
btn_gpio_on[n]->value((progStatus.gpio_on >> n) & 0x01);
}
cnt_gpio_pulse_width = new Fl_Counter(col1, y + hd * 9, 80, 20, "Pulse width (msec)");
cnt_gpio_pulse_width->tooltip(_("Set >0 if pulsed PTT used"));
cnt_gpio_pulse_width->type(1);
cnt_gpio_pulse_width->labelfont(FL_COURIER);
cnt_gpio_pulse_width->labelsize(12);
cnt_gpio_pulse_width->minimum(0);
cnt_gpio_pulse_width->maximum(50);
cnt_gpio_pulse_width->step(1);
cnt_gpio_pulse_width->callback((Fl_Callback*)cb_cnt_gpio_pulse_width);
cnt_gpio_pulse_width->align(Fl_Align(FL_ALIGN_RIGHT));
cnt_gpio_pulse_width->value(progStatus.gpio_pulse_width);
tabGPIO->end();
return tabGPIO;
}

View file

@ -430,6 +430,10 @@ static void cb_mnuPTT(Fl_Menu_*, void*) {
open_ptt_tab();
}
static void cb_mnuGPIO(Fl_Menu_*, void*) {
open_gpio_tab();
}
static void cb_mnuAUX(Fl_Menu_*, void *) {
open_aux_tab();
}

View file

@ -29,6 +29,7 @@ Fl_Menu_Item menu_small_menu[] = {
{_("Transceiver"), 0, (Fl_Callback*)cb_mnuConfigXcvr, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("tcpip"), 0, (Fl_Callback*)cb_mnuTCPIP, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("PTT"), 0, (Fl_Callback*)cb_mnuPTT, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("GPIO"), 0, (Fl_Callback*)cb_mnuGPIO, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("AUX"), 0, (Fl_Callback*)cb_mnuAUX, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Server"), 0, (Fl_Callback*)cb_mnuSERVER, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Polling"), 0, (Fl_Callback*)cb_Polling, 0, 128, FL_NORMAL_LABEL, 0, 14, 0},

View file

@ -38,6 +38,7 @@ Fl_Menu_Item touch_menu[] = {
{_("Transceiver"), 0, (Fl_Callback*)cb_mnuConfigXcvr, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("tcpip"), 0, (Fl_Callback*)cb_mnuTCPIP, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("PTT"), 0, (Fl_Callback*)cb_mnuPTT, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("GPIO"), 0, (Fl_Callback*)cb_mnuGPIO, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("AUX"), 0, (Fl_Callback*)cb_mnuAUX, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Server"), 0, (Fl_Callback*)cb_mnuSERVER, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Polling"), 0, (Fl_Callback*)cb_Polling, 0, 128, FL_NORMAL_LABEL, 0, 14, 0},

View file

@ -33,6 +33,7 @@ Fl_Menu_Item menu_wide_menu[] = {
{_("Transceiver"), 0, (Fl_Callback*)cb_mnuConfigXcvr, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("tcpip"), 0, (Fl_Callback*)cb_mnuTCPIP, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("PTT"), 0, (Fl_Callback*)cb_mnuPTT, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("GPIO"), 0, (Fl_Callback*)cb_mnuGPIO, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("AUX"), 0, (Fl_Callback*)cb_mnuAUX, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Server"), 0, (Fl_Callback*)cb_mnuSERVER, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{_("Polling"), 0, (Fl_Callback*)cb_Polling, 0, 128, FL_NORMAL_LABEL, 0, 14, 0},

36
src/include/gpio.h Normal file
View file

@ -0,0 +1,36 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2020
// David Freese, W1HKJ
//
// This file is part of flrig.
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// flrig 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#ifndef GPIO_H
#define GPIO_H
#include <FL/Fl.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Counter.H>
extern Fl_Check_Button *btn_enable_gpio[17];
extern Fl_Check_Button *btn_gpio_on[17];
extern Fl_Counter *cnt_gpio_pulse_width;
extern Fl_Group *createGPIO(int X, int Y, int W, int H, const char *label);
#endif

34
src/include/gpio_ptt.h Normal file
View file

@ -0,0 +1,34 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2020
// David Freese, W1HKJ
//
// This file is part of flrig.
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// flrig 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#ifndef _GPIO_PTT_H
#define _GPIO_PTT_H
#include <string>
#include "status.h"
extern void gpioEXEC(std::string execstr);
extern void export_gpio(int bcm);
extern void unexport_gpio(int bcm);
extern void open_gpio(void);
extern void close_gpio(void);
extern void set_gpio(bool ptt);
#endif

View file

@ -417,6 +417,12 @@ struct status {
Fl_Font memfontnbr;
int memfontsize;
// gpio parameters
bool gpio_ptt;
int enable_gpio;
int gpio_on;
int gpio_pulse_width;
// cwio parameters
int cwioWPM;
int cwioKEYLINE;

View file

@ -240,6 +240,7 @@ extern void show_controls();
extern void open_xmlrpc_tab();
extern void open_tcpip_tab();
extern void open_ptt_tab();
extern void open_gpio_tab();
extern void open_aux_tab();
extern void open_server_tab();

View file

@ -443,6 +443,11 @@ void open_ptt_tab()
select_tab(_("PTT"));
}
void open_gpio_tab()
{
select_tab(_("GPIO"));
}
void open_aux_tab()
{
select_tab(_("Aux"));

166
src/support/gpio_ptt.cxx Normal file
View file

@ -0,0 +1,166 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2020
// David Freese, W1HKJ
//
// This file is part of flrig.
//
// flrig is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// flrig 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <iostream>
#include "gpio_ptt.h"
//-------------------- gpio port PTT --------------------//
#ifndef __MINGW32__
void gpioEXEC(std::string execstr)
{
int pfd[2];
if (pipe(pfd) == -1) {
LOG_PERROR("pipe");
return;
}
pid_t pid;
switch (pid = fork()) {
case -1:
LOG_PERROR("fork");
return;
case 0: // child
close(pfd[0]);
if (dup2(pfd[1], STDOUT_FILENO) != STDOUT_FILENO) {
LOG_PERROR("dup2");
exit(EXIT_FAILURE);
}
close(pfd[1]);
execl("/bin/sh", "sh", "-c", execstr.c_str(), (char *)NULL);
perror("execl");
exit(EXIT_FAILURE);
}
// parent
close(pfd[1]);
}
#else // !__MINGW32__
void gpioEXEC(std::string execstr)
{
char* cmd = strdup(execstr.c_str());
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
LOG_ERROR("CreateProcess failed with error code %ld", GetLastError());
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
free(cmd);
}
#endif // !__MINGW32__
static const char *gpio_name[] = {
"17", "18", "27", "22", "23",
"24", "25", "4", "5", "6",
"13", "19", "26", "12", "16",
"20", "21"};
void export_gpio(int bcm)
{
if (bcm < 0 || bcm > 16) return;
string exec_str = "gpio export ";
exec_str.append(gpio_name[bcm]).append(" out");
gpioEXEC(exec_str);
LOG_INFO("%s", exec_str.c_str());
}
void unexport_gpio(int bcm)
{
if (bcm < 0 || bcm > 16) return;
string exec_str = "gpio unexport ";
exec_str.append(gpio_name[bcm]);
gpioEXEC(exec_str);
LOG_INFO("%s", exec_str.c_str());
}
void open_gpio(void)
{
bool enabled = false;
for (int i = 0; i < 17; i++) {
enabled = (progStatus.enable_gpio >> i) & 0x01;
if (enabled) export_gpio(i);
}
}
void close_gpio(void)
{
bool enabled = false;
for (int i = 0; i < 17; i++) {
enabled = (progStatus.enable_gpio >> i) & 0x01;
if (enabled) unexport_gpio(i);
}
}
void set_gpio(bool ptt)
{
#define VALUE_MAX 30
static const char s_values_str[] = "01";
string portname = "/sys/class/gpio/gpio";
string ctrlport;
bool enabled = false;
int val = 0;
int fd;
for (int i = 0; i < 17; i++) {
enabled = (progStatus.enable_gpio >> i) & 0x01;
if (enabled) {
val = (progStatus.gpio_on >> i) & 0x01;
ctrlport = portname;
ctrlport.append(gpio_name[i]);
ctrlport.append("/value");
fd = fl_open(ctrlport.c_str(), O_WRONLY);
bool ok = false;
if (fd == -1) {
LOG_ERROR("Failed to open gpio (%s) for writing!", ctrlport.c_str());
} else {
if (progStatus.gpio_pulse_width == 0) {
if (ptt) { if (val == 1) val = 1; else val = 0;}
if (!ptt) { if (val == 1) val = 0; else val = 1;}
if (write(fd, &s_values_str[val], 1) == 1)
ok = true;
} else {
if (write(fd, &s_values_str[val], 1) == 1) {
MilliSleep(progStatus.gpio_pulse_width);
if (write(fd, &s_values_str[val == 0 ? 1 : 0], 1) == 1)
ok = true;
}
}
if (ok)
LOG_INFO("Set GPIO ptt on %s %s%s",
ctrlport.c_str(),
(progStatus.gpio_pulse_width > 0) ?
"pulsed " : "",
(val == 1 ? "HIGH" : "LOW")
);
else
LOG_ERROR("Failed to write value!");
close(fd);
}
}
}
}

View file

@ -35,6 +35,8 @@
#include "rig.h"
#include "support.h"
#include "gpio_ptt.h"
using namespace std;
// used for transceivers with a single vfo, called only by rigPTT
@ -72,13 +74,17 @@ void rigPTT(bool on)
return;
}
// PTT priority: CAT; serial; separate serial; GPIO
if (progStatus.comm_catptt) {
selrig->set_PTT_control(on);
} else if (progStatus.comm_dtrptt || progStatus.comm_rtsptt)
} else if (progStatus.comm_dtrptt || progStatus.comm_rtsptt) {
RigSerial->SetPTT(on);
else if (SepSerial->IsOpen() && (progStatus.sep_dtrptt || progStatus.sep_rtsptt) )
} else if (SepSerial->IsOpen() && (progStatus.sep_dtrptt || progStatus.sep_rtsptt) ) {
SepSerial->SetPTT(on);
else
LOG_ERROR("No PTT i/o connected");
} else if (progStatus.gpio_ptt) {
set_gpio(on);
} else {
LOG_DEBUG("No PTT i/o connected");
}
}

View file

@ -433,6 +433,12 @@ status progStatus = {
4, // Fl_Font memfontnbr;
14, // int memfontsize;
// gpio parameters
false, // bool gpio_ptt;
0, // int enable_gpio;
0, // int gpio_on;
0, //int gpio_pulse_width;
// cwio parameters
20, // int cwioWPM;
2, // int cwioKEYLINE; 1 == RTS, 2 == DTR
@ -903,6 +909,11 @@ void status::saveLastState()
spref.set("memfontnbr", memfontnbr);
spref.set("memfontsize", memfontsize);
spref.set("gpio_ptt", gpio_ptt);
spref.set("enable_gpio", enable_gpio);
spref.set("gpio_on", gpio_on);
spref.set("gpio_pulse_width", gpio_pulse_width);
spref.set("cwioWPM", cwioWPM);
spref.set("cwio_comp", cwio_comp);
spref.set("cwioKEYLINE", cwioKEYLINE);
@ -1452,6 +1463,11 @@ bool status::loadXcvrState(string xcvr)
spref.get("memfontnbr", memfontnbr, memfontnbr);
spref.get("memfontsize", memfontsize, memfontsize);
if (spref.get("gpio_ptt", i, i)) gpio_ptt = i;
spref.get("enable_gpio", enable_gpio, enable_gpio);
spref.get("gpio_on", gpio_on, gpio_on);
spref.get("gpio_pulse_width", gpio_pulse_width, gpio_pulse_width);
spref.get("cwioWPM", cwioWPM, cwioWPM);
spref.get("cwio_comp", cwio_comp, cwio_comp);
spref.get("cwioKEYLINE", cwioKEYLINE, cwioKEYLINE);