diff --git a/99-direwolf-cmedia.rules b/99-direwolf-cmedia.rules
new file mode 100644
index 0000000..587f616
--- /dev/null
+++ b/99-direwolf-cmedia.rules
@@ -0,0 +1,30 @@
+# Normally, all of /dev/hidraw* are accessible only by root.
+#
+# $ ls -l /dev/hidraw*
+# crw------- 1 root root 247, 0 Sep 24 09:40 /dev/hidraw0
+#
+# An ordinary user, trying to acccess it will be denied.
+#
+# Unnecessarily running applications as root is generally a bad idea because it makes it too easy
+# to accidentally trash your system. We need to relax the restrictions so ordinary users can use these devices.
+#
+# If all went well with installation, the /etc/udev/rules.d directory should contain a file called
+# 99-direwolf-cmedia.rules containing:
+#
+
+SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d8c", GROUP="audio", MODE="0660"
+
+#
+# I used the "audio" group, mimicking the permissions on the sound side of the device.
+#
+# $ ls -l /dev/snd/pcm*
+# crw-rw----+ 1 root audio 116, 16 Sep 24 09:40 /dev/snd/pcmC0D0p
+# crw-rw----+ 1 root audio 116, 17 Sep 24 09:40 /dev/snd/pcmC0D1p
+#
+# You should see something similar to this where someone in the "audio" group has read-write access.
+#
+# $ ls -l /dev/hidraw*
+# crw-rw---- 1 root audio 247, 0 Oct 6 19:24 /dev/hidraw0
+#
+# Read the User Guide and run the "cm108" application for more information.
+#
diff --git a/CHANGES.md b/CHANGES.md
index 2f95bc4..dbaf01d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,6 +11,8 @@ This is a snapshot of ongoing development towards version of 1.5. Some features
- KISS "Set Hardware" command to report transmit queue length.
+- PTT using GPIO pin of CM108/CM119 (e.g. DMK URI, RB-USB RIM)
+
### Bugs Fixed: ###
diff --git a/Makefile.linux b/Makefile.linux
index a81542f..aa5a90b 100644
--- a/Makefile.linux
+++ b/Makefile.linux
@@ -4,7 +4,7 @@
-APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc kissutil
+APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc kissutil cm108
all : $(APPS) direwolf.desktop direwolf.conf
@echo " "
@@ -292,6 +292,21 @@ LDFLAGS += -lhamlib
endif
+# If, for some reason, can obtain the libudev-dev package, or
+# don't want to install it, comment out the next 3 lines.
+
+ifeq ($(wildcard /usr/include/libudev.h),)
+$(error /usr/include/libudev.h does not exist. Install it with "sudo apt-get install libudev-dev" or "sudo yum install libudev-dev" )
+endif
+
+
+# Enable cm108 PTT support if libudev header file is present.
+
+enable_cm108 := $(wildcard /usr/include/libudev.h)
+ifneq ($(enable_cm108),)
+CFLAGS += -DUSE_CM108
+LDFLAGS += -ludev
+endif
# Name of current directory.
@@ -312,7 +327,7 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_psk.o dem
gen_tone.o audio.o audio_stats.o digipeater.o cdigipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
ptt.o beacon.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.o \
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o waypoint.o serial_port.o log.o telemetry.o \
- dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o mheard.o ax25_link.o \
+ dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o mheard.o ax25_link.o cm108.o \
misc.a geotranz.a
$(CC) -o $@ $^ $(LDFLAGS)
@echo " "
@@ -325,6 +340,11 @@ ifneq ($(enable_hamlib),)
@echo "\t>\tThis includes support for hamlib."
else
@echo "\t>\tThis does NOT include support for hamlib."
+endif
+ifneq ($(enable_cm108),)
+ @echo "\t>\tThis includes support for CM108/CM119 PTT."
+else
+ @echo "\t>\tThis does NOT include support for CM108/CM119 PTT."
endif
@echo " "
@@ -435,6 +455,12 @@ kissutil : kissutil.c kiss_frame.c ax25_pad.o fcs_calc.o textcolor.o serial_port
$(CC) $(CFLAGS) -g -DKISSUTIL -o $@ $^ $(LDFLAGS)
+# List USB audio adapters than can use GPIO for PTT.
+
+cm108 : cm108.c textcolor.o misc.a
+ $(CC) $(CFLAGS) -g -DCM108_MAIN -o $@ $^ $(LDFLAGS)
+
+
# Touch Tone to Speech sample application.
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a
@@ -569,6 +595,7 @@ install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon
$(INSTALL) atest $(INSTALLDIR)/bin
$(INSTALL) ttcalc $(INSTALLDIR)/bin
$(INSTALL) kissutil $(INSTALLDIR)/bin
+ $(INSTALL) cm108 $(INSTALLDIR)/bin
$(INSTALL) dwespeak.sh $(INSTALLDIR)/bin
#
# Telemetry Toolkit executables. Other .conf and .txt files will go into doc directory.
@@ -643,6 +670,11 @@ install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon
$(INSTALL) -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
$(INSTALL) -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
$(INSTALL) -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
+#
+# Set group and mode of HID devices corresponding to C-Media USB Audio adapters.
+# This will allow us to use the CM108/CM119 GPIO pins for PTT.
+#
+ $(INSTALL) -D --mode=644 99-direwolf-cmedia.rules /etc/udev/rules.d/99-direwolf-cmedia.rules
#
@echo " "
@echo "If this is your first install, not an upgrade, type this to put a copy"
diff --git a/audio.h b/audio.h
index 6afda51..13fb22c 100644
--- a/audio.h
+++ b/audio.h
@@ -29,8 +29,9 @@ enum ptt_method_e {
PTT_METHOD_NONE, /* VOX or no transmit. */
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */
- PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
- PTT_METHOD_HAMLIB }; /* HAMLib, Linux only. */
+ PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
+ PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */
+ PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */
typedef enum ptt_method_e ptt_method_t;
@@ -191,13 +192,17 @@ struct audio_s {
struct {
- ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB. */
+ ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB, CM108. */
char ptt_device[100]; /* Serial device name for PTT. e.g. COM1 or /dev/ttyS0 */
/* Also used for HAMLIB. Could be host:port when model is 1. */
- /* For years, 20 characters was plenty and then along comes this crazy name: */
+ /* For years, 20 characters was plenty then we start getting extreme names like this: */
+ /* /dev/serial/by-id/usb-FTDI_Navigator__CAT___2nd_PTT__00000000-if00-port0 */
/* /dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0 */
/* Issue 104, changed to 100 bytes in version 1.5. */
+
+ /* This same field is also used for CM108 GPIO PTT which will */
+ /* have a name like /dev/hidraw1. */
ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */
ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */
@@ -205,8 +210,9 @@ struct audio_s {
int out_gpio_num; /* GPIO number. Originally this was only for PTT. */
/* It is now more general. */
/* octrl array is indexed by PTT, DCD, or CONnected indicator. */
+ /* For CM108, this should be in range of 1-8. */
-#define MAX_GPIO_NAME_LEN 16 // 12 would cover any case I've seen so this should be safe
+#define MAX_GPIO_NAME_LEN 20 // 12 would cover any case I've seen so this should be safe
char out_gpio_name[MAX_GPIO_NAME_LEN];
/* orginally, gpio number NN was assumed to simply */
@@ -215,6 +221,8 @@ struct audio_s {
/* This is filled in by ptt_init so we don't have to */
/* recalculate it each time we access it. */
+ /* This could probably be collapsed into ptt_device instead of being separate. */
+
int ptt_lpt_bit; /* Bit number for parallel printer port. */
/* Bit 0 = pin 2, ..., bit 7 = pin 9. */
diff --git a/cm108.c b/cm108.c
new file mode 100644
index 0000000..5454e63
--- /dev/null
+++ b/cm108.c
@@ -0,0 +1,706 @@
+//
+// This file is part of Dire Wolf, an amateur radio packet TNC.
+//
+// Copyright (C) 2017 John Langner, WB2OSZ
+//
+// Parts of this were adapted from "hamlib" which contains the notice:
+//
+// * Copyright (c) 2000-2012 by Stephane Fillod
+// * Copyright (c) 2011 by Andrew Errington
+// * CM108 detection code Copyright (c) Thomas Sailer used with permission
+//
+// This program 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 2 of the License, or
+// (at your option) any later version.
+//
+// This program 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 .
+
+/*------------------------------------------------------------------
+ *
+ * Module: cm108.c
+ *
+ * Purpose: Use the CM108/CM119 (or compatible) GPIO pins for the Push To Talk (PTT) Control.
+ *
+ * Description:
+ *
+ * There is an incresing demand for using the GPIO pins of USB audio devices for PTT.
+ * We have a couple commercial products:
+ *
+ * DMK URI http://www.dmkeng.com/URI_Order_Page.htm
+ * RB-USB RIM http://www.repeater-builder.com/products/usb-rim-lite.html
+ *
+ * and homebrew projects which are all very similar.
+ *
+ * http://www.qsl.net/kb9mwr/projects/voip/usbfob-119.pdf
+ * http://rtpdir.weebly.com/uploads/1/6/8/7/1687703/usbfob.pdf
+ * http://www.repeater-builder.com/projects/fob/USB-Fob-Construction.pdf
+ * https://irongarment.wordpress.com/2011/03/29/cm108-compatible-chips-with-gpio/
+ *
+ * Usually GPIO 3 is used because it is easier to tack solder a wire to a pin on the end.
+ *
+ * Soundmodem and hamlib paved the way but didn't get too far.
+ * Dire Wolf 1.3 added HAMLIB support (Linux only) which theoretically allows this in a
+ * roundabout way. This is documented in the User Guide, section called,
+ * "Hamlib PTT Example 2: Use GPIO of USB audio adapter. (e.g. DMK URI)"
+ *
+ * It's rather involved and the explantion doesn't cover the case of multiple
+ * USB-Audio adapters. It is not as straightforward as you might expect. Here we have
+ * an example of 3 C-Media USB adapters, a SignaLink USB, a keyboard, and a mouse.
+ *
+ *
+ * VID PID Product Sound ADEVICE HID [ptt]
+ * --- --- ------- ----- ------- ---------
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/pcmC1D0c plughw:1,0 /dev/hidraw0
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/pcmC1D0p plughw:1,0 /dev/hidraw0
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/controlC1 /dev/hidraw0
+ * 08bb 2904 USB Audio CODEC /dev/snd/pcmC2D0c plughw:2,0 /dev/hidraw2
+ * 08bb 2904 USB Audio CODEC /dev/snd/pcmC2D0p plughw:2,0 /dev/hidraw2
+ * 08bb 2904 USB Audio CODEC /dev/snd/controlC2 /dev/hidraw2
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/pcmC0D0c plughw:0,0 /dev/hidraw1
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/pcmC0D0p plughw:0,0 /dev/hidraw1
+ * ** 0d8c 000c C-Media USB Headphone Set /dev/snd/controlC0 /dev/hidraw1
+ * ** 0d8c 0008 C-Media USB Audio Device /dev/snd/pcmC4D0c plughw:4,0 /dev/hidraw6
+ * ** 0d8c 0008 C-Media USB Audio Device /dev/snd/pcmC4D0p plughw:4,0 /dev/hidraw6
+ * ** 0d8c 0008 C-Media USB Audio Device /dev/snd/controlC4 /dev/hidraw6
+ * 413c 2010 Dell USB Keyboard /dev/hidraw4
+ * 0461 4d15 USB Optical Mouse /dev/hidraw5
+ *
+ *
+ * The USB soundcards (/dev/snd/pcm...) have an associated Human Interface Device (HID)
+ * corresponding to the GPIO pins which are sometimes connected to pushbuttons.
+ * The mapping has no obvious pattern.
+ *
+ * Sound Card 0 HID 1
+ * Sound Card 1 HID 0
+ * Sound Card 2 HID 2
+ * Sound Card 4 HID 6
+ *
+ * That would be a real challenge if you had to figure that all out and configure manually.
+ * Dire Wolf version 1.5 makes this much more flexible and easier to use by supporting multiple
+ * sound devices and automatically determining the corresponding HID for the PTT signal.
+ *
+ *---------------------------------------------------------------*/
+
+#ifndef USE_CM108
+
+#ifdef CM108_MAIN
+
+#include "direwolf.h"
+#include "textcolor.h"
+
+int main (void)
+{
+ text_color_init (0); // Turn off text color.
+ dw_printf ("CM108 PTT support was disabled in Makefile.linux.\n");
+ return (0);
+}
+
+#endif
+
+#else // USE_CM108 is defined.
+
+#include "direwolf.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include // ioctl, _IOR
+#include
+#include
+#include // for HIDIOCGRAWINFO
+
+#include "textcolor.h"
+#include "cm108.h"
+
+static int cm108_write (char *name, int iomask, int iodata);
+
+
+// The CM108, CM109, and CM119 datasheets all say that idProduct can be in the range
+// of 0008 to 000f programmable by MSEL and MODE pin. How can we tell the difference?
+
+// CM108B is 0012.
+// CM119B is 0013.
+// CM108AH is 0139 programmable by MSEL and MODE pin.
+// CM119A is 013A programmable by MSEL and MODE pin.
+
+// To make matters even more confusing, these can be overridden
+// with an external EEPROM. Some have 8, rather than 4 GPIO.
+
+#define CMEDIA_VID 0xd8c // Vendor ID
+#define CMEDIA_PID1_MIN 0x0008 // range for CM108, CM109, CM119 (no following letters)
+#define CMEDIA_PID1_MAX 0x000f
+
+#define CMEDIA_PID2 0x013a // CM119A
+
+#define CMEDIA_PID_CM108AH 0x0139 // CM108AH
+#define CMEDIA_PID_CM108B 0x0012 // CM108B
+#define CMEDIA_PID_CM119A 0x013a // CM119A
+#define CMEDIA_PID_CM119B 0x0013 // CM119B
+#define CMEDIA_PID_HS100 0x013c // HS100
+
+// The SSS chips seem to be pretty much compatible but they have only two GPIO.
+// https://irongarment.wordpress.com/2011/03/29/cm108-compatible-chips-with-gpio/
+// Data sheet says VID/PID is from an EEPROM but mentions no default.
+
+#define SSS_VID 0x0c76 // SSS1621, SSS1623
+#define SSS_PID1 0x1605
+#define SSS_PID2 0x1607
+#define SSS_PID3 0x160b
+
+
+// Device VID PID Number of GPIO
+// ------ --- --- --------------
+// CM108 0d8c 0008-000f * 4
+// CM108AH 0d8c 0139 * 3 Has GPIO 1,3,4 but not 2
+// CM108B 0d8c 0012 3 Has GPIO 1,3,4 but not 2
+// CM109 0d8c 0008-000f * 8
+// CM119 0d8c 0008-000f * 8
+// CM119A 0d8c 013a * 8
+// CM119B 0d8c 0013 8
+// HS100 0d8c 013c 0
+//
+// SSS1621 0c76 1605 2 per ZL3AME, Can't find data sheet
+// SSS1623 0c76 1607,160b 2 per ZL3AME, Not in data sheet.
+//
+// * idProduct programmable by MSEL and MODE pin.
+//
+
+// CMedia pin GPIO Notes
+// ---------- ---- -----
+// 43 1
+// 11 2 N.C. for CM108AH, CM108B
+// 13 3 Most popular for PTT because it is on the end.
+// 15 4
+// 16 5 CM109, CM119, CM119A, CM119B only
+// 17 6 "
+// 20 7 "
+// 22 8 "
+
+// Test for supported devices.
+
+#define GOOD_DEVICE(v,p) ( (v == CMEDIA_VID && ((p >= CMEDIA_PID1_MIN && p <= CMEDIA_PID1_MAX) || p == CMEDIA_PID2)) || \
+ (v == SSS_VID && (p == SSS_PID1 || p == SSS_PID2 || p == SSS_PID3)) )
+
+// Look out for null source pointer, and avoid buffer overflow on destination.
+
+#define SAFE_STRCPY(to,from) { if (from != NULL) { strncpy(to,from,sizeof(to)); to[sizeof(to)-1] = '\0'; } }
+
+
+// Used to process regular expression matching results.
+
+static void inline substr_se (char *dest, const char *src, int start, int endp1)
+{
+ int len = endp1 - start;
+
+ if (start < 0 || endp1 < 0 || len <= 0) {
+ dest[0] = '\0';
+ return;
+ }
+ memcpy (dest, src + start, len);
+ dest[len] = '\0';
+
+} /* end substr_se */
+
+
+/*
+ * Result of taking inventory of USB soundcards and USB HIDs.
+ */
+
+struct thing_s {
+ int vid; // vendor id
+ int pid; // product id
+ char product[32]; // product name (e.g. manufacturer, model)
+ char devnode_sound[22]; // e.g. /dev/snd/pcmC0D0p
+ char plughw[15]; // Above in more familiar format e.g. plughw:0,0
+ char devnode_hidraw[17]; // e.g. /dev/hidraw3
+ char devnode_usb[25]; // e.g. /dev/bus/usb/001/012
+};
+
+int cm108_inventory (struct thing_s *things, int max_things);
+
+
+/*-------------------------------------------------------------------
+ *
+ * Name: main
+ *
+ * Purpose: Test program to list USB audio and HID devices.
+ *
+ * sudo apt-get install libudev-dev
+ * gcc -DCM108_MAIN textcolor.c -l udev
+ *
+ *------------------------------------------------------------------*/
+
+#define MAXX_THINGS 60
+
+#ifdef CM108_MAIN
+
+int main (void)
+{
+ struct thing_s things[MAXX_THINGS];
+ int num_things;
+ int i;
+
+ text_color_init (0); // Turn off text color.
+
+ num_things = cm108_inventory (things, MAXX_THINGS);
+
+ dw_printf (" VID PID %-*s %-*s %-*s %-*s"
+#if EXTRA
+ " %-*s"
+#endif
+ "\n", (int)sizeof(things[0].product), "Product",
+ (int)sizeof(things[0].devnode_sound), "Sound",
+ (int)sizeof(things[0].plughw), "ADEVICE",
+ (int)sizeof(things[0].devnode_hidraw), "HID [ptt]"
+#if EXTRA
+ , (int)sizeof(things[0].devnode_usb), "USB"
+#endif
+ );
+
+ dw_printf (" --- --- %-*s %-*s %-*s %-*s"
+#if EXTRA
+ " %-*s"
+#endif
+ "\n", (int)sizeof(things[0].product), "-------",
+ (int)sizeof(things[0].devnode_sound), "-----",
+ (int)sizeof(things[0].plughw), "-------",
+ (int)sizeof(things[0].devnode_hidraw), "---------"
+#if EXTRA
+ , (int)sizeof(things[0].devnode_usb), "---"
+#endif
+ );
+ for (i = 0; i < num_things; i++) {
+
+ dw_printf ("%2s %04x %04x %-*s %-*s %-*s %-*s"
+#if EXTRA
+ " %-*s"
+#endif
+ "\n",
+ GOOD_DEVICE(things[i].vid,things[i].pid) ? "**" : " ",
+ things[i].vid, things[i].pid,
+ (int)sizeof(things[i].product), things[i].product,
+ (int)sizeof(things[i].devnode_sound), things[i].devnode_sound,
+ (int)sizeof(things[0].plughw), things[i].plughw,
+ (int)sizeof(things[i].devnode_hidraw), things[i].devnode_hidraw
+#if EXTRA
+ , (int)sizeof(things[i].devnode_usb), things[i].devnode_usb
+#endif
+ );
+ }
+
+ return (0);
+}
+
+#endif // CM108_MAIN
+
+
+
+/*-------------------------------------------------------------------
+ *
+ * Name: cm108_inventory
+ *
+ * Purpose: Take inventory of USB audio and HID.
+ *
+ * Inputs: max_things - Maximum number of items to collect.
+ *
+ * Outputs: things - Array of items collected.
+ * Corresponding sound device and HID are merged into one item.
+ *
+ * Returns: Number of items placed in things array.
+ * Should be in the range of 0 thru max_things.
+ * -1 for a bad unexpected error.
+ *
+ *------------------------------------------------------------------*/
+
+
+int cm108_inventory (struct thing_s *things, int max_things)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ struct udev_device *parentdev;
+
+ int num_things = 0;
+ memset (things, 0, sizeof(struct thing_s) * max_things);
+
+/*
+ * First get a list of the USB audio devices.
+ * This is based on the example in http://www.signal11.us/oss/udev/
+ */
+ udev = udev_new();
+ if (!udev) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("INTERNAL ERROR: Can't create udev.\n");
+ return (-1);
+ }
+
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(enumerate, "sound");
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path;
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+ char const *devnode = udev_device_get_devnode(dev);
+ if (devnode != NULL) {
+ parentdev = udev_device_get_parent_with_subsystem_devtype( dev, "usb", "usb_device");
+ if (parentdev != NULL) {
+ char const *p;
+ int vid = 0;
+ int pid = 0;
+
+ p = udev_device_get_sysattr_value(parentdev,"idVendor");
+ if (p != NULL) vid = strtol(p, NULL, 16);
+ p = udev_device_get_sysattr_value(parentdev,"idProduct");
+ if (p != NULL) pid = strtol(p, NULL, 16);
+
+ if (num_things < max_things) {
+ things[num_things].vid = vid;
+ things[num_things].pid = pid;
+ SAFE_STRCPY (things[num_things].product, udev_device_get_sysattr_value(parentdev,"product"));
+ SAFE_STRCPY (things[num_things].devnode_sound, devnode);
+ SAFE_STRCPY (things[num_things].devnode_usb, udev_device_get_devnode(parentdev));
+ num_things++;
+ }
+ udev_device_unref(parentdev);
+ }
+ }
+ }
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+
+/*
+ * Now merge in all of the USB HID.
+ */
+ udev = udev_new();
+ if (!udev) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("INTERNAL ERROR: Can't create udev.\n");
+ return (-1);
+ }
+
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(enumerate, "hidraw");
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path;
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+ char const *devnode = udev_device_get_devnode(dev);
+ if (devnode != NULL) {
+ parentdev = udev_device_get_parent_with_subsystem_devtype( dev, "usb", "usb_device");
+ if (parentdev != NULL) {
+ char const *p;
+ int vid = 0;
+ int pid = 0;
+
+ p = udev_device_get_sysattr_value(parentdev,"idVendor");
+ if (p != NULL) vid = strtol(p, NULL, 16);
+ p = udev_device_get_sysattr_value(parentdev,"idProduct");
+ if (p != NULL) pid = strtol(p, NULL, 16);
+
+ int j, matched = 0;
+ char const *usb = udev_device_get_devnode(parentdev);
+
+ // Add hidraw name to any matching existing.
+ for (j = 0; j < num_things; j++) {
+ if (things[j].vid == vid && things[j].pid == pid && usb != NULL && strcmp(things[j].devnode_usb,usb) == 0) {
+ matched = 1;
+ SAFE_STRCPY (things[j].devnode_hidraw, devnode);
+ }
+ }
+
+ // If it did not match to existing, add new entry.
+ if (matched == 0 && num_things < max_things) {
+ things[num_things].vid = vid;
+ things[num_things].pid = pid;
+ SAFE_STRCPY (things[num_things].product, udev_device_get_sysattr_value(parentdev,"product"));
+ SAFE_STRCPY (things[num_things].devnode_hidraw, devnode);
+ SAFE_STRCPY (things[num_things].devnode_usb, usb);
+ num_things++;
+ }
+ udev_device_unref(parentdev);
+ }
+ }
+ }
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+
+/*
+ * Seeing the form /dev/snd/pcmC4D0p will be confusing to many because we
+ * would generally something like plughw:4,0 for in the direwolf configuration file.
+ * Construct the more familiar form.
+ */
+ int i;
+ regex_t pcm_re;
+ char emsg[100];
+ int e = regcomp (&pcm_re, "pcmC([0-9]+)D([0-9]+)[cp]", REG_EXTENDED);
+ if (e) {
+ regerror (e, &pcm_re, emsg, sizeof(emsg));
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("INTERNAL ERROR: %s:%d: %s\n", __FILE__, __LINE__, emsg);
+ return (-1);
+ }
+
+ for (i = 0; i < num_things; i++) {
+ regmatch_t match[3];
+
+ if (regexec (&pcm_re, things[i].devnode_sound, 3, match, 0) == 0) {
+ char c[32], d[32];
+ substr_se (c, things[i].devnode_sound, match[1].rm_so, match[1].rm_eo);
+ substr_se (d, things[i].devnode_sound, match[2].rm_so, match[2].rm_eo);
+ snprintf (things[i].plughw, sizeof(things[i].plughw), "plughw:%s,%s", c, d);
+ }
+ }
+
+ return (num_things);
+
+} /* end cm108_inventory */
+
+
+/*-------------------------------------------------------------------
+ *
+ * Name: cm108_find_ptt
+ *
+ * Purpose: Try to find /dev/hidraw corresponding to plughw:n,n
+ *
+ * Inputs: output_audio_device
+ * - Device name used in the ADEVICE configuration.
+ * This would generally be something like plughw:1,0
+ *
+ * ptt_device_size - Size of result area to avoid buffer overflow.
+ *
+ * Outputs: ptt_device - Device name, something like /dev/hidraw2.
+ * Will be emptry string if no match found.
+ *
+ * Returns: none
+ *
+ *------------------------------------------------------------------*/
+
+void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_device_size)
+{
+ struct thing_s things[MAXX_THINGS];
+ int num_things;
+ int i;
+
+ strlcpy (ptt_device, "", ptt_device_size);
+ num_things = cm108_inventory (things, MAXX_THINGS);
+
+ for (i = 0; i < num_things; i++) {
+
+ if (GOOD_DEVICE(things[i].vid,things[i].pid) ) {
+ if (strcmp(output_audio_device, things[i].plughw) == 0) {
+ strlcpy (ptt_device, things[i].devnode_hidraw, ptt_device_size);
+ }
+ }
+ }
+
+} /* end cm108_find_ptt */
+
+
+
+/*-------------------------------------------------------------------
+ *
+ * Name: cm108_set_gpio_pin
+ *
+ * Purpose: Set one GPIO pin of the CM108 or similar.
+ *
+ * Inputs: name - Name of device such as /dev/hidraw2.
+ *
+ * num - GPIO number, range 1 thru 8.
+ *
+ * state - 1 for on, 0 for off.
+ *
+ * Returns: 0 for success. -1 for error.
+ *
+ * Errors: A descriptive error message will be printed for any problem.
+ *
+ * Future: For our initial implementation we are making the simplifying
+ * restriction of using only one GPIO pin per device and limit
+ * configuratin to PTT only.
+ * Longer term, we might want to have DCD, and maybe other
+ * controls thru the same chip.
+ * In this case, we would need to retain bit masks for each
+ * device so new data can be merged with old before sending it out.
+ *
+ *------------------------------------------------------------------*/
+
+int cm108_set_gpio_pin (char *name, int num, int state)
+{
+ int iomask;
+ int iodata;
+
+ if (num < 1 || num > 8) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("%s CM108 GPIO number %d must be in range of 1 thru 8.\n", name, num);
+ return (-1);
+ }
+
+ if (state != 0 && state != 1) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("%s CM108 GPIO state %d must be 0 or 1.\n", name, state);
+ return (-1);
+ }
+
+ iomask = 1 << (num - 1);
+ iodata = state << (num - 1);
+
+ return (cm108_write (name, iomask, iodata));
+
+} /* end cm108_set_gpio_pin */
+
+
+/*-------------------------------------------------------------------
+ *
+ * Name: cm108_write
+ *
+ * Purpose: Set the GPIO pins of the CM108 or similar.
+ *
+ * Inputs: name - Name of device such as /dev/hidraw2.
+ *
+ * iomask - Bit mask for I/O direction.
+ * LSB is GPIO1, bit 1 is GPIO2, etc.
+ * 1 for output, 0 for input.
+ *
+ * iodata - Output data, same bit order as iomask.
+ *
+ * Returns: 0 for success. -1 for error.
+ *
+ * Errors: A descriptive error message will be printed for any problem.
+ *
+ * Description: This is the lowest level function.
+ * An application probably wants to use cm108_set_gpio_pin.
+ *
+ *------------------------------------------------------------------*/
+
+static int cm108_write (char *name, int iomask, int iodata)
+{
+ int fd;
+ struct hidraw_devinfo info;
+ char io[5];
+ int n;
+
+ //text_color_set(DW_COLOR_DEBUG);
+ //dw_printf ("TEMP DEBUG cm108_write: %s %d %d\n", name, iomask, iodata);
+
+/*
+ * By default, the USB HID are accessible only by root:
+ *
+ * crw------- 1 root root 249, 1 ... /dev/hidraw1
+ *
+ * How should we handle this?
+ * Manually changing it will revert back on the next reboot or
+ * when the device is removed and reinserted.
+ *
+ * According to various articles on the Internet, we should be able to
+ * add a file to /etc/udev/rules.d. "99-direwolf-cmedia.rules" would be a
+ * suitable name. The leading number is the order. We want this to be
+ * near the end. I think the file extension must be ".rules."
+ *
+ * We could completely open it up to everyone like this:
+ *
+ * # Allow ordinary user to access CMedia GPIO for PTT.
+ * SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d8c", MODE="0666"
+ *
+ * Whenever we have CMedia USB audio adapter, it should be accessible by everyone.
+ * This would not apply to other /dev/hidraw* corresponding to keyboard, mouse, etc.
+ *
+ * Notice the == (double =) for testing and := for setting a property.
+ *
+ * If you are concerned about security, you could restrict access to
+ * a particular group, something like this:
+ *
+ * SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d8c", GROUP="audio", MODE="0660"
+ *
+ * I figure "audio" makes more sense than "gpio" because we need to be part of
+ * audio group to use the USB Audio adapter for sound.
+ */
+
+ fd = open (name, O_WRONLY);
+ if (fd == -1) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Could not open %s for write, errno=%d\n", name, errno);
+ if (errno == EACCES) { // 13
+ dw_printf ("Type \"ls -l %s\" and verify that it has audio group rw similar to this:\n", name);
+ dw_printf (" crw-rw---- 1 root audio 247, 0 Oct 6 19:24 %s\n", name);
+ dw_printf ("rather than root-only access like this:\n");
+ dw_printf (" crw------- 1 root root 247, 0 Sep 24 09:40 %s\n", name);
+ }
+ return (-1);
+ }
+
+ // Just for fun, let's get the device information.
+
+#if 1
+ n = ioctl(fd, HIDIOCGRAWINFO, &info);
+ if (n == 0) {
+ if ( ! GOOD_DEVICE(info.vendor, info.product)) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("ioctl HIDIOCGRAWINFO failed for %s. errno = %d.\n", name, errno);
+ }
+ }
+ else {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("%s is not a supported device type. Proceed at your own risk. vid=%04x pid=%04x\n", name, info.vendor, info.product);
+ }
+#endif
+ // To make a long story short, I think we need 0 for the first two bytes.
+
+ io[0] = 0;
+ io[1] = 0;
+ io[2] = iomask;
+ io[3] = iodata;
+ io[4] = 0;
+
+ // Writing 4 bytes fails with errno 32, EPIPE, "broken pipe."
+ // Hamlib writes 5 bytes which I don't understand.
+ // Writing 5 bytes works.
+ // I have no idea why. From the CMedia datasheet it looks like we need 4.
+
+ n = write (fd, io, sizeof(io));
+ if (n != sizeof(io)) {
+ // Errors observed during development.
+ // as pi EACCES 13 /* Permission denied */
+ // as root EPIPE 32 /* Broken pipe - Happens if we send 4 bytes */
+
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Write to %s failed, n=%d, errno=%d\n", name, n, errno);
+
+ if (errno == EACCES) {
+ dw_printf ("Type \"ls -l %s\" and verify that it has audio group rw similar to this:\n", name);
+ dw_printf (" crw-rw---- 1 root audio 247, 0 Oct 6 19:24 %s\n", name);
+ dw_printf ("rather than root-only access like this:\n");
+ dw_printf (" crw------- 1 root root 247, 0 Sep 24 09:40 %s\n", name);
+ }
+
+ close (fd);
+ return (-1);
+ }
+
+ close (fd);
+ return (0);
+
+} /* end cm108_write */
+
+#endif // ifdef USE_CM108
+
+/* end cm108.c */
+
+
\ No newline at end of file
diff --git a/cm108.h b/cm108.h
new file mode 100644
index 0000000..2def77a
--- /dev/null
+++ b/cm108.h
@@ -0,0 +1,5 @@
+/* Dire Wolf cm108.h */
+
+extern void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_device_size);
+
+extern int cm108_set_gpio_pin (char *name, int num, int state);
\ No newline at end of file
diff --git a/config.c b/config.c
index 3c1d4e1..ed8a20e 100644
--- a/config.c
+++ b/config.c
@@ -63,6 +63,10 @@
#include "tt_text.h"
#include "ax25_link.h"
+#ifdef USE_CM108 // Linux only
+#include "cm108.h"
+#endif
+
// geotranz
#include "utm.h"
@@ -1613,6 +1617,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
* xxx LPT [-]bit-num
* PTT RIG model port
* PTT RIG AUTO port
+ * PTT CM108 [ [-]bit-num ] [ hid-device ]
*
* When model is 2, port would host:port like 127.0.0.1:4532
* Otherwise, port would be a serial port like /dev/ttyS0
@@ -1737,16 +1742,97 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_HAMLIB;
+#else
+#if __WIN32__
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: Windows version of direwolf does not support HAMLIB.\n", line);
+ exit (EXIT_FAILURE);
#else
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file line %d: %s with RIG is only available when hamlib support is enabled.\n", line, otname);
-#if __WIN32__
- dw_printf ("Hamlib is not currently supported on Windows.\n");
-#else
dw_printf ("You must rebuild direwolf with hamlib support.\n");
dw_printf ("See User Guide for details.\n");
#endif
+#endif
+ }
+ if (strcasecmp(t, "CM108") == 0) {
+
+/* CM108 - GPIO of USB sound card. case, Linux only. */
+
+#ifdef USE_CM108
+
+ if (ot != OCTYPE_PTT) {
+ // Future project: Allow DCD and CON via the same device.
+ // This gets more complicated because we can't selectively change a single GPIO bit.
+ // We would need to keep track of what is currently there, change one bit, in our local
+ // copy of the status and then write out the byte for all of the pins.
+ // Let's keep it simple with just PTT for the first stab at this.
+
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: PTT CM108 option is only valid for PTT, not %s.\n", line, otname);
+ continue;
+ }
+
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num = 3; // All known designs use GPIO 3.
+ // User can override for special cases.
+ p_audio_config->achan[channel].octrl[ot].ptt_invert = 0; // High for transmit.
+ strcpy (p_audio_config->achan[channel].octrl[ot].ptt_device, "");
+
+ // Try to find PTT device for audio output device.
+ // Simplifiying assumption is that we have one radio per USB Audio Adapter.
+ // Failure at this point is not an error.
+ // See if config file sets it explicitly before complaining.
+
+ cm108_find_ptt (p_audio_config->adev[ACHAN2ADEV(channel)].adevice_out,
+ p_audio_config->achan[channel].octrl[ot].ptt_device,
+ (int)sizeof(p_audio_config->achan[channel].octrl[ot].ptt_device));
+
+ while ((t = split(NULL,0)) != NULL) {
+ if (*t == '-') {
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t+1);
+ p_audio_config->achan[channel].octrl[ot].ptt_invert = 1;
+ }
+ else if (isdigit(*t)) {
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t);
+ p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
+ }
+ else if (*t == '/') {
+ strlcpy (p_audio_config->achan[channel].octrl[ot].ptt_device, t, sizeof(p_audio_config->achan[channel].octrl[ot].ptt_device));
+ }
+ else {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: Found \"%s\" when expecting GPIO number or device name like /dev/hidraw1.\n", line, t);
+ continue;
+ }
+ }
+ if (p_audio_config->achan[channel].octrl[ot].out_gpio_num < 1 || p_audio_config->achan[channel].octrl[ot].out_gpio_num > 8) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: CM108 GPIO number %d is not in range of 1 thru 8.\n", line,
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num);
+ continue;
+ }
+ if (strlen(p_audio_config->achan[channel].octrl[ot].ptt_device) == 0) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: Could not determine USB Audio GPIO PTT device for audio output %s.\n", line,
+ p_audio_config->adev[ACHAN2ADEV(channel)].adevice_out);
+ dw_printf ("You must explicitly mention a device name such as /dev/hidraw1.\n");
+ dw_printf ("See User Guide for details.\n");
+ continue;
+ }
+ p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_CM108;
+
+#else
+#if __WIN32__
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: CM108 USB Audio GPIO PTT is not available for Windows.\n", line);
+#else
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: %s with CM108 is only available when USB Audio GPIO support is enabled.\n", line, otname);
+ dw_printf ("You must rebuild direwolf with CM108 Audio Adapter GPIO PTT support.\n");
+ dw_printf ("See User Guide for details.\n");
+#endif
+ exit (EXIT_FAILURE);
#endif
}
else {
diff --git a/doc/Raspberry-Pi-APRS.pdf b/doc/Raspberry-Pi-APRS.pdf
index 774526d..328d269 100644
Binary files a/doc/Raspberry-Pi-APRS.pdf and b/doc/Raspberry-Pi-APRS.pdf differ
diff --git a/doc/User-Guide.pdf b/doc/User-Guide.pdf
index 5e337cc..da393db 100644
Binary files a/doc/User-Guide.pdf and b/doc/User-Guide.pdf differ
diff --git a/ptt.c b/ptt.c
index da5429a..c070e5a 100644
--- a/ptt.c
+++ b/ptt.c
@@ -52,6 +52,9 @@
*
* Handle more complicated gpio node names for CubieBoard, etc.
*
+ * Version 1.5: Ability to use GPIO pins of CM108/CM119 for PTT signal.
+ *
+ *
* References: http://www.robbayer.com/files/serial-win.pdf
*
* https://www.kernel.org/doc/Documentation/gpio.txt
@@ -59,16 +62,20 @@
*---------------------------------------------------------------*/
/*
- Idea for future enhancement:
+ A growing number of people have been asking about support for the DMK URI
+ or the similar RB-USB RIM.
- A growing number of people have been asking about support for the DMK URI.
- This uses a C-Media CM108/CM119 with one interesting addition, a GPIO
+ These use a C-Media CM108/CM119 with an interesting addition, a GPIO
pin is used to drive PTT. Here is some related information.
DMK URI:
http://www.dmkeng.com/URI_Order_Page.htm
http://dmkeng.com/images/URI%20Schematic.pdf
+
+ RB-USB RIM:
+
+ http://www.repeater-builder.com/products/usb-rim-lite.html
http://www.repeater-builder.com/voip/pdf/cm119-datasheet.pdf
Homebrew versions of the same idea:
@@ -83,6 +90,7 @@
http://docs.allstarlink.org/drupal/
http://soundmodem.sourcearchive.com/documentation/0.16-1/ptt_8c_source.html
https://github.com/N0NB/hamlib/blob/master/src/cm108.c#L190
+ http://permalink.gmane.org/gmane.linux.hams.hamlib.devel/3420
Information about the "hidraw" device:
@@ -92,12 +100,31 @@
https://github.com/signal11/hidapi/blob/master/libusb/hid.c
http://stackoverflow.com/questions/899008/howto-write-to-the-gpio-pin-of-the-cm108-chip-in-linux
https://www.kernel.org/doc/Documentation/hid/hidraw.txt
+ https://github.com/torvalds/linux/blob/master/samples/hidraw/hid-example.c
- In version 1.3, we add HAMLIB support which should be able to do this.
- (Linux only & haven't verified that it actually works yet!)
+ Similar chips: SSS1621, SSS1623
+
+ https://irongarment.wordpress.com/2011/03/29/cm108-compatible-chips-with-gpio/
+
+ Here is an attempt to add direct CM108 support.
+ Seems to be hardcoded for only a single USB audio adapter.
+
+ https://github.com/donothingloop/direwolf_cm108
+
+ In version 1.3, we add HAMLIB support which should be able to do this in a roundabout way.
+ (Linux only at this point.)
+
+ This is documented in the User Guide, section called,
+ "Hamlib PTT Example 2: Use GPIO of USB audio adapter. (e.g. DMK URI)"
+
+ It's rather involved and the explantion doesn't cover the case of multiple
+ USB-Audio adapters. It would be nice to have a little script which lists all
+ of the USB-Audio adapters and the corresponding /dev/hidraw device.
+ ( We now have it. The included "cm108" application. )
- Might want to have CM108 GPIO support built in, someday, for simpler building & configuration.
- Maybe even for Windows. ;-)
+ In version 1.5 we have a flexible, easy to use implementation for Linux.
+ Windows would be a lot of extra work because USB devices are nothing like Linux.
+ We'd be starting from scratch to figure out how to do it.
*/
@@ -126,6 +153,10 @@
#include
#endif
+#ifdef USE_CM108
+#include "cm108.h"
+#endif
+
/* So we can have more common code for fd. */
typedef int HANDLE;
#define INVALID_HANDLE_VALUE (-1)
@@ -157,10 +188,6 @@ typedef int HANDLE;
#endif
-#if TEST
-#define dw_printf printf
-#endif
-
static struct audio_s *save_audio_config_p; /* Save config information for later use. */
@@ -603,10 +630,12 @@ void export_gpio(int ch, int ot, int invert, int direction)
* PTT_METHOD_GPIO - general purpose I/O.
* PTT_METHOD_LPT - Parallel printer port.
* PTT_METHOD_HAMLIB - HAMLib rig control.
+ * PTT_METHOD_CM108 - GPIO pins of CM108 etc. USB Audio.
*
* ptt_device Name of serial port device.
* e.g. COM1 or /dev/ttyS0.
* HAMLIB can also use hostaddr:port.
+ * Like /dev/hidraw1 for CM108.
*
* ptt_line RTS or DTR when using serial port.
*
@@ -992,6 +1021,32 @@ void ptt_init (struct audio_s *audio_config_p)
#endif
+/*
+ * Confirm what is going on with CM108 GPIO output.
+ * Could use some error checking for overlap.
+ */
+
+#if USE_CM108
+
+ for (ch = 0; ch < MAX_CHANS; ch++) {
+
+ if (audio_config_p->achan[ch].valid) {
+ int ot;
+ for (ot = 0; ot < NUM_OCTYPES; ot++) {
+ if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_CM108) {
+ text_color_set(DW_COLOR_INFO);
+ dw_printf ("Using %s GPIO %d for channel %d %s control.\n",
+ audio_config_p->achan[ch].octrl[ot].ptt_device,
+ audio_config_p->achan[ch].octrl[ot].out_gpio_num,
+ ch,
+ otnames[ot]);
+ }
+ }
+ }
+ }
+
+#endif
+
/* Why doesn't it transmit? Probably forgot to specify PTT option. */
@@ -1059,7 +1114,9 @@ void ptt_set (int ot, int chan, int ptt_signal)
* This is a very convenient place to get that information.
*/
+#ifndef TEST
dlq_channel_busy (chan, ot, ptt_signal);
+#endif
/*
* Inverted output?
@@ -1221,6 +1278,21 @@ void ptt_set (int ot, int chan, int ptt_signal)
}
#endif
+/*
+ * Using CM108 USB Audio adapter GPIO?
+ */
+
+#ifdef USE_CM108
+
+ if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_CM108) {
+
+ if (cm108_set_gpio_pin (save_audio_config_p->achan[chan].octrl[ot].ptt_device,
+ save_audio_config_p->achan[chan].octrl[ot].out_gpio_num, ptt) != 0) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("ERROR: %s for channel %d has failed. See User Guide for troubleshooting tips.\n", otnames[ot], chan);
+ }
+ }
+#endif
} /* end ptt_set */
@@ -1354,18 +1426,15 @@ void ptt_term (void)
/*
* Quick stand-alone test for above.
*
- * gcc -DTEST -o ptest ptt.c ; ./ptest
+ * gcc -DTEST -o ptest ptt.c textcolor.o misc.a ; ./ptest
*
+ * TODO: Retest this, add CM108 GPIO to test.
*/
#if TEST
-void text_color_set (dw_color_t c) { }
-
-#define dw_printf printf
-
-main ()
+int main ()
{
struct audio_s my_audio_config;
int n;
@@ -1375,17 +1444,18 @@ main ()
my_audio_config.adev[0].num_channels = 2;
- my_audio_config.valid[0] = 1;
- my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
- //strlcpy (my_audio_config.ptt_device, "COM1", sizeof(my_audio_config.ptt_device));
- strlcpy (my_audio_config.ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.ptt_device));
- my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_RTS;
+ my_audio_config.achan[0].valid = 1;
+ my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
+// TODO: device should be command line argument.
+ strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device));
+ //strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device));
+ my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_RTS;
- my_audio_config.valid[1] = 1;
- my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
- //strlcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "COM1", sizeof(my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device));
- strlcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device));
- my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_DTR;
+ my_audio_config.achan[1].valid = 1;
+ my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
+ strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device));
+ //strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device));
+ my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_DTR;
/* initialize - both off */
@@ -1420,7 +1490,7 @@ main ()
/* Same thing again but invert RTS. */
- my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_invert = 1;
+ my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_invert = 1;
ptt_init (&my_audio_config);
@@ -1476,6 +1546,14 @@ main ()
#endif
+
+/* Parallel printer port. */
+
+#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
+
+ // TODO
+
+#if 0
memset (&my_audio_config, 0, sizeof(my_audio_config));
my_audio_config.num_channels = 2;
my_audio_config.valid[0] = 1;
@@ -1496,16 +1574,11 @@ main ()
}
ptt_term ();
-
-/* Parallel printer port. */
-
-#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
-
- // TODO
+#endif
#endif
-
+ return(0);
}
#endif /* TEST */