static THD_FUNCTION(spi_thread, p) { unsigned i; SPIDriver *spip = (SPIDriver *)p; virtual_timer_t vt; uint8_t txbuf[256]; uint8_t rxbuf[256]; chRegSetThreadName("SPI overlord"); chVTObjectInit(&vt); /* Prepare transmit pattern.*/ for (i = 0; i < sizeof(txbuf); i++) txbuf[i] = (uint8_t)i; /* Continuous transmission.*/ while (true) { /* Starts a VT working as watchdog to catch a malfunction in the SPI driver.*/ chVTSet(&vt, MS2ST(10), tmo, (void *)"SPI timeout"); spiExchange(spip, sizeof(txbuf), txbuf, rxbuf); /* Stops the watchdog.*/ chVTReset(&vt); } }
/** * @brief Create a timer. */ osTimerId osTimerCreate(const osTimerDef_t *timer_def, os_timer_type type, void *argument) { osTimerId timer = chPoolAlloc(&timpool); chVTObjectInit(&timer->vt); timer->ptimer = timer_def->ptimer; timer->type = type; timer->argument = argument; return timer; }
/** * @brief Initializes a generic teensy HID debug driver object. * @details The HW dependent part of the initialization has to be performed * outside, usually in the hardware initialization code. * * @param[out] hiddp pointer to a @p HIDDebugDriver structure * * @init */ void hidDebugObjectInit(HIDDebugDriver *hiddp) { hiddp->vmt = &vmt; osalEventObjectInit(&hiddp->event); hiddp->state = HIDDEBUG_STOP; /* TODO: how to make sure the queue is non-existent? */ /* hiddp->iqueue = (input_queue_t)NULL; */ hiddp->ib = (uint8_t *)NULL; oqObjectInit(&hiddp->oqueue, hiddp->ob, HID_DEBUG_OUTPUT_BUFFER_SIZE, onotify, hiddp); /* create the flush timer here as well (TODO: need to clean up/integrate!) */ chVTObjectInit(&hid_debug_flush_timer); }
/** * @brief Initializes the sensor read functionallity. * * @param[in] srdp Pointer to the SensorReadDriver object. * @param[in] intsenp Pointer to the interrupt sensor read configuration. * @param[in] pollsenp Pointer to the polled sensor read configuration. * @param[in] intsencnt Number of interrupt driven sensors. * @param[in] pollsencnt Number of polled driven sensors. * * @return The operation status. * @retval MSG_OK The initialization was successful. * @retval MSG_RESET Something went wrong during the initialization. * * @api */ msg_t SensorReadInit(SensorReadDriver *srdp, const interrupt_sensor_t *intsenp, const polled_sensor_t *pollsenp, size_t intsencnt, size_t pollsencnt) { chDbgCheck(srdp != NULL); chDbgCheck(srdp->state == SRD_UNINITIALIZED); chDbgAssert((intsenp == NULL) && (intsencnt != 0), "Pointer can't be NULL when the count is > 0"); chDbgAssert((pollsenp == NULL) && (pollsencnt != 0), "Pointer can't be NULL when the count is > 0"); size_t i; msg_t retval; /* Clear the lookup table */ for (i = 0; i < EXT_MAX_CHANNELS; i++) srdp->expchannel_lookup[i] = -1; /* Generate interrupt channel -> array index table */ for (i = 0; i < intsencnt; i++) srdp->expchannel_lookup[intsenp[i].interrupt_channel] = i; /* Copy sensor pointers and sizes to driver structures */ srdp->interrupt_sensor_ptr = intsenp; srdp->interrupt_sensor_cnt = intsencnt; srdp->polled_sensor_ptr = pollsenp; srdp->polled_sensor_cnt = pollsencnt; /* Run interrupt sensor initialization */ for (i = 0; i < intsencnt; i++) { /* Run sensor initialization with requested params */ if (intsenp[i].sensor.init_sensor != NULL) retval = intsenp[i].sensor.init_sensor(intsenp[i].sensor.params); else retval = MSG_RESET; if (retval != MSG_OK) return retval; } /* Run polled sensor initialization */ for (i = 0; i < pollsencnt; i++) { /* Check so the requested rate is plausible */ if (CH_CFG_ST_FREQUENCY / pollsenp[i].frequency_hz == 0) return MSG_TIMEOUT; /* Zero the accumulated ticks */ if (pollsenp[i].accumulator != NULL) *(pollsenp[i].accumulator) = 0; /* Run sensor initialization with requested params */ if (pollsenp[i].sensor.init_sensor != NULL) retval = pollsenp[i].sensor.init_sensor(pollsenp[i].sensor.params); else retval = MSG_RESET; if (retval != MSG_OK) return retval; else /* Initialization is OK, initialize the virtual timer */ chVTObjectInit(pollsenp[i].polling_vt); } /* Everything OK, transverse the state and start the read thread */ srdp->state = SRD_STOPPED; chThdCreateStatic(waThreadSRD1, sizeof(waThreadSRD1), SRD_THREAD_PRIORITY, ThreadSRD1, srdp); return MSG_OK; }
/** * @brief Initializes an @p event_timer_t structure. * * @param[out] etp the @p event_timer_t structure to be initialized * @param[in] time the interval in system ticks */ void evtObjectInit(event_timer_t *etp, systime_t time) { chEvtObjectInit(&etp->et_es); chVTObjectInit(&etp->et_vt); etp->et_interval = time; }
/* * Application entry point. */ int main(void) { unsigned i; static uint8_t patterns1[4096], patterns2[4096], buf1[4096], buf2[4096]; /* System initializations. - HAL initialization, this also initializes the configured device drivers and performs the board-specific initializations. - Kernel initialization, the main() function becomes a thread and the RTOS is active.*/ halInit(); chSysInit(); /* Creates the blinker thread.*/ chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 10, Thread1, NULL); /* Activates the ADC1 driver and the temperature sensor.*/ adcStart(&ADCD1, NULL); adcSTM32EnableTSVREFE(); /* Starts an ADC continuous conversion and its watchdog virtual timer.*/ chVTSet(&adcvt, MS2ST(10), tmo, (void *)"ADC timeout"); adcStartConversion(&ADCD1, &adcgrpcfg2, samples2, ADC_GRP2_BUF_DEPTH); /* Activating SPI drivers.*/ spiStart(&SPID1, &hs_spicfg); spiStart(&SPID2, &hs_spicfg); spiStart(&SPID3, &hs_spicfg); /* Starting SPI threads instances.*/ chThdCreateStatic(waSPI1, sizeof(waSPI1), NORMALPRIO + 1, spi_thread, &SPID1); chThdCreateStatic(waSPI2, sizeof(waSPI2), NORMALPRIO + 1, spi_thread, &SPID2); chThdCreateStatic(waSPI3, sizeof(waSPI3), NORMALPRIO + 1, spi_thread, &SPID3); /* Allocating two DMA2 streams for memory copy operations.*/ if (dmaStreamAllocate(STM32_DMA2_STREAM6, 0, NULL, NULL)) chSysHalt("DMA already in use"); if (dmaStreamAllocate(STM32_DMA2_STREAM7, 0, NULL, NULL)) chSysHalt("DMA already in use"); for (i = 0; i < sizeof (patterns1); i++) patterns1[i] = (uint8_t)i; for (i = 0; i < sizeof (patterns2); i++) patterns2[i] = (uint8_t)(i ^ 0xAA); /* Normal main() thread activity, it does continues memory copy operations using 2 DMA streams at the lowest priority.*/ while (true) { virtual_timer_t vt; chVTObjectInit(&vt); /* Starts a VT working as watchdog to catch a malfunction in the DMA driver.*/ chVTSet(&vt, MS2ST(10), tmo, (void *)"copy timeout"); /* Copy pattern 1.*/ dmaStartMemCopy(STM32_DMA2_STREAM6, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns1, buf1, sizeof (patterns1)); dmaStartMemCopy(STM32_DMA2_STREAM7, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns1, buf2, sizeof (patterns1)); dmaWaitCompletion(STM32_DMA2_STREAM6); dmaWaitCompletion(STM32_DMA2_STREAM7); if (memcmp(patterns1, buf1, sizeof (patterns1))) chSysHalt("pattern error"); if (memcmp(patterns1, buf2, sizeof (patterns1))) chSysHalt("pattern error"); /* Copy pattern 2.*/ dmaStartMemCopy(STM32_DMA2_STREAM6, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns2, buf1, sizeof (patterns2)); dmaStartMemCopy(STM32_DMA2_STREAM7, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns2, buf2, sizeof (patterns2)); dmaWaitCompletion(STM32_DMA2_STREAM6); dmaWaitCompletion(STM32_DMA2_STREAM7); if (memcmp(patterns2, buf1, sizeof (patterns2))) chSysHalt("pattern error"); if (memcmp(patterns2, buf2, sizeof (patterns2))) chSysHalt("pattern error"); /* Stops the watchdog.*/ chVTReset(&vt); chThdSleepMilliseconds(2); } return 0; }
/* Callback for SETUP request on the endpoint 0 (control) */ static bool usb_request_hook_cb(USBDriver *usbp) { const USBDescriptor *dp; /* usbp->setup fields: * 0: bmRequestType (bitmask) * 1: bRequest * 2,3: (LSB,MSB) wValue * 4,5: (LSB,MSB) wIndex * 6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */ /* Handle HID class specific requests */ if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) && ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) { switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) { case USB_RTYPE_DIR_DEV2HOST: switch(usbp->setup[1]) { /* bRequest */ case HID_GET_REPORT: switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0?) */ case KEYBOARD_INTERFACE: #ifdef NKRO_ENABLE case NKRO_INTERFACE: #endif /* NKRO_ENABLE */ usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL); return TRUE; break; #ifdef MOUSE_ENABLE case MOUSE_INTERFACE: usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL); return TRUE; break; #endif /* MOUSE_ENABLE */ #ifdef EXTRAKEY_ENABLE case EXTRAKEY_INTERFACE: if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */ switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */ case REPORT_ID_SYSTEM: extra_report_blank[0] = REPORT_ID_SYSTEM; usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); return TRUE; break; case REPORT_ID_CONSUMER: extra_report_blank[0] = REPORT_ID_CONSUMER; usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); return TRUE; break; default: return FALSE; } } else { return FALSE; } break; #endif /* EXTRAKEY_ENABLE */ default: usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; break; } break; case HID_GET_PROTOCOL: if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */ usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL); return TRUE; } break; case HID_GET_IDLE: usbSetupTransfer(usbp, &keyboard_idle, 1, NULL); return TRUE; break; } break; case USB_RTYPE_DIR_HOST2DEV: switch(usbp->setup[1]) { /* bRequest */ case HID_SET_REPORT: switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */ case KEYBOARD_INTERFACE: #ifdef NKRO_ENABLE case NKRO_INTERFACE: #endif /* NKRO_ENABLE */ /* keyboard_led_stats = <read byte from next OUT report> * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */ usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL); return TRUE; break; } break; case HID_SET_PROTOCOL: if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */ keyboard_protocol = ((usbp->setup[2]) != 0x00); /* LSB(wValue) */ #ifdef NKRO_ENABLE keymap_config.nkro = !!keyboard_protocol; if(!keymap_config.nkro && keyboard_idle) { #else /* NKRO_ENABLE */ if(keyboard_idle) { #endif /* NKRO_ENABLE */ /* arm the idle timer if boot protocol & idle */ osalSysLockFromISR(); chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); osalSysUnlockFromISR(); } } usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; break; case HID_SET_IDLE: keyboard_idle = usbp->setup[3]; /* MSB(wValue) */ /* arm the timer */ #ifdef NKRO_ENABLE if(!keymap_config.nkro && keyboard_idle) { #else /* NKRO_ENABLE */ if(keyboard_idle) { #endif /* NKRO_ENABLE */ osalSysLockFromISR(); chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); osalSysUnlockFromISR(); } usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; break; } break; } } /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */ if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) { dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4])); if(dp == NULL) return FALSE; usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); return TRUE; } for (int i=0;i<NUM_USB_DRIVERS;i++) { if (drivers.array[i].config.int_in) { // NOTE: Assumes that we only have one serial driver return qmkusbRequestsHook(usbp); } } return FALSE; } /* Start-of-frame callback */ static void usb_sof_cb(USBDriver *usbp) { kbd_sof_cb(usbp); osalSysLockFromISR(); for (int i=0; i<NUM_USB_DRIVERS;i++) { qmkusbSOFHookI(&drivers.array[i].driver); } osalSysUnlockFromISR(); } /* USB driver configuration */ static const USBConfig usbcfg = { usb_event_cb, /* USB events callback */ usb_get_descriptor_cb, /* Device GET_DESCRIPTOR request callback */ usb_request_hook_cb, /* Requests hook callback */ usb_sof_cb /* Start Of Frame callback */ }; /* * Initialize the USB driver */ void init_usb_driver(USBDriver *usbp) { for (int i=0; i<NUM_USB_DRIVERS;i++) { QMKUSBDriver* driver = &drivers.array[i].driver; drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state; drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state; drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state; qmkusbObjectInit(driver, &drivers.array[i].config); qmkusbStart(driver, &drivers.array[i].config); } /* * Activates the USB driver and then the USB bus pull-up on D+. * Note, a delay is inserted in order to not have to disconnect the cable * after a reset. */ usbDisconnectBus(usbp); wait_ms(1500); usbStart(usbp, &usbcfg); usbConnectBus(usbp); chVTObjectInit(&keyboard_idle_timer); } /* --------------------------------------------------------- * Keyboard functions * --------------------------------------------------------- */ /* keyboard IN callback hander (a kbd report has made it IN) */ void kbd_in_cb(USBDriver *usbp, usbep_t ep) { /* STUB */ (void)usbp; (void)ep; }