Changeset 4f3a9cdb in subsurface


Ignore:
Timestamp:
Jun 26, 2017, 10:21:14 PM (4 weeks ago)
Author:
Dirk Hohndel <dirk@…>
Branches:
master
Children:
81dabe5
Parents:
d0c3ef4
git-author:
Linus Torvalds <torvalds@…> (06/26/17 20:03:09)
git-committer:
Dirk Hohndel <dirk@…> (06/26/17 22:21:14)
Message:

BT serial: recognize LE-only devices, and fall back to emulated serial

This is somewhat hacky, but it allows at least the Shearwater
libdivecomputer backend to continue to treat even the BLE GATT model as
just a serial protocol.

What it does is create a special "emulate serial behavior over the
packetized BLE protocol" helper layer, that qtserialbluetooth falls back
on when rfcomm is not available.

NOTE! This still requires some BLE packet code changes to work with the
odd way that Shearwater sets up their BLE GATT communication. So note
that no further patches are necessary to *libdivecomputer*, but some
updates are needed for the subsurface qt-ble.cpp code.

I have those updates in my tree, and this code is all tested on my
Perdix AI, but those patches are currently too ugly to commit as-is.
I've cleaned up this "fake serial" code sufficiently, that cleanup comes
next.

Signed-off-by: Linus Torvalds <torvalds@…>
Signed-off-by: Dirk Hohndel <dirk@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/qtserialbluetooth.cpp

    r196adb5 r4f3a9cdb  
    3838extern "C" {
    3939typedef struct qt_serial_t {
     40        dc_custom_io_t *ops;
    4041        /*
    4142         * RFCOMM socket used for Bluetooth Serial communication.
     
    4950} qt_serial_t;
    5051
     52#ifdef BLE_SUPPORT
     53
     54static dc_status_t ble_serial_open(void **userdata, const char* devaddr);
     55static dc_status_t ble_serial_close(void **userdata);
     56static dc_status_t ble_serial_read(void **userdata, void* data, size_t size, size_t *actual);
     57static dc_status_t ble_serial_write(void **userdata, const void* data, size_t size, size_t *actual);
     58static dc_status_t ble_serial_purge(void **userdata, dc_direction_t queue);
     59static dc_status_t ble_serial_get_available(void **userdata, size_t *available);
     60
     61static dc_custom_io_t ble_serial_ops = {
     62        .userdata = NULL,
     63
     64        .serial_open = ble_serial_open,
     65        .serial_close = ble_serial_close,
     66        .serial_read = ble_serial_read,
     67        .serial_write = ble_serial_write,
     68        .serial_purge = ble_serial_purge,
     69        .serial_get_available = ble_serial_get_available,
     70        .serial_set_timeout = NULL,     // the regular qt_set_timeout is fine
     71// These doesn't make sense over bluetooth
     72// NULL means NOP
     73        .serial_configure = NULL,
     74        .serial_set_dtr = NULL,
     75        .serial_set_rts = NULL,
     76        .serial_set_halfduplex = NULL,
     77        .serial_set_break = NULL,
     78
     79        .packet_size  = 20,
     80        .packet_open  = qt_ble_open,
     81        .packet_close = qt_ble_close,
     82        .packet_read  = qt_ble_read,
     83        .packet_write = qt_ble_write,
     84};
     85
     86static struct qt_serial_t serial_over_ble = {
     87        .ops = &ble_serial_ops,
     88};
     89
     90
     91static dc_status_t ble_serial_open(void **userdata, const char* devaddr)
     92{
     93        *userdata = &serial_over_ble;
     94        return qt_ble_open(&ble_serial_ops, NULL, devaddr);
     95}
     96
     97#define BUFSZ 1024
     98static struct {
     99        unsigned int out_bytes, in_bytes, in_pos;
     100        unsigned char in[BUFSIZ];
     101        unsigned char out[BUFSIZ];
     102} buffer;
     103
     104static dc_status_t ble_serial_flush_write(void)
     105{
     106        int bytes = buffer.out_bytes;
     107
     108        if (!bytes)
     109                return DC_STATUS_SUCCESS;
     110        buffer.out_bytes = 0;
     111        ble_serial_ops.packet_write(&ble_serial_ops, buffer.out, bytes, NULL);
     112}
     113
     114static dc_status_t ble_serial_flush_read(void)
     115{
     116        buffer.in_bytes = buffer.in_pos = 0;
     117        return DC_STATUS_SUCCESS;
     118}
     119
     120static dc_status_t ble_serial_close(void **userdata)
     121{
     122        ble_serial_flush_write();
     123        *userdata = NULL;
     124        return qt_ble_close(&ble_serial_ops);
     125}
     126
     127static dc_status_t ble_serial_read(void **userdata, void* data, size_t size, size_t *actual)
     128{
     129        int len;
     130
     131        if (buffer.in_pos >= buffer.in_bytes) {
     132                dc_status_t rc;
     133                size_t received;
     134
     135                ble_serial_flush_write();
     136                rc = ble_serial_ops.packet_read(&ble_serial_ops, buffer.in, sizeof(buffer.in), &received);
     137                if (rc != DC_STATUS_SUCCESS)
     138                        return rc;
     139                if (!received)
     140                        return DC_STATUS_IO;
     141                buffer.in_pos = 0;
     142                buffer.in_bytes = received;
     143        }
     144
     145        len = buffer.in_bytes - buffer.in_pos;
     146        if (len > size)
     147                len = size;
     148
     149        memcpy(data, buffer.in + buffer.in_pos, len);
     150        buffer.in_pos += len;
     151        if (actual)
     152                *actual = len;
     153        return DC_STATUS_SUCCESS;
     154}
     155
     156static dc_status_t ble_serial_write(void **userdata, const void* data, size_t size, size_t *actual)
     157{
     158        dc_status_t rc = DC_STATUS_SUCCESS;
     159        size_t transferred = 0;
     160
     161        ble_serial_flush_read();
     162        while (size) {
     163                int len = sizeof(buffer.out) - buffer.out_bytes;
     164
     165                if (len > size)
     166                        len = size;
     167                memcpy(buffer.out + buffer.out_bytes, data, len);
     168                buffer.out_bytes += len;
     169
     170                if (buffer.out_bytes == sizeof(buffer.out)) {
     171                        rc = ble_serial_flush_write();
     172                        if (rc != DC_STATUS_SUCCESS)
     173                                break;
     174                }
     175                transferred += len;
     176                data = (const void *) (len + (const char *)data);
     177                size -= len;
     178        }
     179        if (actual)
     180                *actual = transferred;
     181        return DC_STATUS_SUCCESS;
     182}
     183
     184static dc_status_t ble_serial_purge(void **userdata, dc_direction_t queue)
     185{
     186        /* Do we care? */
     187        return DC_STATUS_SUCCESS;
     188}
     189
     190static dc_status_t ble_serial_get_available(void **userdata, size_t *available)
     191{
     192        *available = buffer.in_bytes - buffer.in_pos;
     193        return DC_STATUS_SUCCESS;
     194}
     195
     196#endif
     197
     198
    51199
    52200static dc_status_t qt_serial_open(void **userdata, const char* devaddr)
    53201{
     202#ifdef BLE_SUPPORT
     203        if (!strncmp(devaddr, "LE:", 3))
     204                return ble_serial_open(userdata, devaddr);
     205#endif
     206
    54207        // Allocate memory.
    55208        qt_serial_t *serial_port = (qt_serial_t *) malloc (sizeof (qt_serial_t));
     
    57210                return DC_STATUS_NOMEMORY;
    58211        }
     212
     213        serial_port->ops = NULL;
    59214
    60215        // Default to blocking reads.
     
    206361                return DC_STATUS_SUCCESS;
    207362
     363        if (device && device->ops)
     364                return device->ops->serial_close(userdata);
     365
    208366#if defined(Q_OS_WIN)
    209367        // Cleanup
     
    230388{
    231389        qt_serial_t *device = (qt_serial_t*) *userdata;
     390
     391        if (device && device->ops)
     392                return device->ops->serial_read(userdata, data, size, actual);
    232393
    233394#if defined(Q_OS_WIN)
     
    292453        qt_serial_t *device = (qt_serial_t*) *userdata;
    293454
     455        if (device && device->ops)
     456                return device->ops->serial_write(userdata, data, size, actual);
     457
    294458#if defined(Q_OS_WIN)
    295459        if (device == NULL)
     
    337501}
    338502
    339 static dc_status_t qt_serial_flush(void **userdata, dc_direction_t queue)
     503static dc_status_t qt_serial_purge(void **userdata, dc_direction_t queue)
    340504{
    341505        qt_serial_t *device = (qt_serial_t*) *userdata;
     506
     507        if (device && device->ops)
     508                return device->ops->serial_purge(userdata, queue);
     509
    342510        (void)queue;
    343511        if (device == NULL)
     
    352520}
    353521
    354 static dc_status_t qt_serial_get_received(void **userdata, size_t *available)
     522static dc_status_t qt_serial_get_available(void **userdata, size_t *available)
    355523{
    356524        qt_serial_t *device = (qt_serial_t*) *userdata;
     525
     526        if (device && device->ops)
     527                return device->ops->serial_get_available(userdata, available);
     528
    357529#if defined(Q_OS_WIN)
    358530        if (device == NULL)
     
    410582        .serial_read = qt_serial_read,
    411583        .serial_write = qt_serial_write,
    412         .serial_purge = qt_serial_flush,
    413         .serial_get_available = qt_serial_get_received,
     584        .serial_purge = qt_serial_purge,
     585        .serial_get_available = qt_serial_get_available,
    414586        .serial_set_timeout = qt_serial_set_timeout,
    415587// These doesn't make sense over bluetooth
Note: See TracChangeset for help on using the changeset viewer.