/* * Copyright (C) 2023 Bernd Herzog * * This file is part of PortaPack. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include "usb_serial_io.h" #include "usb_serial_endpoints.h" #pragma GCC diagnostic push // external code, so ignore warnings #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include #include #include #include #include #pragma GCC diagnostic pop #include #include SerialUSBDriver SUSBD1; void bulk_out_receive(void) { int ret; do { ret = usb_transfer_schedule( &usb_endpoint_bulk_out, &usb_endpoint_bulk_out.buffer[0], 32, serial_bulk_transfer_complete, NULL); } while (ret != -1); } void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) { (void)user_data; chSysLockFromIsr(); for (unsigned int i = 0; i < bytes_transferred; i++) { msg_t ret; do { ret = chIQPutI(&SUSBD1.iqueue, usb_endpoint_bulk_out.buffer[i]); if (ret == Q_FULL) chThdSleepMilliseconds(1); } while (ret == Q_FULL); } chSysUnlockFromIsr(); } static void onotify(GenericQueue* qp) { SerialUSBDriver* sdp = chQGetLink(qp); uint8_t buff[64]; int n = chOQGetFullI(&sdp->oqueue); if (n > 64) n = 64; // don't overflow if (n > 0) { for (int i = 0; i < n; i++) { buff[i] = chOQGetI(&sdp->oqueue); } int ret; chSysUnlock(); do { ret = usb_transfer_schedule( &usb_endpoint_bulk_in, &buff[0], n, NULL, NULL); if (ret == -1) chThdSleepMilliseconds(1); } while (ret == -1); chSysLock(); } } static size_t write(void* ip, const uint8_t* bp, size_t n) { return chOQWriteTimeout(&((SerialUSBDriver*)ip)->oqueue, bp, n, TIME_INFINITE); } static size_t read(void* ip, uint8_t* bp, size_t n) { return chIQReadTimeout(&((SerialUSBDriver*)ip)->iqueue, bp, n, TIME_INFINITE); } static msg_t put(void* ip, uint8_t b) { return chOQPutTimeout(&((SerialUSBDriver*)ip)->oqueue, b, TIME_INFINITE); } static msg_t get(void* ip) { return chIQGetTimeout(&((SerialUSBDriver*)ip)->iqueue, TIME_INFINITE); } static msg_t putt(void* ip, uint8_t b, systime_t timeout) { return chOQPutTimeout(&((SerialUSBDriver*)ip)->oqueue, b, timeout); } static msg_t gett(void* ip, systime_t timeout) { return chIQGetTimeout(&((SerialUSBDriver*)ip)->iqueue, timeout); } static size_t writet(void* ip, const uint8_t* bp, size_t n, systime_t time) { return chOQWriteTimeout(&((SerialUSBDriver*)ip)->oqueue, bp, n, time); } static size_t readt(void* ip, uint8_t* bp, size_t n, systime_t time) { return chIQReadTimeout(&((SerialUSBDriver*)ip)->iqueue, bp, n, time); } static const struct SerialUSBDriverVMT vmt = { write, read, put, get, putt, gett, writet, readt}; void init_serial_usb_driver(SerialUSBDriver* sdp) { sdp->vmt = &vmt; chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, NULL, sdp); chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); }