/**
 * @brief   Notification of data inserted into the output queue.
 *
 * @param[in] qp        the queue pointer.
 */
static void onotify(io_queue_t *qp) {
  size_t n;
  SerialUSBDriver *sdup = qGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
      (sdup->state != SDU_READY)) {
    return;
  }

  /* If there is not an ongoing transaction and the output queue contains
     data then a new transaction is started.*/
  if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) {
    if ((n = oqGetFullI(&sdup->oqueue)) > 0U) {
      osalSysUnlock();

      usbPrepareQueuedTransmit(sdup->config->usbp,
                               sdup->config->bulk_in,
                               &sdup->oqueue, n);

      osalSysLock();
      (void) usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in);
    }
  }
}
Beispiel #2
0
static msg_t put(void *ip, uint8_t b) {
  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return MSG_RESET;
  }

  return obqPutTimeout(&((SerialUSBDriver *)ip)->obqueue, b, TIME_INFINITE);
}
Beispiel #3
0
/**
 * @brief   Notification of data removed from the input queue.
 */
static void inotify(GenericQueue *qp) {
  size_t n, maxsize;
  SerialUSBDriver *sdup = chQGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if (usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE)
    return;

  /* If there is in the queue enough space to hold at least one packet and
     a transaction is not yet started then a new transaction is started for
     the available space.*/
  maxsize = sdup->config->usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize;
  if (!usbGetReceiveStatusI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP) &&
      ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize)) {
    chSysUnlock();

    n = (n / maxsize) * maxsize;
    usbPrepareQueuedReceive(sdup->config->usbp,
                            USB_CDC_DATA_AVAILABLE_EP,
                            &sdup->iqueue, n);

    chSysLock();
    usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP);
  }
}
/**
 * @brief   Notification of data removed from the input queue.
 *
 * @param[in] qp        the queue pointer.
 */
static void inotify(io_queue_t *qp) {
  size_t n, maxsize;
  SerialUSBDriver *sdup = qGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
      (sdup->state != SDU_READY)) {
    return;
  }

  /* If there is in the queue enough space to hold at least one packet and
     a transaction is not yet started then a new transaction is started for
     the available space.*/
  maxsize = sdup->config->usbp->epc[sdup->config->bulk_out]->out_maxsize;
  if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->bulk_out)) {
    if ((n = iqGetEmptyI(&sdup->iqueue)) >= maxsize) {
      osalSysUnlock();

      n = (n / maxsize) * maxsize;
      usbPrepareQueuedReceive(sdup->config->usbp,
                              sdup->config->bulk_out,
                              &sdup->iqueue, n);

      osalSysLock();
      (void) usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out);
    }
  }
}
Beispiel #5
0
/**
 * @brief   SOF handler.
 * @details The SOF interrupt is used for automatic flushing of incomplete
 *          buffers pending in the output queue.
 *
 * @param[in] sdup      pointer to a @p SerialUSBDriver object
 *
 * @iclass
 */
void sduSOFHookI(SerialUSBDriver *sdup) {

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
      (sdup->state != SDU_READY)) {
    return;
  }

  /* If there is already a transaction ongoing then another one cannot be
     started.*/
  if (usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) {
    return;
  }

  /* Checking if there only a buffer partially filled, if so then it is
     enforced in the queue and transmitted.*/
  if (obqTryFlushI(&sdup->obqueue)) {
    size_t n;
    uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n);

    osalDbgAssert(buf != NULL, "queue is empty");

    usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n);
  }
}
Beispiel #6
0
/**
 * @brief   Notification of data removed from the input queue.
 */
static void inotify(GenericQueue *qp) {
  size_t n, maxsize;
  BulkUSBDriver *bdup = chQGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(bdup->config->usbp) != USB_ACTIVE) ||
      (bdup->state != BDU_READY))
    return;

  /* If there is in the queue enough space to hold at least one packet and
     a transaction is not yet started then a new transaction is started for
     the available space.*/
  maxsize = bdup->config->usbp->epc[bdup->config->bulk_out]->out_maxsize;
  if (!usbGetReceiveStatusI(bdup->config->usbp, bdup->config->bulk_out) &&
      ((n = chIQGetEmptyI(&bdup->iqueue)) >= maxsize)) {
    chSysUnlock();

    n = (n / maxsize) * maxsize;
    usbPrepareQueuedReceive(bdup->config->usbp,
                            bdup->config->bulk_out,
                            &bdup->iqueue, n);

    chSysLock();
    usbStartReceiveI(bdup->config->usbp, bdup->config->bulk_out);
  }
}
/**
 * @brief   Notification of data inserted into the output queue.
 *
 * @param[in] qp        the queue pointer.
 */
static void onotify(io_queue_t *qp) {
  size_t n;
  HIDDebugDriver *hiddp = qGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
   * must not be started.*/
  if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) ||
     (hiddp->state != HIDDEBUG_READY)) {
    return;
  }

  /* If there is not an ongoing transaction and the output queue contains
   * enough data then a new transaction is started.*/
  if(!usbGetTransmitStatusI(hiddp->config->usbp, hiddp->config->ep_in)) {
    if((n = oqGetFullI(&hiddp->oqueue)) >= DEBUG_TX_SIZE) {
      osalSysUnlock();

      usbPrepareQueuedTransmit(hiddp->config->usbp,
                               hiddp->config->ep_in,
                               &hiddp->oqueue, DEBUG_TX_SIZE);

      osalSysLock();
      (void)usbStartTransmitI(hiddp->config->usbp, hiddp->config->ep_in);
    }
  }
}
void usb_debug_flush_output(HIDDebugDriver *hiddp) {
  size_t n;

  /* we'll sleep for a moment to finish any transfers that may be pending already */
  /* there's a race condition somewhere, maybe because we have 2x buffer */
  chThdSleepMilliseconds(2);
  osalSysLock();
  /* check that the states of things are as they're supposed to */
  if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) ||
     (hiddp->state != HIDDEBUG_READY)) {
    osalSysUnlock();
    return;
  }

  /* rearm the timer */
  chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp);

  /* don't do anything if the queue is empty */
  if((n = oqGetFullI(&hiddp->oqueue)) == 0) {
    osalSysUnlock();
    return;
  }

  osalSysUnlock();
  /* if we don't have enough bytes in the queue, fill with zeroes */
  while(n++ < DEBUG_TX_SIZE) {
    oqPut(&hiddp->oqueue, 0);
  }
  /* will transmit automatically because of the onotify callback */
  /* which transmits as soon as the queue has enough */
}
Beispiel #9
0
static msg_t get(void *ip) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return MSG_RESET;
  }

  return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, TIME_INFINITE);
}
Beispiel #10
0
static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return 0;
  }

  return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp, n, timeout);
}
Beispiel #11
0
static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return 0;
  }

  return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp, n, timeout);
}
Beispiel #12
0
static msg_t gett(void *ip, systime_t timeout) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return MSG_RESET;
  }

  return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, timeout);
}
Beispiel #13
0
static msg_t putt(void *ip, uint8_t b, systime_t timeout) {

  if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return MSG_RESET;
  }

  return obqPutTimeout(&((USBHIDDriver *)ip)->obqueue, b, timeout);
}
Beispiel #14
0
static size_t read(void *ip, uint8_t *bp, size_t n) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return 0;
  }

  return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp,
                        n, TIME_INFINITE);
}
Beispiel #15
0
static size_t write(void *ip, const uint8_t *bp, size_t n) {

  if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) {
    return 0;
  }

  return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp,
                         n, TIME_INFINITE);
}
Beispiel #16
0
void LogTextMessage(const char* format, ...) {
  if ((usbGetDriverStateI(BDU1.config->usbp) == USB_ACTIVE) && (connected)) {
    int h = 0x546F7841; // "AxoT"
    chSequentialStreamWrite((BaseSequentialStream * )&BDU1,
                            (const unsigned char* )&h, 4);

    va_list ap;
    va_start(ap, format);
    chvprintf((BaseSequentialStream *)&BDU1, format, ap);
    va_end(ap);
    chSequentialStreamPut((BaseSequentialStream * )&BDU1, 0);
  }
}
Beispiel #17
0
static void send_extra_report(uint8_t report_id, uint16_t data) {
  osalSysLock();
  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
    osalSysUnlock();
    return;
  }

  report_extra_t report = {
    .report_id = report_id,
    .usage = data
  };

  usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
  osalSysUnlock();
}
Beispiel #18
0
/**
 * @brief   Performs a transmit transaction on an IN endpoint.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 * @param[in] buf       buffer where to fetch the data to be transmitted
 * @param[in] n         transaction size
 *
 * @return              The operation status.
 * @retval MSG_OK       operation performed successfully.
 * @retval MSG_RESET    driver not in @p USB_ACTIVE state or the operation
 *                      has been aborted by an USB reset or a transition to
 *                      the @p USB_SUSPENDED state.
 *
 * @api
 */
msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) {
  msg_t msg;

  osalSysLock();

  if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
    osalSysUnlock();
    return MSG_RESET;
  }

  usbStartTransmitI(usbp, ep, buf, n);
  msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread);
  osalSysUnlock();

  return msg;
}
Beispiel #19
0
/**
 * @brief   Notification of filled buffer inserted into the output buffers queue.
 *
 * @param[in] bqp       the buffers queue pointer.
 */
static void obnotify(io_buffers_queue_t *bqp) {
  size_t n;
  SerialUSBDriver *sdup = bqGetLinkX(bqp);
  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
      (sdup->state != SDU_READY)) {
    return;
  }
  /* Checking if there is already a transaction ongoing on the endpoint.*/
  if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) {
    /* Trying to get a full buffer.*/
    uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n);
    if (buf != NULL) {
      /* Buffer found, starting a new transaction.*/
      usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n);
    }
  }
}
Beispiel #20
0
static THD_FUNCTION(serialThread, arg) {
    (void)arg;
    event_listener_t new_data_listener;
    event_listener_t sd1_listener;
    event_listener_t sd2_listener;
    chEvtRegister(&new_data_event, &new_data_listener, 0);
    eventflags_t events = CHN_INPUT_AVAILABLE
            | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED;
    chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1),
        &sd1_listener,
        EVENT_MASK(1),
        events);
    chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2),
        &sd2_listener,
        EVENT_MASK(2),
        events);
    bool need_wait = false;
    while(true) {
        eventflags_t flags1 = 0;
        eventflags_t flags2 = 0;
        if (need_wait) {
            eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
            if (mask & EVENT_MASK(1)) {
                flags1 = chEvtGetAndClearFlags(&sd1_listener);
                print_error("DOWNLINK", flags1, &SD1);
            }
            if (mask & EVENT_MASK(2)) {
                flags2 = chEvtGetAndClearFlags(&sd2_listener);
                print_error("UPLINK", flags2, &SD2);
            }
        }

        // Always stay as master, even if the USB goes into sleep mode
        is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE;
        router_set_master(is_master);

        need_wait = true;
        need_wait &= read_from_serial(&SD2, UP_LINK) == 0;
        need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0;
        update_transport();
    }
}
Beispiel #21
0
void send_mouse(report_mouse_t *report) {
  osalSysLock();
  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
    osalSysUnlock();
    return;
  }

  if(usbGetTransmitStatusI(&USB_DRIVER, MOUSE_IN_EPNUM)) {
    /* Need to either suspend, or loop and call unlock/lock during
     * every iteration - otherwise the system will remain locked,
     * no interrupts served, so USB not going through as well.
     * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
    if (osalThreadSuspendTimeoutS(&(&USB_DRIVER)->epc[MOUSE_IN_EPNUM]->in_state->thread, MS2ST(10)==MSG_TIMEOUT)) {
      osalSysUnlock();
      return;
    }
  }
  usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t));
  osalSysUnlock();
}
Beispiel #22
0
static THD_FUNCTION(buttonThread, arg) {
  (void)arg;

  wkup_old_state = 0;

  while(1) {
    wkup_cur_state = palReadPad(GPIOA, GPIOA_BUTTON);
    if(wkup_cur_state != wkup_old_state) {
      chSysLock();
      if(usbGetDriverStateI(&USBD1) == USB_ACTIVE) {
        chSysUnlock();
        chnWrite((BaseChannel *)&HIDD, (uint8_t *)"Hello, world!\n", 14);
      } else
        chSysUnlock();

      wkup_old_state = wkup_cur_state;
    }
    chThdSleepMilliseconds(50);
  }
}
Beispiel #23
0
/**
 * @brief   Notification of empty buffer released into the input buffers queue.
 *
 * @param[in] bqp       the buffers queue pointer.
 */
static void ibnotify(io_buffers_queue_t *bqp) {
  SerialUSBDriver *sdup = bqGetLinkX(bqp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
      (sdup->state != SDU_READY)) {
    return;
  }

  /* Checking if there is already a transaction ongoing on the endpoint.*/
  if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->bulk_out)) {
    /* Trying to get a free buffer.*/
    uint8_t *buf = ibqGetEmptyBufferI(&sdup->ibqueue);
    if (buf != NULL) {
      /* Buffer found, starting a new transaction.*/
      usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out,
                       buf, SERIAL_USB_BUFFERS_SIZE);
    }
  }
}
/* callback */
static void hid_debug_flush_cb(void *arg) {
  HIDDebugDriver *hiddp = (HIDDebugDriver *)arg;
  size_t i, n;
  uint8_t buf[DEBUG_TX_SIZE];

  osalSysLockFromISR();

  /* check that the states of things are as they're supposed to */
  if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) ||
     (hiddp->state != HIDDEBUG_READY)) {
    /* rearm the timer */
    chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp);
    osalSysUnlockFromISR();
    return;
  }

  /* don't do anything if the queue or has enough stuff in it */
  if(((n = oqGetFullI(&hiddp->oqueue)) == 0) || (n >= DEBUG_TX_SIZE)) {
    /* rearm the timer */
    chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp);
    osalSysUnlockFromISR();
    return;
  }

  /* there's stuff hanging in the queue - so dequeue and send */
  for(i = 0; i < n; i++)
    buf[i] = (uint8_t)oqGetI(&hiddp->oqueue);
  for(i = n; i < DEBUG_TX_SIZE; i++)
    buf[i] = 0;
  osalSysUnlockFromISR();
  usbPrepareTransmit(hiddp->config->usbp, hiddp->config->ep_in, buf, DEBUG_TX_SIZE);
  osalSysLockFromISR();
  (void)usbStartTransmitI(hiddp->config->usbp, hiddp->config->ep_in);

  /* rearm the timer */
  chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp);
  osalSysUnlockFromISR();
}
Beispiel #25
0
/**
 * @brief   Notification of data inserted into the output queue.
 */
static void onotify(GenericQueue *qp) {
  size_t n;
  SerialUSBDriver *sdup = chQGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if (usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE)
    return;

  /* If there is not an ongoing transaction and the output queue contains
     data then a new transaction is started.*/
  if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP) &&
      ((n = chOQGetFullI(&sdup->oqueue)) > 0)) {
    chSysUnlock();

    usbPrepareQueuedTransmit(sdup->config->usbp,
                             USB_CDC_DATA_REQUEST_EP,
                             &sdup->oqueue, n);

    chSysLock();
    usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP);
  }
}
Beispiel #26
0
/**
 * @brief   Notification of data inserted into the output queue.
 */
static void onotify(GenericQueue *qp) {
  size_t n;
  BulkUSBDriver *bdup = chQGetLink(qp);

  /* If the USB driver is not in the appropriate state then transactions
     must not be started.*/
  if ((usbGetDriverStateI(bdup->config->usbp) != USB_ACTIVE) ||
      (bdup->state != BDU_READY))
    return;

  /* If there is not an ongoing transaction and the output queue contains
     data then a new transaction is started.*/
  if (!usbGetTransmitStatusI(bdup->config->usbp, bdup->config->bulk_in) &&
      ((n = chOQGetFullI(&bdup->oqueue)) > 0)) {
    chSysUnlock();

    usbPrepareQueuedTransmit(bdup->config->usbp,
                             bdup->config->bulk_in,
                             &bdup->oqueue, n);

    chSysLock();
    usbStartTransmitI(bdup->config->usbp, bdup->config->bulk_in);
  }
}
Beispiel #27
0
static THD_FUNCTION(buttonThread, arg) {
  (void)arg;

  wkup_old_state = 0;

  while(1) {
    wkup_cur_state = palReadPad(BUTTON_GPIO, BUTTON_PIN);
    if(wkup_cur_state != wkup_old_state) {
      chSysLock();
      if(usbGetDriverStateI(&USB_DRIVER) == USB_ACTIVE) {
        chSysUnlock();
        /* just some test code for various reports
         * choose one and comment the others
         */

        /* keyboard test, sends 'n' in nkro mode, 'm' in normal mode */
#ifdef NKRO_ENABLE
        if(wkup_cur_state == BUTTON_ACTIVE) {
          report.nkro.bits[2] |= 2; // 'n'
        } else {
          report.nkro.bits[2] &= 0b11111101;
        }
#else
        report.keys[0] = ((wkup_cur_state == BUTTON_ACTIVE) ? 0x10 : 0); // 'm'
#endif
        send_keyboard(&report);

        /* mouse test, moves the mouse pointer diagonally right and down */
        // send_mouse(&mouse_report);

        /* consumer keys test, sends 'mute audio' */
        // if(wkup_cur_state == BUTTON_ACTIVE) {
        //   send_consumer(AUDIO_MUTE);
        // } else {
        //   send_consumer(0);
        // }

        /* system keys test, sends 'sleep key'
         * on macs it takes a second or two for the system to react
         * I suppose it's to prevent from accidental hits of the sleep key
         */
        // if(wkup_cur_state == BUTTON_ACTIVE) {
        //   send_system(SYSTEM_SLEEP);
        // } else {
        //   send_system(0);
        // }

        /* debug console test, sends the button state and the alphabet
         *  - also blink, to see that the code above is not blocking
         */
        // sendchar(((wkup_cur_state == BUTTON_ACTIVE) ? '1' : '0'));
        // uint8_t n;
        // for(n = 0; n < 26; n++) {
        //   sendchar('A' + n);
        //   sendchar('a' + n);
        // }
        // sendchar('\n');
        // palSetPad(LED2_GPIO, LED2_PIN);
        // chThdSleepMilliseconds(50);
        // palClearPad(LED2_GPIO, LED2_PIN);
      } else
        chSysUnlock();

      wkup_old_state = wkup_cur_state;
    }
    chThdSleepMilliseconds(50);
  }
}
Beispiel #28
0
/* Idle requests timer code
 * callback (called from ISR, unlocked state) */
static void keyboard_idle_timer_cb(void *arg) {
  USBDriver *usbp = (USBDriver *)arg;

  osalSysLockFromISR();

  /* check that the states of things are as they're supposed to */
  if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
    /* do not rearm the timer, should be enabled on IDLE request */
    osalSysUnlockFromISR();
    return;
  }

#ifdef NKRO_ENABLE
  if(!keymap_config.nkro && keyboard_idle) {
#else /* NKRO_ENABLE */
  if(keyboard_idle) {
#endif /* NKRO_ENABLE */
    /* TODO: are we sure we want the KBD_ENDPOINT? */
    if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
      usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE);
    }
    /* rearm the timer */
    chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
  }

  /* do not rearm the timer if the condition above fails
   * it should be enabled again on either IDLE or SET_PROTOCOL requests */
  osalSysUnlockFromISR();
}

/* LED status */
uint8_t keyboard_leds(void) {
  return (uint8_t)(keyboard_led_stats & 0xFF);
}

/* prepare and start sending a report IN
 * not callable from ISR or locked state */
void send_keyboard(report_keyboard_t *report) {
  osalSysLock();
  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
    osalSysUnlock();
    return;
  }
  osalSysUnlock();

#ifdef NKRO_ENABLE
  if(keymap_config.nkro) {  /* NKRO protocol */
    /* need to wait until the previous packet has made it through */
    /* can rewrite this using the synchronous API, then would wait
     * until *after* the packet has been transmitted. I think
     * this is more efficient */
    /* busy wait, should be short and not very common */
    osalSysLock();
    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) {
      /* Need to either suspend, or loop and call unlock/lock during
       * every iteration - otherwise the system will remain locked,
       * no interrupts served, so USB not going through as well.
       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread);
    }
    usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t));
    osalSysUnlock();
  } else
#endif /* NKRO_ENABLE */
  { /* boot protocol */
    /* need to wait until the previous packet has made it through */
    /* busy wait, should be short and not very common */
    osalSysLock();
    if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) {
      /* Need to either suspend, or loop and call unlock/lock during
       * every iteration - otherwise the system will remain locked,
       * no interrupts served, so USB not going through as well.
       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
      osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
    }
    usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE);
    osalSysUnlock();
  }
  keyboard_report_sent = *report;
}