diff --git a/bindings/python/test_Hamlib_Rig_class.py b/bindings/python/test_Hamlib_Rig_class.py index 3f60f0ce6..83387836f 100755 --- a/bindings/python/test_Hamlib_Rig_class.py +++ b/bindings/python/test_Hamlib_Rig_class.py @@ -70,6 +70,7 @@ class TestClass: 'scan', 'send_dtmf', 'send_morse', +'send_raw', 'set_ant', 'set_bank', 'set_channel', diff --git a/bindings/python/test_rig.py b/bindings/python/test_rig.py index 5c0c305ec..ee3c28e31 100755 --- a/bindings/python/test_rig.py +++ b/bindings/python/test_rig.py @@ -190,6 +190,23 @@ class TestClass: assert rig.set_spectrum_callback(None) is None + def do_test_send_raw(self, rig): + """rig_send_raw() tests""" + + # When using the Dummy driver, rig.c replies with a copy of the data + test_string_1 = "test string 012\n" + test_string_2 = test_string_1 * 2 + assert rig.send_raw(test_string_1) == test_string_1 + assert rig.send_raw(test_string_2, "\n") == test_string_1 + assert rig.send_raw(test_string_2, bytes([10])) == test_string_1 + + test_bytes_1 = bytes("test bytes\x00\x01\x02", "ASCII") + test_bytes_2 = test_bytes_1 * 2 + assert rig.send_raw(test_bytes_1) == test_bytes_1 + assert rig.send_raw(test_bytes_1, "s") == b"tes" + assert rig.send_raw(test_bytes_2, b"\x02") == test_bytes_1 + + def test_with_open(self, model, rig_file, serial_speed): """Call all the methods that depend on open()""" rig = Hamlib.Rig(model) @@ -211,6 +228,9 @@ class TestClass: self.do_test_antenna(rig) self.do_test_squelch(rig) self.do_test_callback(rig) + # When using the Dummy driver, rig.c replies with a copy of the data + if model == Hamlib.RIG_MODEL_DUMMY: + self.do_test_send_raw(rig) assert rig.close() is None assert rig.state.comm_state == 0 diff --git a/bindings/rig.swg b/bindings/rig.swg index a062bcfef..7d577afc3 100644 --- a/bindings/rig.swg +++ b/bindings/rig.swg @@ -735,6 +735,48 @@ int *rig_spectrum_cb_python(RIG *rig, struct rig_spectrum_line *rig_spectrum_lin return status; } +#ifdef SWIGPYTHON + PyObject *send_raw(PyObject *send_obj, PyObject *term_obj=NULL) + { + char *send, *term; + size_t send_len; + int reply_len = MAX_RETURNSTR; + unsigned char reply_buffer[MAX_RETURNSTR]; + int count; + + if (PyUnicode_Check(send_obj)) { + send = PyUnicode_AsUTF8AndSize(send_obj, &send_len); + } else if (PyBytes_Check(send_obj)) { + PyBytes_AsStringAndSize(send_obj, &send, &send_len); + } else { + SWIG_Python_RaiseOrModifyTypeError("Expected string or bytes for send argument"); + return NULL; + } + + // Using NULL for length in PyUnicode_AsUTF8AndSize() and PyBytes_AsStringAndSize() + // because we can't accept '\0' because there is no length for term in rig_send_raw() + if (PyUnicode_Check(term_obj)) { + term = PyUnicode_AsUTF8AndSize(term_obj, NULL); + } else if (PyBytes_Check(term_obj)) { + PyBytes_AsStringAndSize(term_obj, &term, NULL); + } else if (term_obj == Py_None) { + term = NULL; + } else { + SWIG_Python_RaiseOrModifyTypeError("Expected string or bytes or NULL for term argument"); + return NULL; + } + + count = rig_send_raw(self->rig, send, send_len, reply_buffer, reply_len, term); + self->error_status = count < 0 ? count : RIG_OK; + + if (PyUnicode_Check(send_obj)) { + return PyUnicode_FromStringAndSize(reply_buffer, count); + } else { + return PyBytes_FromStringAndSize(reply_buffer, count); + } + } +#endif + //#ifndef SWIGJAVA /* TODO */ void get_level(setting_t level, vfo_t vfo = RIG_VFO_CURR) diff --git a/rigs/tentec/orion.c b/rigs/tentec/orion.c index c2c30d31f..eb635863c 100644 --- a/rigs/tentec/orion.c +++ b/rigs/tentec/orion.c @@ -228,7 +228,7 @@ static int tt565_transaction(RIG *rig, const char *cmd, int cmd_len, char *data, } /** - * \param rig + * \param rig The rig handle * \returns RIG_OK or < 0 * \brief Basically, it just sets up *priv */ @@ -257,7 +257,7 @@ int tt565_close(RIG *rig) } /** - * \param rig + * \param rig The rig handle * \brief tt565_cleanup routine * * the serial port is closed by the frontend @@ -309,7 +309,7 @@ static void start_thread(RIG *rig) } /** - * \param rig + * \param rig The rig handle * \brief tt565_open routine * * Open the rig - check firmware version issues @@ -342,7 +342,7 @@ int tt565_open(RIG *rig) } /** - * \param rig + * \param rig The rig handle * \param vfo RIG_VFO_MAIN or RIG_VFO_SUB * \returns 'M' or 'S' for main or subreceiver or <0 error * \brief vfo must be RIG_VFO_MAIN or RIG_VFO_SUB @@ -375,7 +375,7 @@ static char which_receiver(const RIG *rig, vfo_t vfo) } } /** - * \param rig + * \param rig The rig handle * \param vfo RIG_VFO_A, RIG_VFO_B, or RIG_VFO_NONE * \returns 'A' or 'B' or 'N' for VFO A, B, or null VFO, or <0 error * \brief vfo must be RIG_VFO_A, RIG_VFO_B, or RIG_VFO_NONE. @@ -1972,7 +1972,7 @@ int tt565_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op) } /** - * \param rig + * \param rig The rig handle * \param vfo * \param msg A message string (<= 20 char) * \returns RIG_OK diff --git a/src/ext.c b/src/ext.c index 710748d4b..7236f1d79 100644 --- a/src/ext.c +++ b/src/ext.c @@ -218,7 +218,7 @@ int HAMLIB_API rig_ext_parm_foreach(RIG *rig, /** - * \param rig + * \param rig The rig handle * \param name * \brief lookup ext token by its name, return pointer to confparams struct. * @@ -267,7 +267,7 @@ const struct confparams *HAMLIB_API rig_ext_lookup(RIG *rig, const char *name) } /** - * \param rig + * \param rig The rig handle * \param token * \brief lookup ext token, return pointer to confparams struct. * @@ -316,7 +316,7 @@ const struct confparams *HAMLIB_API rig_ext_lookup_tok(RIG *rig, /** - * \param rig + * \param rig The rig handle * \param name * \brief Simple lookup returning token id associated with name */ diff --git a/src/misc.c b/src/misc.c index 1e3e3665b..8d448d2a2 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1031,7 +1031,7 @@ static const struct /** * \brief check input to set_level - * \param rig Pointer to rig data + * \param rig The rig handle * \param level RIG_LEVEL_* trying to set * \param val Raw input from the caller * \param gran If not NULL, set to location of level_gran data diff --git a/src/rig.c b/src/rig.c index 8e0ca4e00..4807011db 100644 --- a/src/rig.c +++ b/src/rig.c @@ -8887,9 +8887,23 @@ extern int read_icom_frame(hamlib_port_t *p, const unsigned char rxbuffer[], size_t rxbuffer_len); -// Returns # of bytes read -// reply_len should be max bytes expected + 1 -// if term is null then will read reply_len bytes exactly and reply will not be null terminated +/** + * \brief Send verbatim data + * + * \a reply_len should be max bytes expected + 1 + * + * If \a term is NULL then will read \a reply_len bytes exactly and reply will not be '\0' terminated. + * \param rig The rig handle + * \param send The buffer containing the data to be sent + * \param send_len The length of send buffer + * \param reply The buffer that will contain the data to be received + * \param reply_len The length of the reply buffer + * \param term The optional 1-char string that will terminate the read + * + * \return the number of bytes read if the operation has been successful, otherwise + * a negative value if an error occurred (in which case, cause is + * set appropriately). + */ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, int send_len, unsigned char *reply, int reply_len, unsigned char *term) { @@ -8909,12 +8923,9 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, if (simulate) { - rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", - __func__, rig->caps->model_name); - memcpy(reply, send, send_len); - retval = send_len; - ELAPSED2; - RETURNFUNC(retval); + rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating write for model %s\n", + __func__, rig->caps->model_name); + retval = RIG_OK; } else { @@ -8935,8 +8946,18 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, if (simulate) { // Simulate a response by copying the command - memcpy(buf, send, send_len); - nbytes = send_len + 1; + rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", + __func__, rig->caps->model_name); + + nbytes = send_len < reply_len ? send_len : reply_len; + for (int i = 0; i < nbytes; i++) + { + buf[i] = send[i]; + if (term && memchr(term, send[i], 1)) { + nbytes = i + 1; + break; + } + } } else {