From b7057c414fc43bb81fc0d01bc07f32d18bce8ab0 Mon Sep 17 00:00:00 2001 From: Jan Mulder Date: Wed, 5 Jul 2017 18:37:21 +0200 Subject: OSTC over BLE: take care of credits Handle credits. Do not just ask for maximum credits all the time as this will stop the download. Also do not let the credits go back to 0 (while this might work, this is not tested). Getting back the 0 credits stops the download, and even when it can be restarted, it is less efficient (and not needed). Notice also that it takes some time before a grant request is honoured. During testing I saw reception of up to 25 packets between request and grant. So a lower bound for the request of 32 packets seems resonable. One aspect the Telit/Stollmann TIO puzzeled me. Sections 4.1 and 4.2 both talk about credits, but my hyphothesis is that there are two credits counters in play. One for traffic either way. This commit only deals with credits granted by Subsurface to the OSTC to send data. Credits granted by the OSTC to allow Subsurface to send new commands is NOT part of this commit, and is seemingly not needed in our scenario. As we only send new commands to the OSTC when a previous one is finished (per HW's interface spec), the OSTC does not run out of credits to receive commands. Signed-off-by: Jan Mulder --- core/qt-ble.cpp | 66 +++++++++++++++++++++++++++++++++++---------------------- core/qt-ble.h | 2 ++ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/core/qt-ble.cpp b/core/qt-ble.cpp index 0ce52bc02..7afdf484b 100644 --- a/core/qt-ble.cpp +++ b/core/qt-ble.cpp @@ -30,6 +30,9 @@ static int debugCounter; #define IS_EON_STEEL(_d) same_string((_d)->product, "EON Steel") #define IS_G2(_d) same_string((_d)->product, "G2") +#define MAXIMAL_HW_CREDIT 255 +#define MINIMAL_HW_CREDIT 32 + extern "C" { void waitFor(int ms) { @@ -65,21 +68,24 @@ void BLEObject::characteristcStateChanged(const QLowEnergyCharacteristic &c, con { if (IS_HW(device)) { if (c.uuid() == hwAllCharacteristics[HW_OSTC_BLE_DATA_TX]) { + hw_credit--; receivedPackets.append(value); + if (hw_credit == MINIMAL_HW_CREDIT) + setHwCredit(MAXIMAL_HW_CREDIT - hw_credit); } else { qDebug() << "ignore packet from" << c.uuid() << value.toHex(); } } else { receivedPackets.append(value); } - //qDebug() << ".. incoming packet count" << receivedPackets.length(); } void BLEObject::characteristicWritten(const QLowEnergyCharacteristic &c, const QByteArray &value) { if (IS_HW(device)) { if (c.uuid() == hwAllCharacteristics[HW_OSTC_BLE_CREDITS_RX]) { - qDebug() << "HW_OSTC_BLE_CREDITS_RX confirmed" << c.uuid() << value.toHex(); + bool ok; + hw_credit += value.toHex().toInt(&ok, 16); isCharacteristicWritten = true; } } else { @@ -90,8 +96,6 @@ void BLEObject::characteristicWritten(const QLowEnergyCharacteristic &c, const Q void BLEObject::writeCompleted(const QLowEnergyDescriptor &d, const QByteArray &value) { - Q_UNUSED(value) - qDebug() << "BLE write completed on" << d.name() << d.value(); } @@ -188,7 +192,7 @@ dc_status_t BLEObject::read(void *data, size_t size, size_t *actual) int offset = 0; while (!receivedPackets.isEmpty()) { /* - * Yes, to while loops with same condition seems strange. The inner one + * Yes, two while loops with same condition seems strange. The inner one * does the real work, but it prevents the QtEventloop to do its thing. * As the incoming packets arrive based on signals and slots, that * stuff is not handeled during the inner loop. So, add a short waitFor @@ -220,6 +224,36 @@ we_are_done: return DC_STATUS_SUCCESS; } +dc_status_t BLEObject::setHwCredit(unsigned int c) +{ + /* The Terminal I/O client transmits initial UART credits to the server (see 6.5). + * + * Notice that we have to write to the characteristic here, and not to its + * descriptor as for the enabeling of notifications or indications. + * + * Futher notice that this function has the implicit effect of processing the + * event loop (due to waiting for the confirmation of the credit request). + * So, as characteristcStateChanged will be triggered, while receiving + * data from the OSTC, these are processed too. + */ + + QList list = preferredService()->characteristics(); + isCharacteristicWritten = false; + preferredService()->writeCharacteristic(list[HW_OSTC_BLE_CREDITS_RX], + QByteArray(1, c), + QLowEnergyService::WriteWithResponse); + + /* And wait for the answer*/ + int msec = BLE_TIMEOUT; + while (msec > 0 && !isCharacteristicWritten) { + waitFor(100); + msec -= 100; + }; + if (!isCharacteristicWritten) + return DC_STATUS_TIMEOUT; + return DC_STATUS_SUCCESS; +} + dc_status_t BLEObject::setupHwTerminalIo(QList allC) { /* This initalizes the Terminal I/O client as described in * http://www.telit.com/fileadmin/user_upload/products/Downloads/sr-rf/BlueMod/TIO_Implementation_Guide_r04.pdf @@ -252,26 +286,8 @@ dc_status_t BLEObject::setupHwTerminalIo(QList allC) d = allC[HW_OSTC_BLE_DATA_TX].descriptors().first(); preferredService()->writeDescriptor(d, QByteArray::fromHex("0100")); - /* The Terminal I/O client transmits initial UART credits to the server (see 6.5). - * - * Notice that we have to write to the characteristic here, and not to its - * descriptor as for the enabeling of notifications or indications. - */ - isCharacteristicWritten = false; - preferredService()->writeCharacteristic(allC[HW_OSTC_BLE_CREDITS_RX], - QByteArray(1, 255), - QLowEnergyService::WriteWithResponse); - - /* And give to OSTC some time to get initialized */ - int msec = BLE_TIMEOUT; - while (msec > 0 && !isCharacteristicWritten) { - waitFor(100); - msec -= 100; - }; - if (!isCharacteristicWritten) - return DC_STATUS_TIMEOUT; - - return DC_STATUS_SUCCESS; + /* The Terminal I/O client transmits initial UART credits to the server (see 6.5). */ + return setHwCredit(MAXIMAL_HW_CREDIT); } dc_status_t qt_ble_open(dc_custom_io_t *io, dc_context_t *context, const char *devaddr) diff --git a/core/qt-ble.h b/core/qt-ble.h index 7368b71cd..ad5dfda2b 100644 --- a/core/qt-ble.h +++ b/core/qt-ble.h @@ -32,6 +32,7 @@ public slots: void characteristicWritten(const QLowEnergyCharacteristic &c, const QByteArray &value); void writeCompleted(const QLowEnergyDescriptor &d, const QByteArray &value); dc_status_t setupHwTerminalIo(QList); + dc_status_t setHwCredit(unsigned int c); private: QVector services; @@ -39,6 +40,7 @@ private: QList receivedPackets; bool isCharacteristicWritten; dc_user_device_t *device; + unsigned int hw_credit = 0; QList hwAllCharacteristics = { "{00000001-0000-1000-8000-008025000000}", // HW_OSTC_BLE_DATA_RX -- cgit v1.2.3-70-g09d2