#include "seader_i.h" #include #define TAG "SeaderUART" #define RESET_PIN &gpio_ext_pa6 #define PWM_FREQ 3571200 #define RAW_BAUDRATE_DEFAULT (PWM_FREQ / 372) #define SEC1210_BAUDRATE_DEFAULT 115200 // Raw version static bool hasSAM = false; static bool ppsSetup = false; static uint8_t PPS[] = {0xFF, 0x11, 0x96, 0x78}; static void seader_uart_on_irq_rx_dma_cb( FuriHalSerialHandle* handle, FuriHalSerialRxEvent ev, size_t size, void* context) { SeaderUartBridge* seader_uart = (SeaderUartBridge*)context; if(ev & (FuriHalSerialRxEventData | FuriHalSerialRxEventIdle)) { uint8_t data[FURI_HAL_SERIAL_DMA_BUFFER_SIZE] = {0}; while(size) { size_t ret = furi_hal_serial_dma_rx( handle, data, (size > FURI_HAL_SERIAL_DMA_BUFFER_SIZE) ? FURI_HAL_SERIAL_DMA_BUFFER_SIZE : size); furi_stream_buffer_send(seader_uart->rx_stream, data, ret, 0); size -= ret; }; furi_thread_flags_set(furi_thread_get_id(seader_uart->thread), WorkerEvtRxDone); } } void seader_uart_disable(SeaderUartBridge* seader_uart) { furi_assert(seader_uart); furi_thread_flags_set(furi_thread_get_id(seader_uart->thread), WorkerEvtStop); furi_thread_join(seader_uart->thread); furi_thread_free(seader_uart->thread); free(seader_uart); } void seader_uart_serial_init(Seader* seader, uint8_t uart_ch) { SeaderUartBridge* seader_uart = seader->uart; furi_assert(!seader_uart->serial_handle); seader_uart->serial_handle = furi_hal_serial_control_acquire(uart_ch); furi_assert(seader_uart->serial_handle); if(seader->worker->sam_comm_type == SeaderSamCommunicationTypeSec1210) { furi_hal_serial_init(seader_uart->serial_handle, SEC1210_BAUDRATE_DEFAULT); furi_hal_serial_dma_rx_start( seader_uart->serial_handle, seader_uart_on_irq_rx_dma_cb, seader_uart, false); } else { furi_hal_serial_init(seader_uart->serial_handle, RAW_BAUDRATE_DEFAULT); furi_hal_serial_configure_framing( seader_uart->serial_handle, FuriHalSerialDataBits8, FuriHalSerialParityEven, FuriHalSerialStopBits2); furi_hal_serial_dma_rx_start( seader_uart->serial_handle, seader_uart_on_irq_rx_dma_cb, seader_uart, false); // NOTE: Consider putting this before the UART setup if we find the ATR on startup is problematic furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, PWM_FREQ, 50); furi_hal_gpio_init(RESET_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(RESET_PIN, true); // Active low, so set high } } void seader_uart_sam_reset(Seader* seader) { if(seader->worker->sam_comm_type == SeaderSamCommunicationTypeRaw) { hasSAM = false; ppsSetup = false; seader_uart_set_baudrate(seader->uart, RAW_BAUDRATE_DEFAULT); furi_hal_gpio_write(RESET_PIN, false); furi_delay_ms(1); furi_hal_gpio_write(RESET_PIN, true); } } void seader_uart_serial_deinit(Seader* seader) { SeaderUartBridge* seader_uart = seader->uart; furi_assert(seader_uart->serial_handle); furi_hal_serial_deinit(seader_uart->serial_handle); furi_hal_serial_control_release(seader_uart->serial_handle); seader_uart->serial_handle = NULL; if(seader->worker->sam_comm_type == SeaderSamCommunicationTypeRaw) { furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); furi_hal_gpio_init_simple(RESET_PIN, GpioModeAnalog); furi_hal_gpio_write(RESET_PIN, false); } } void seader_uart_set_baudrate(SeaderUartBridge* seader_uart, uint32_t baudrate) { if(baudrate != 0) { furi_hal_serial_set_br(seader_uart->serial_handle, baudrate); } else { FURI_LOG_I(TAG, "No baudrate specified"); } } size_t seader_uart_process_buffer_sec1210(Seader* seader, uint8_t* cmd, size_t cmd_len) { if(cmd_len < 2) { return cmd_len; } size_t consumed = 0; do { consumed = seader_ccid_process(seader, cmd, cmd_len); if(consumed > 0) { memset(cmd, 0, consumed); cmd_len -= consumed; if(cmd_len > 0) { memmove(cmd, cmd + consumed, cmd_len); } char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0}; memset(display, 0, SEADER_UART_RX_BUF_SIZE); for(uint8_t i = 0; i < cmd_len; i++) { snprintf(display + (i * 2), sizeof(display), "%02x", cmd[i]); } FURI_LOG_I(TAG, "cmd is now %d bytes: %s", cmd_len, display); } } while(consumed > 0 && cmd_len > 0); return cmd_len; } size_t seader_uart_process_buffer_raw(Seader* seader, uint8_t* cmd, size_t cmd_len) { SeaderUartBridge* seader_uart = seader->uart; char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0}; memset(display, 0, SEADER_UART_RX_BUF_SIZE); for(uint8_t i = 0; i < cmd_len; i++) { snprintf(display + (i * 2), sizeof(display), "%02x", cmd[i]); } FURI_LOG_I(TAG, "seader_uart_process_buffer_raw %d bytes: %s", cmd_len, display); if(ppsSetup) { if(memcmp(PPS, cmd, sizeof(PPS)) == 0) { // If you ever have issue with this, try bumping it to 230400 FURI_LOG_I(TAG, "PPS received, setting baudrate to 223125"); seader_uart_set_baudrate(seader->uart, 223125); seader_t_1_set_IFSD(seader); // Kick off next part of detection process /* seader_worker_send_version(seader); SeaderWorker* seader_worker = seader->worker; if(seader_worker->callback) { seader_worker->callback(SeaderWorkerEventSamPresent, seader_worker->context); } */ return 0; } } if(hasSAM) { CCID_Message message; message.payload = cmd; message.dwLength = cmd_len; if(seader_recv_t1(seader, &message)) { return 0; } else { return cmd_len; } } if(cmd_len < sizeof(SAM_ATR)) { return cmd_len; } do { if(memcmp(SAM_ATR, cmd, sizeof(SAM_ATR)) == 0) { FURI_LOG_I(TAG, "SAM ATR!"); hasSAM = true; // In order to get the transmission to work, we fudge the baudrate here /* seader_uart_set_baudrate(seader_uart, 9900); furi_hal_serial_configure_framing( seader_uart->serial_handle, FuriHalSerialDataBits8, FuriHalSerialParityEven, FuriHalSerialStopBits2); */ // 5.2.3 PPS - Protocol Parameter Selection // 0xFF, 0x11, 0x96, 0x78 seader_uart_send(seader_uart, PPS, sizeof(PPS)); ppsSetup = true; return 0; } cmd++; cmd_len--; } while(cmd_len > 0); return cmd_len; } size_t seader_uart_process_buffer(Seader* seader, uint8_t* cmd, size_t cmd_len) { if(seader->worker->sam_comm_type == SeaderSamCommunicationTypeSec1210) { return seader_uart_process_buffer_sec1210(seader, cmd, cmd_len); } else { return seader_uart_process_buffer_raw(seader, cmd, cmd_len); } } int32_t seader_uart_worker(void* context) { Seader* seader = (Seader*)context; SeaderUartBridge* seader_uart = seader->uart; furi_thread_set_current_priority(FuriThreadPriorityHighest); memcpy(&seader_uart->cfg, &seader_uart->cfg_new, sizeof(SeaderUartConfig)); seader_uart->rx_stream = furi_stream_buffer_alloc(SEADER_UART_RX_BUF_SIZE, 1); seader_uart->tx_sem = furi_semaphore_alloc(1, 1); seader_uart->tx_thread = furi_thread_alloc_ex("SeaderUartTxWorker", 1.5 * 1024, seader_uart_tx_thread, seader); seader_uart_serial_init(seader, seader_uart->cfg.uart_ch); // NOTE: I question the value of this seader_uart_set_baudrate(seader_uart, seader_uart->cfg.baudrate); furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx); furi_thread_start(seader_uart->tx_thread); uint8_t cmd[SEADER_UART_RX_BUF_SIZE]; size_t cmd_len = 0; while(1) { uint32_t events = furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever); furi_check(!(events & FuriFlagError)); if(events & WorkerEvtStop) { memset(cmd, 0, cmd_len); cmd_len = 0; break; } if(events & (WorkerEvtRxDone | WorkerEvtSamTxComplete)) { size_t len = furi_stream_buffer_receive( seader_uart->rx_stream, seader_uart->rx_buf, SEADER_UART_RX_BUF_SIZE, 0); if(len > 0) { furi_delay_ms(5); //WTF if(memcmp(seader_uart->rx_buf, seader_uart->tx_buf, len) == 0) { FURI_LOG_I(TAG, "Ignoring echoed data"); continue; } char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0}; for(uint8_t i = 0; i < len; i++) { snprintf(display + (i * 2), sizeof(display), "%02x", seader_uart->rx_buf[i]); } FURI_LOG_I(TAG, "RECV %d bytes: %s", len, display); if(cmd_len + len > SEADER_UART_RX_BUF_SIZE) { FURI_LOG_I(TAG, "OVERFLOW: %d + %d", cmd_len, len); memset(cmd, 0, cmd_len); cmd_len = 0; } memcpy(cmd + cmd_len, seader_uart->rx_buf, len); cmd_len += len; cmd_len = seader_uart_process_buffer(seader, cmd, cmd_len); } } } seader_uart_serial_deinit(seader); furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtTxStop); furi_thread_join(seader_uart->tx_thread); furi_thread_free(seader_uart->tx_thread); furi_stream_buffer_free(seader_uart->rx_stream); furi_semaphore_free(seader_uart->tx_sem); return 0; } SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) { SeaderUartBridge* seader_uart = malloc(sizeof(SeaderUartBridge)); seader_uart->T = 1; memcpy(&(seader_uart->cfg_new), cfg, sizeof(SeaderUartConfig)); seader_uart->thread = furi_thread_alloc_ex("SeaderUartWorker", 5 * 1024, seader_uart_worker, seader); furi_thread_start(seader_uart->thread); return seader_uart; } void seader_uart_send(SeaderUartBridge* seader_uart, uint8_t* data, size_t len) { memcpy(seader_uart->tx_buf, data, len); seader_uart->tx_len = len; furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx); } int32_t seader_uart_tx_thread(void* context) { Seader* seader = (Seader*)context; SeaderUartBridge* seader_uart = seader->uart; furi_thread_set_current_priority(FuriThreadPriorityHighest); while(1) { uint32_t events = furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, FuriFlagWaitAny, FuriWaitForever); furi_check(!(events & FuriFlagError)); if(events & WorkerEvtTxStop) break; if(events & WorkerEvtSamRx) { if(seader_uart->tx_len > 0) { char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0}; for(uint8_t i = 0; i < seader_uart->tx_len; i++) { snprintf(display + (i * 2), sizeof(display), "%02x", seader_uart->tx_buf[i]); } // FURI_LOG_I(TAG, "SEND %d bytes: %s", seader_uart->tx_len, display); furi_hal_serial_tx( seader_uart->serial_handle, seader_uart->tx_buf, seader_uart->tx_len); } } } return 0; } void seader_uart_get_config(SeaderUartBridge* seader_uart, SeaderUartConfig* cfg) { furi_assert(seader_uart); furi_assert(cfg); memcpy(cfg, &(seader_uart->cfg_new), sizeof(SeaderUartConfig)); } void seader_uart_get_state(SeaderUartBridge* seader_uart, SeaderUartState* st) { furi_assert(seader_uart); furi_assert(st); memcpy(st, &(seader_uart->st), sizeof(SeaderUartState)); } SeaderUartBridge* seader_uart_alloc(Seader* seader) { uint32_t baudrate; if(seader->worker->sam_comm_type == SeaderSamCommunicationTypeSec1210) { baudrate = SEC1210_BAUDRATE_DEFAULT; } else { baudrate = RAW_BAUDRATE_DEFAULT; } SeaderUartConfig cfg = {.uart_ch = FuriHalSerialIdLpuart, .baudrate = baudrate}; SeaderUartState uart_state; SeaderUartBridge* seader_uart; FURI_LOG_I(TAG, "Enable UART %ld baud", baudrate); seader_uart = seader_uart_enable(&cfg, seader); seader_uart_get_config(seader_uart, &cfg); seader_uart_get_state(seader_uart, &uart_state); return seader_uart; } void seader_uart_free(SeaderUartBridge* seader_uart) { seader_uart_disable(seader_uart); }