diff --git a/NEWS b/NEWS index a0114ed9c..189e9aff0 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ Version 5.x -- future * Change FT1000MP Mark V model names to align with FT1000MP Version 4.6 + * Added rig_cm108_get/set_bit to API and get/set_gpio to rigctl(d) for GPIO1,2,3,4 access on CM108 * Added BG2FX FX4/C/CR/L * Fixed IC7610 to use new 0x25 0x26 command added in latest firmware * Fix W command in rigctld to work propery -- can take terminating char or # of bytes to expect diff --git a/doc/man1/rigctl.1 b/doc/man1/rigctl.1 index a253c586e..b218ad994 100644 --- a/doc/man1/rigctl.1 +++ b/doc/man1/rigctl.1 @@ -1398,6 +1398,31 @@ Examples: .BR client_version " \(aq" \fIString\fP "\(aq .EX Client can send its version to rigctld and get feedback on compatibility, deprecation, and alternatives +.TP +.BR hamlib_version +.EX +Returns hamlib version with ISO8601 date/time +. +.TP +.BR test +.EX +Performs test routines. Under development. +. +.TP +.BR set_gpio " \(aq" \fIGPIO#\fP "\(aq +.EX +Sets GPIO1, GPIO2, GPIO3, GPIO4 on the GPIO ptt port +Can also use 1,2,3,4 +. +.TP +.BR XXXX +.EX +Stuff +. +.TP +.BR XXXX +.EX +Stuff . .SH READLINE . diff --git a/doc/man1/rigctld.1 b/doc/man1/rigctld.1 index 6112ef07e..871ce5953 100644 --- a/doc/man1/rigctld.1 +++ b/doc/man1/rigctld.1 @@ -1202,6 +1202,52 @@ CW Skimmer is started and "set_lock_mode 0" when CW Skimmer is stopped. .BR get_lock_mode Returns current lock mode status 1=On, 2=Off (only useful with rigctld) . +.TP +.BR send_raw " \(aq" \fITerminator\fP "\(aq \(aq" \fIString\fP \(aq +.EX +Can send ASCII string or 0xnn values -- there can be no spaces in the command string. +Possible terminator values are CR, LF, ;, ICOM, 0-100 (bytes to read), or -1 meaning unknown (will timeout on read) +Examples: + send_raw ; FA;MD; + send_raw icom 0xFE;0xFE;0x94;0x03;0xFD + send_raw -1 0xFE;0xFE;0x94;0x03;0xFD + send_raw 14 0xFE;0xFE;0x94;0x03;0xFD +. +.TP +.BR client_version " \(aq" \fIString\fP "\(aq +.EX + Client can send its version to rigctld and get feedback on compatibility, deprecation, and alternatives +.TP +.BR hamlib_version +.EX +Returns hamlib version with ISO8601 date/time +. ++.TP ++.BR hamlib_version ++.EX ++Returns hamlib version with ISO8601 date/time ++. ++.TP ++.BR test ++.EX ++Performs test routines. Under development. ++. ++.TP ++.BR set_gpio " \(aq" \fIGPIO#\fP "\(aq ++.EX ++Sets GPIO1, GPIO2, GPIO3, GPIO4 on the GPIO ptt port ++Can also use 1,2,3,4 ++. ++.TP ++.BR XXXX ++.EX ++Stuff ++. ++.TP ++.BR XXXX ++.EX ++Stuff + . .SH PROTOCOL . diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 4e0dd8c9f..ad57c3390 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -3694,6 +3694,10 @@ extern HAMLIB_EXPORT(int) rig_is_model(RIG *rig, rig_model_t model); extern HAMLIB_EXPORT(char*) rig_date_strget(char *buf, int buflen, int localtime); +enum GPIO { GPIO1, GPIO2, GPIO3, GPIO4 }; +extern HAMLIB_EXPORT(int) rig_cm108_get_bit(hamlib_port_t *p, enum GPIO gpio, int *bit); +extern HAMLIB_EXPORT(int) rig_cm108_set_bit(hamlib_port_t *p, enum GPIO gpio, int bit); + //! @endcond diff --git a/src/cm108.c b/src/cm108.c index d46c449c1..50587cad9 100644 --- a/src/cm108.c +++ b/src/cm108.c @@ -195,7 +195,7 @@ int cm108_ptt_set(hamlib_port_t *p, ptt_t pttx) case RIG_PTT_CM108: { - ssize_t nw; + ssize_t bytes; char out_rep[] = { 0x00, // report number @@ -227,9 +227,9 @@ int cm108_ptt_set(hamlib_port_t *p, ptt_t pttx) } // Send the HID packet - nw = write(p->fd, out_rep, sizeof(out_rep)); + bytes = write(p->fd, out_rep, sizeof(out_rep)); - if (nw < 0) + if (bytes < 0) { return -RIG_EIO; } @@ -295,30 +295,122 @@ int cm108_ptt_get(hamlib_port_t *p, ptt_t *pttx) */ int cm108_dcd_get(hamlib_port_t *p, dcd_t *dcdx) { + int bytes; + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); - // On the CM108 and compatible chips the squelch line on the radio is - // wired to Volume Down input pin. The state of this pin is reported - // in HID messages from the CM108 device, but I am not sure how - // to query this state on demand. - - switch (p->type.dcd) - { - case RIG_DCD_CM108: - { - return -RIG_ENIMPL; - } - - default: - rig_debug(RIG_DEBUG_ERR, - "%s: unsupported DCD type %d\n", - __func__, - p->type.dcd); - return -RIG_ENAVAIL; - } - return RIG_OK; } #endif +int cm108_set_bit(hamlib_port_t *p, enum GPIO gpio, int bit) +{ + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + ssize_t bytes; + char out_rep[] = + { + 0x00, // report number + // HID output report + 0x00, + bit ? (1 << (gpio - 1)) : 0, // set GPIO + 1 << (gpio - 1), // Data direction register (1=output) + 0x00 + }; + rig_debug(RIG_DEBUG_VERBOSE, "%s: out_rep = 0x%02x 0x%02x\n", __func__, + out_rep[2], out_rep[3]); + + // Build a packet for CM108 HID to turn GPIO bit on or off. + // Packet is 4 bytes, preceded by a 'report number' byte + // 0x00 report number + // Write data packet (from CM108 documentation) + // byte 0: 00xx xxxx Write GPIO + // byte 1: xxxx dcba GPIO3-0 output values (1=high) + // byte 2: xxxx dcba GPIO3-0 data-direction register (1=output) + // byte 3: xxxx xxxx SPDIF + + // Send the HID packet + bytes = write(p->fd, out_rep, sizeof(out_rep)); + + if (bytes < 0) + { + return -RIG_EIO; + } + + return RIG_OK; +} + +int cm108_get_bit(hamlib_port_t *p, enum GPIO gpio, int *bit) +{ + ssize_t bytes; + char reply[4]; + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + char in_rep[] = + { + 0x00, // report number + 0x01, // HID input report + 0x00, + 0x00 + }; + + // Send the HID packet + bytes = write(p->fd, in_rep, sizeof(in_rep)); + + if (bytes < 0) + { + return -RIG_EIO; + } + + bytes = read(p->fd, reply, sizeof(reply)); + + if (bytes <= 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: read error: %s\n", __func__, strerror(errno)); + return -RIG_EPROTO; + } + + int mask = 1 << (gpio - 1); + *bit = (reply[1] & mask) != 0; + rig_debug(RIG_DEBUG_VERBOSE, + "%s: mask=0x%02x, reply=0x%02x 0x%02x 0x%02x 0x%02x, bit=%d\n", __func__, mask, + reply[0], reply[1], reply[2], reply[3], *bit); + return RIG_OK; +} + +int rig_cm108_get_bit(hamlib_port_t *p, enum GPIO gpio, int *bit) +{ + if (gpio < 1 || gpio > 4) + { + rig_debug(RIG_DEBUG_ERR, "%s: gpio must be 1,2,3,4 for cm108\n", __func__); + return -RIG_EINVAL; + } + + cm108_get_bit(p, gpio, bit); + rig_debug(RIG_DEBUG_TRACE, "%s: gpio=%d bit=%d\n", __func__, gpio, *bit); + return RIG_OK; +} + + +int rig_cm108_set_bit(hamlib_port_t *p, enum GPIO gpio, int bit) +{ + if (gpio < 1 || gpio > 4) + { + rig_debug(RIG_DEBUG_ERR, "%s: gpio must be 1,2,3,4 for cm108\n", __func__); + return -RIG_EINVAL; + } + + int retval = cm108_set_bit(p, gpio, bit); + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: cm108_set_bit: %s\n", __func__, strerror(retval)); + return retval; + } + + rig_debug(RIG_DEBUG_TRACE, "%s: simulated gpio=%d bit=%d\n", __func__, gpio, + bit); + return RIG_OK; +} + + /** @} */ diff --git a/src/gpio.c b/src/gpio.c index 1b2602eee..e5fcfb597 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -189,4 +189,3 @@ int gpio_dcd_get(hamlib_port_t *port, dcd_t *dcdx) return RIG_OK; } - diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 1f1d1a0fd..90cfa9b19 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -267,6 +267,8 @@ declare_proto_rig(send_raw); declare_proto_rig(client_version); declare_proto_rig(hamlib_version); declare_proto_rig(test); +declare_proto_rig(cm108_get_bit); +declare_proto_rig(cm108_set_bit); /* @@ -384,6 +386,8 @@ static struct test_table test_list[] = { 0xa6, "get_vfo_list", ACTION(get_vfo_list), ARG_NOVFO }, { 0xa7, "test", ACTION(test), ARG_NOVFO | ARG_IN, "routine" }, { 0xa8, "hamlib_version", ACTION(hamlib_version), ARG_NOVFO }, + { 0xa9, "get_gpio", ACTION(cm108_get_bit), ARG_NOVFO | ARG_IN1 | ARG_OUT1, "GPIO#", "0/1" }, + { 0xaa, "set_gpio", ACTION(cm108_set_bit), ARG_NOVFO | ARG_IN , "GPIO#", "0/1" }, { 0x00, "", NULL }, }; @@ -5609,3 +5613,51 @@ declare_proto_rig(send_raw) return RIG_OK; } + +declare_proto_rig(cm108_get_bit) +{ + rig_debug(RIG_DEBUG_TRACE, "%s:\n", __func__); + + int gpio = -1; + int bit = -1; + // try GPIO format first + int n = sscanf(arg1,"GPIO%d", &gpio); + if (n == 0) + n = sscanf(arg1,"%d", &gpio); + if (n != 1) return -RIG_EINVAL; + int retval = rig_cm108_get_bit(&rig->state.pttport, gpio, &bit); + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: %s\n", __func__, strerror(retval)); + return retval; + } + rig_debug(RIG_DEBUG_TRACE, "%s: gpio=%d\n", __func__, gpio); + if ((interactive && prompt) || (interactive && !prompt && ext_resp)) + { + fprintf(fout, "%s: ", cmd->arg2); + } + fprintf(fout, "%d (simulated)\n", 1); + + + return RIG_OK; +} + +declare_proto_rig(cm108_set_bit) +{ + rig_debug(RIG_DEBUG_TRACE, "%s:\n", __func__); + int gpio, bit=-1; + // try GPIO format first + int n = sscanf(arg1,"GPIO%d", &gpio); + if (n == 0) + n = sscanf(arg1,"%d", &gpio); + if (n != 1) return -RIG_EINVAL; + n = sscanf(arg2, "%d", &bit); + if (n != 1) return -RIG_EINVAL; + rig_debug(RIG_DEBUG_TRACE, "%s: set gpio=%d, bit=%d\n", __func__, gpio, bit); + int retval = rig_cm108_set_bit(&rig->state.pttport, gpio, bit); + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: %s\n", __func__, strerror(retval)); + } + return retval; +}