<commit_before>/* This file is part of the RayActor Lighting Software.
 *
 * RayActor is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * RayActor 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Rayactor. If not, see <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include <errno.h>
#include <stdbool.h>

#include <erl_driver.h>

#include <libusb.h>
#include <ftdi.h>
#include <poll.h>

#include "ftdi_drv.h"
#include "context.h"
#include "transfer.h"

#if !defined(LIBUSB_API_VERSION) || (LIBUSB_API_VERSION < 0x01000104)
#error "You need at least libusb version 1.0.20!"
#endif

static ErlDrvSSizeT ctrl_reply(uint8_t reply, char *buf, ErlDrvSizeT len,
                               char **rbuf, ErlDrvSizeT rlen)
{
    char *ptr;
    ErlDrvBinary *bin;

    if (len >= rlen) {
        if ((bin = driver_alloc_binary(len + 1)) == NULL)
            return -1;
        ptr = *rbuf = bin->orig_bytes;
    } else {
        ptr = *rbuf;
    }

    *ptr++ = reply;
    memcpy(ptr, buf, len);
    return len + 1;
}

static inline ErlDrvSSizeT ctrl_ok(char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_OK, NULL, 0, rbuf, rlen);
}

static inline ErlDrvSSizeT ctrl_ok_nodata(char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_OK_NODATA, NULL, 0, rbuf, rlen);
}

static inline ErlDrvSSizeT ctrl_error(char *err, char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_ERROR, err, strlen(err), rbuf, rlen);
}

static ErlDrvSSizeT ctrl_errno(char **rbuf, ErlDrvSizeT rlen)
{
    char *desc = erl_errno_id(errno);
    return ctrl_error(desc, rbuf, rlen);
}

static uint64_t add_device_ref(drv_ctx_t *ctx, struct libusb_device *dev)
{
    dev_rev_list_t *new, *iter;

    if ((new = driver_alloc(sizeof(dev_rev_list_t))) == NULL)
        return 0;

    libusb_ref_device(dev);
    new->device = dev;
    new->ref = (uint64_t)dev;
    new->next = NULL;

    if (ctx->devices == NULL) {
        ctx->devices = new;
    } else {
        for (iter = ctx->devices; iter->next != NULL; iter = iter->next);
        iter->next = new;
    }

    return new->ref;
}

static struct libusb_device *lookup_device_ref(drv_ctx_t *ctx, uint64_t ref)
{
    dev_rev_list_t *iter;

    iter = ctx->devices;
    while (iter != NULL) {
        if (iter->ref == ref)
            return iter->device;
        iter = iter->next;
    }

    return NULL;
}

static void free_device_refs(drv_ctx_t *ctx)
{
    dev_rev_list_t *next;

    while (ctx->devices != NULL) {
        libusb_unref_device(ctx->devices->device);
        next = ctx->devices->next;
        driver_free(ctx->devices);
        ctx->devices = next;
    }
}

static int poll_event_ctrl(drv_ctx_t *ctx, int fd, short events, int on)
{
    int mode;
    ErlDrvEvent event;

    mode = (events & POLLIN  ? ERL_DRV_READ  : 0)
         | (events & POLLOUT ? ERL_DRV_WRITE : 0);
    event = (ErlDrvEvent)(ErlDrvSInt)fd;

    return driver_select(ctx->port, event, mode, on);
}

static void LIBUSB_CALL add_poll_event(int fd, short events, void *drv_data)
{
    if (poll_event_ctrl((drv_ctx_t*)drv_data, fd, events, 1) != 0) {
        // TODO: error handling!
    }
}

static void LIBUSB_CALL del_poll_event(int fd, void *drv_data)
{
    if (poll_event_ctrl((drv_ctx_t*)drv_data, fd, POLLIN | POLLOUT, 0) != 0) {
        // TODO: error handling!
    }
}

static void handle_events(drv_ctx_t *ctx)
{
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 0;<commit_msg>ftdi_drv: Use boolean for (un)registering poll FDs<commit_after>/* This file is part of the RayActor Lighting Software.
 *
 * RayActor is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * RayActor 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Rayactor. If not, see <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include <errno.h>
#include <stdbool.h>

#include <erl_driver.h>

#include <libusb.h>
#include <ftdi.h>
#include <poll.h>

#include "ftdi_drv.h"
#include "context.h"
#include "transfer.h"

#if !defined(LIBUSB_API_VERSION) || (LIBUSB_API_VERSION < 0x01000104)
#error "You need at least libusb version 1.0.20!"
#endif

static ErlDrvSSizeT ctrl_reply(uint8_t reply, char *buf, ErlDrvSizeT len,
                               char **rbuf, ErlDrvSizeT rlen)
{
    char *ptr;
    ErlDrvBinary *bin;

    if (len >= rlen) {
        if ((bin = driver_alloc_binary(len + 1)) == NULL)
            return -1;
        ptr = *rbuf = bin->orig_bytes;
    } else {
        ptr = *rbuf;
    }

    *ptr++ = reply;
    memcpy(ptr, buf, len);
    return len + 1;
}

static inline ErlDrvSSizeT ctrl_ok(char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_OK, NULL, 0, rbuf, rlen);
}

static inline ErlDrvSSizeT ctrl_ok_nodata(char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_OK_NODATA, NULL, 0, rbuf, rlen);
}

static inline ErlDrvSSizeT ctrl_error(char *err, char **rbuf, ErlDrvSizeT rlen)
{
    return ctrl_reply(FTDI_DRV_CTRL_REPLY_ERROR, err, strlen(err), rbuf, rlen);
}

static ErlDrvSSizeT ctrl_errno(char **rbuf, ErlDrvSizeT rlen)
{
    char *desc = erl_errno_id(errno);
    return ctrl_error(desc, rbuf, rlen);
}

static uint64_t add_device_ref(drv_ctx_t *ctx, struct libusb_device *dev)
{
    dev_rev_list_t *new, *iter;

    if ((new = driver_alloc(sizeof(dev_rev_list_t))) == NULL)
        return 0;

    libusb_ref_device(dev);
    new->device = dev;
    new->ref = (uint64_t)dev;
    new->next = NULL;

    if (ctx->devices == NULL) {
        ctx->devices = new;
    } else {
        for (iter = ctx->devices; iter->next != NULL; iter = iter->next);
        iter->next = new;
    }

    return new->ref;
}

static struct libusb_device *lookup_device_ref(drv_ctx_t *ctx, uint64_t ref)
{
    dev_rev_list_t *iter;

    iter = ctx->devices;
    while (iter != NULL) {
        if (iter->ref == ref)
            return iter->device;
        iter = iter->next;
    }

    return NULL;
}

static void free_device_refs(drv_ctx_t *ctx)
{
    dev_rev_list_t *next;

    while (ctx->devices != NULL) {
        libusb_unref_device(ctx->devices->device);
        next = ctx->devices->next;
        driver_free(ctx->devices);
        ctx->devices = next;
    }
}

static int poll_event_ctrl(drv_ctx_t *ctx, int fd, short events, bool on)
{
    int mode;
    ErlDrvEvent event;

    mode = (events & POLLIN  ? ERL_DRV_READ  : 0)
         | (events & POLLOUT ? ERL_DRV_WRITE : 0);
    event = (ErlDrvEvent)(ErlDrvSInt)fd;

    return driver_select(ctx->port, event, mode, on ? 1 : 0);
}

static void LIBUSB_CALL add_poll_event(int fd, short events, void *drv_data)
{
    if (poll_event_ctrl((drv_ctx_t*)drv_data, fd, events, true) != 0) {
        // TODO: error handling!
    }
}

static void LIBUSB_CALL del_poll_event(int fd, void *drv_data)
{
    if (poll_event_ctrl((drv_ctx_t*)drv_data, fd,
                        POLLIN | POLLOUT, false) != 0) {
        // TODO: error handling!
    }
}

static void handle_events(drv_ctx_t *ctx)
{
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
{'fraction_non_alphanumeric': 0.11673981191222571, 'fraction_numerical': 0.00877742946708464, 'mean_word_length': 3.1476859074362973, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '207865', 'n_tokens_mistral': 2952, 'n_tokens_neox': 2868, 'n_words': 787}