void APP_Initialize(void) { #ifdef PRE_APP_INIT_HOOK PRE_APP_INIT_HOOK(); #endif // We can do this after USB_DEVICE_Initialize() has been called since it's // not used until we reach the tasks function. UIDStore_AsUnicodeString(USBDescriptor_UnicodeUID()); CoarseTimer_Settings timer_settings = { .timer_id = AS_TIMER_ID(COARSE_TIMER_ID), .interrupt_source = AS_TIMER_INTERRUPT_SOURCE(COARSE_TIMER_ID) }; SYS_INT_VectorPrioritySet(AS_TIMER_INTERRUPT_VECTOR(COARSE_TIMER_ID), INT_PRIORITY_LEVEL6); CoarseTimer_Initialize(&timer_settings); // Initialize the Logging system, bottom up USBTransport_Initialize(NULL); USBConsole_Initialize(); SysLog_Initialize(NULL); // Initialize the DMX / RDM Transceiver TransceiverHardwareSettings transceiver_settings = { .usart = AS_USART_ID(TRANSCEIVER_UART), .usart_vector = AS_USART_INTERRUPT_VECTOR(TRANSCEIVER_UART), .usart_tx_source = AS_USART_INTERRUPT_TX_SOURCE(TRANSCEIVER_UART), .usart_rx_source = AS_USART_INTERRUPT_RX_SOURCE(TRANSCEIVER_UART), .usart_error_source = AS_USART_INTERRUPT_ERROR_SOURCE(TRANSCEIVER_UART), .port = TRANSCEIVER_PORT, .break_bit = TRANSCEIVER_PORT_BIT, .tx_enable_bit = TRANSCEIVER_TX_ENABLE_PORT_BIT, .rx_enable_bit = TRANSCEIVER_RX_ENABLE_PORT_BIT, .input_capture_module = AS_IC_ID(TRANSCEIVER_IC), .input_capture_vector = AS_IC_INTERRUPT_VECTOR(TRANSCEIVER_IC), .input_capture_source = AS_IC_INTERRUPT_SOURCE(TRANSCEIVER_IC), .timer_module_id = AS_TIMER_ID(TRANSCEIVER_TIMER), .timer_vector = AS_TIMER_INTERRUPT_VECTOR(TRANSCEIVER_TIMER), .timer_source = AS_TIMER_INTERRUPT_SOURCE(TRANSCEIVER_TIMER), .input_capture_timer = AS_IC_TMR_ID(TRANSCEIVER_TIMER), }; Transceiver_Initialize(&transceiver_settings, NULL, NULL); // Base RDM Responder RDMResponderSettings responder_settings = { .identify_port = RDM_RESPONDER_IDENTIFY_PORT, .identify_bit = RDM_RESPONDER_IDENTIFY_PORT_BIT, .mute_port = RDM_RESPONDER_MUTE_PORT, .mute_bit = RDM_RESPONDER_MUTE_PORT_BIT, }; memcpy(responder_settings.uid, UIDStore_GetUID(), UID_LENGTH); RDMResponder_Initialize(&responder_settings); ReceiverCounters_ResetCounters(); // RDM Handler RDMHandlerSettings rdm_handler_settings = { .default_model = LED_MODEL_ID, .send_callback = NULL }; RDMHandler_Initialize(&rdm_handler_settings); // Initialize RDM Models, keep these in Model ID order. LEDModel_Initialize(); RDMHandler_AddModel(&LED_MODEL_ENTRY); ProxyModel_Initialize(); RDMHandler_AddModel(&PROXY_MODEL_ENTRY); MovingLightModel_Initialize(); RDMHandler_AddModel(&MOVING_LIGHT_MODEL_ENTRY); SensorModel_Initialize(); RDMHandler_AddModel(&SENSOR_MODEL_ENTRY); NetworkModel_Initialize(); RDMHandler_AddModel(&NETWORK_MODEL_ENTRY); DimmerModel_Initialize(); RDMHandler_AddModel(&DIMMER_MODEL_ENTRY); // Initialize the Host message layers. MessageHandler_Initialize(NULL); StreamDecoder_Initialize(NULL); Flags_Initialize(); // SPI DMX Output SPIRGBConfiguration spi_config; spi_config.module_id = SPI_MODULE_ID; spi_config.baud_rate = SPI_BAUD_RATE; spi_config.use_enhanced_buffering = SPI_USE_ENHANCED_BUFFERING; SPIRGB_Init(&spi_config); // Send a frame with all pixels set to 0. SPIRGB_BeginUpdate(); SPIRGB_CompleteUpdate(); }
void Responder_Receive(const TransceiverEvent *event) { // While this function is running, UART interrupts are disabled. // Try to keep things short. if (event->op != T_OP_RX) { return; } if (event->result == T_RESULT_RX_START_FRAME) { // Right now we can only tell a DMX frame ended when the next one starts. // TODO(simon): get some clarity on this. It needs to be discussed and // explained in E1.37-5. if (g_state == STATE_DMX_DATA && (g_responder_counters.dmx_min_slot_count == UNINITIALIZED_COUNTER || g_responder_counters.dmx_last_slot_count < g_responder_counters.dmx_min_slot_count)) { g_responder_counters.dmx_min_slot_count = g_responder_counters.dmx_last_slot_count; } if (g_state == STATE_RDM_SUB_START_CODE || g_state == STATE_RDM_MESSAGE_LENGTH || (g_state == STATE_RDM_BODY && g_offset < 9)) { // COMMS_STATUS, short frame g_responder_counters.rdm_short_frame++; } g_offset = 0u; g_state = STATE_START_CODE; if (event->timing) { g_timing = *event->timing; } } if (event->result == T_RESULT_RX_FRAME_TIMEOUT) { SPIRGB_CompleteUpdate(); return; } for (; g_offset < event->length; g_offset++) { uint8_t b = event->data[g_offset]; switch (g_state) { case STATE_START_CODE: if (b == NULL_START_CODE) { g_responder_counters.dmx_last_checksum = 0u; g_responder_counters.dmx_last_slot_count = 0u; SysLog_Message(SYSLOG_DEBUG, "DMX frame"); g_responder_counters.dmx_frames++; g_state = STATE_DMX_DATA; SPIRGB_BeginUpdate(); } else if (b == RDM_START_CODE) { g_responder_counters.rdm_frames++; g_state = STATE_RDM_SUB_START_CODE; } else { SysLog_Print(SYSLOG_DEBUG, "ASC frame: %d", (int) b); g_responder_counters.asc_frames++; g_state = STATE_DISCARD; } break; case STATE_RDM_SUB_START_CODE: if (b != RDM_SUB_START_CODE) { SysLog_Print(SYSLOG_ERROR, "RDM sub-start-code mismatch: %d", (int) b); g_responder_counters.rdm_sub_start_code_invalid++; g_state = STATE_DISCARD; } else { g_state = STATE_RDM_MESSAGE_LENGTH; } break; case STATE_RDM_MESSAGE_LENGTH: if (b < sizeof(RDMHeader)) { SysLog_Print(SYSLOG_INFO, "RDM msg len too short: %d", (int) b); g_responder_counters.rdm_msg_len_invalid++; g_state = STATE_DISCARD; } else { g_state = STATE_RDM_BODY; } break; // data[2] is at least 24 case STATE_RDM_BODY: if (g_offset == RDM_PARAM_DATA_LENGTH_OFFSET) { if (b != event->data[MESSAGE_LENGTH_OFFSET] - sizeof(RDMHeader)) { SysLog_Print(SYSLOG_INFO, "Invalid RDM PDL: %d, msg len: %d", (int) b, event->data[MESSAGE_LENGTH_OFFSET]); g_state = STATE_DISCARD; g_responder_counters.rdm_param_data_len_invalid++; continue; } } if (g_offset + 1u == event->data[MESSAGE_LENGTH_OFFSET]) { g_state = STATE_RDM_CHECKSUM_LO; } break; case STATE_RDM_CHECKSUM_LO: g_state = STATE_RDM_CHECKSUM_HI; break; case STATE_RDM_CHECKSUM_HI: if (RDMUtil_VerifyChecksum(event->data, event->length)) { DispatchRDMRequest(event->data); } else { PossiblyIncrementChecksumCounter(event->data); } g_state = STATE_RDM_POST_CHECKSUM; break; case STATE_RDM_POST_CHECKSUM: PossiblyIncrementLengthMismatchCounter(event->data); g_state = STATE_DISCARD; break; case STATE_DMX_DATA: // TODO(simon): configure this with DMX_START_ADDRESS and footprints. if (g_offset - 1u < 6u) { SPIRGB_SetPixel((g_offset - 1u) / 3u, (g_offset - 1u) % 3u, b); } else if (g_offset - 1u == 6u) { SPIRGB_CompleteUpdate(); } g_responder_counters.dmx_last_checksum += b; g_responder_counters.dmx_last_slot_count++; if (g_responder_counters.dmx_max_slot_count == UNINITIALIZED_COUNTER || g_responder_counters.dmx_last_slot_count > g_responder_counters.dmx_max_slot_count) { g_responder_counters.dmx_max_slot_count = g_responder_counters.dmx_last_slot_count; } break; case STATE_DISCARD: break; } } }