Bläddra i källkod

FL-176 LF RFID RX (#248)

* pulldown ibutton pin during rfid read
* enable and handle COMP interrupts
* send events from comparator IRQ and handle in app
* manchester encode
* successfully read em4100
* read-emulate
* led
coreglitch 5 år sedan
förälder
incheckning
ccd40497eb

+ 3 - 1
applications/lf-rfid/em4100.c

@@ -43,11 +43,13 @@ void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) {
 
     data[63] = 0; // stop bit
 
+    /*
     printf("em data: ");
     for(uint8_t i = 0; i < 64; i++) {
         printf("%d ", data[i]);
     }
     printf("\n");
+    */
 }
 
 void em4100_emulation(uint8_t* data, GpioPin* pin) {
@@ -65,4 +67,4 @@ void em4100_emulation(uint8_t* data, GpioPin* pin) {
 
     gpio_write(pin, false);
     taskEXIT_CRITICAL();
-}
+}

+ 246 - 43
applications/lf-rfid/lf-rfid.c

@@ -1,13 +1,16 @@
 #include "flipper_v2.h"
 
-typedef enum {
-    EventTypeTick,
-    EventTypeKey,
-} EventType;
+typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
+
+typedef struct {
+    bool value;
+    uint32_t dwt_value;
+} RxEvent;
 
 typedef struct {
     union {
         InputEvent input;
+        RxEvent rx;
     } value;
     EventType type;
 } AppEvent;
@@ -15,6 +18,8 @@ typedef struct {
 typedef struct {
     uint32_t freq_khz;
     bool on;
+    uint8_t customer_id;
+    uint32_t em_data;
 } State;
 
 static void render_callback(CanvasApi* canvas, void* ctx) {
@@ -26,11 +31,16 @@ static void render_callback(CanvasApi* canvas, void* ctx) {
     canvas->set_font(canvas, FontPrimary);
     canvas->draw_str(canvas, 2, 12, "LF RFID");
 
-    canvas->draw_str(canvas, 2, 24, state->on ? "ON" : "OFF");
-    char buf[12];
+    canvas->draw_str(canvas, 2, 24, state->on ? "Reading" : "Emulating");
+
+    char buf[14];
+
     sprintf(buf, "%d kHz", (int)state->freq_khz);
     canvas->draw_str(canvas, 2, 36, buf);
 
+    sprintf(buf, "%02d:%010ld", state->customer_id, state->em_data);
+    canvas->draw_str(canvas, 2, 45, buf);
+
     release_mutex((ValueMutex*)ctx, state);
 }
 
@@ -47,6 +57,109 @@ extern TIM_HandleTypeDef TIM_C;
 void em4100_emulation(uint8_t* data, GpioPin* pin);
 void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data);
 
+GpioPin debug_0 = {.pin = GPIO_PIN_2, .port = GPIOB};
+GpioPin debug_1 = {.pin = GPIO_PIN_3, .port = GPIOC};
+
+extern COMP_HandleTypeDef hcomp1;
+
+void* comp_ctx = NULL;
+
+void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) {
+    if(hcomp != &hcomp1) return;
+
+    // gpio_write(&debug_0, true);
+
+    osMessageQueueId_t event_queue = (QueueHandle_t)comp_ctx;
+
+    AppEvent event;
+    event.type = EventTypeRx;
+    event.value.rx.value = (HAL_COMP_GetOutputLevel(hcomp) == COMP_OUTPUT_LEVEL_HIGH);
+    event.value.rx.dwt_value = DWT->CYCCNT;
+    osMessageQueuePut(event_queue, &event, 0, 0);
+
+    // gpio_write(&debug_0, false);
+}
+
+const uint8_t ROW_SIZE = 4;
+const uint8_t LINE_SIZE = 10;
+
+static bool even_check(uint8_t* buf) {
+    uint8_t col_parity_sum[ROW_SIZE];
+    for(uint8_t col = 0; col < ROW_SIZE; col++) {
+        col_parity_sum[col] = 0;
+    }
+
+    // line parity
+    for(uint8_t line = 0; line < LINE_SIZE; line++) {
+        printf("%d: ", line);
+        uint8_t parity_sum = 0;
+        for(uint8_t col = 0; col < ROW_SIZE; col++) {
+            parity_sum += buf[line * (ROW_SIZE + 1) + col];
+            col_parity_sum[col] += buf[line * (ROW_SIZE + 1) + col];
+            printf("%d ", buf[line * (ROW_SIZE + 1) + col]);
+        }
+        if((1 & parity_sum) != buf[line * (ROW_SIZE + 1) + ROW_SIZE]) {
+            printf(
+                "line parity fail at %d (%d : %d)\n",
+                line,
+                parity_sum,
+                buf[line * (ROW_SIZE + 1) + ROW_SIZE]);
+            return false;
+        }
+        printf("\n");
+    }
+
+    for(uint8_t col = 0; col < ROW_SIZE; col++) {
+        if((1 & col_parity_sum[col]) != buf[LINE_SIZE * (ROW_SIZE + 1) + col]) {
+            printf(
+                "col parity fail at %d (%d : %d)\n",
+                col,
+                col_parity_sum[col],
+                buf[LINE_SIZE * (ROW_SIZE + 1) + col]);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void extract_data(uint8_t* buf, uint8_t* customer, uint32_t* em_data) {
+    uint32_t data = 0;
+    uint8_t offset = 0;
+
+    printf("customer: ");
+    for(uint8_t line = 0; line < 2; line++) {
+        for(uint8_t col = 0; col < ROW_SIZE; col++) {
+            uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
+
+            data |= bit << (7 - offset);
+            printf("%d ", bit);
+
+            offset++;
+        }
+    }
+    printf("\n");
+
+    *customer = data;
+
+    data = 0;
+    offset = 0;
+    printf("data: ");
+    for(uint8_t line = 2; line < LINE_SIZE; line++) {
+        for(uint8_t col = 0; col < ROW_SIZE; col++) {
+            uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
+
+            data |= bit << (31 - offset);
+            printf("%d ", bit);
+
+            offset++;
+        }
+    }
+    printf("\n");
+
+    *em_data = data;
+}
+
 void lf_rfid_workaround(void* p) {
     osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
 
@@ -57,12 +170,25 @@ void lf_rfid_workaround(void* p) {
 
     gpio_init(pull_pin_record, GpioModeOutputPushPull);
 
+    gpio_init(&debug_0, GpioModeOutputPushPull);
+    gpio_init(&debug_1, GpioModeOutputPushPull);
+
+    // pulldown iBtn pin to prevent interference from ibutton
+    gpio_init((GpioPin*)&ibutton_gpio, GpioModeOutputOpenDrain);
+    gpio_write((GpioPin*)&ibutton_gpio, false);
+
+    // init ctx
+    comp_ctx = (void*)event_queue;
+    // start comp
+    HAL_COMP_Start(&hcomp1);
+
     uint8_t emulation_data[64];
-    prepare_data(4378151, 01, emulation_data);
 
     State _state;
     _state.freq_khz = 125;
     _state.on = false;
+    _state.customer_id = 01;
+    _state.em_data = 4378151;
 
     ValueMutex state_mutex;
     if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
@@ -84,55 +210,132 @@ void lf_rfid_workaround(void* p) {
     gui->add_widget(gui, widget, GuiLayerFullscreen);
 
     AppEvent event;
+    uint32_t prev_dwt;
+    int8_t symbol = -1; // init state
+    bool center = false;
+    size_t symbol_cnt = 0;
+
+    GpioPin* led_record = (GpioPin*)&led_gpio[1];
+    gpio_init(led_record, GpioModeOutputOpenDrain);
+
+    uint8_t buf[64];
+    for(size_t i = 0; i < 64; i++) {
+        buf[i] = 0;
+    }
+
     while(1) {
         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
-        State* state = (State*)acquire_mutex_block(&state_mutex);
-
-        if(event_status == osOK) {
-            if(event.type == EventTypeKey) {
-                // press events
-                if(event.value.input.state && event.value.input.input == InputBack) {
-                    hal_pwmn_stop(&TIM_C, TIM_CHANNEL_1); // TODO: move to furiac_onexit
-                    gpio_init(pull_pin_record, GpioModeInput);
-                    // TODO remove all widgets create by app
-                    widget_enabled_set(widget, false);
-                    furiac_exit(NULL);
-                }
 
-                if(event.value.input.state && event.value.input.input == InputUp) {
-                    state->freq_khz += 10;
-                }
+        if(event.type == EventTypeRx && event_status == osOK) {
+            uint32_t dt = (event.value.rx.dwt_value - prev_dwt) / (SystemCoreClock / 1000000.0f);
+            prev_dwt = event.value.rx.dwt_value;
 
-                if(event.value.input.state && event.value.input.input == InputDown) {
-                    state->freq_khz -= 10;
-                }
+            if(dt > 384) {
+                // change symbol 0->1 or 1->0
+                symbol = event.value.rx.value;
+                center = true;
+            } else {
+                // same symbol as prev or center
+                center = !center;
+            }
 
-                if(event.value.input.state && event.value.input.input == InputLeft) {
-                }
+            /*
+            gpio_write(&debug_1, true);
+            delay_us(center ? 10 : 30);
+            gpio_write(&debug_1, false);
+            */
 
-                if(event.value.input.state && event.value.input.input == InputRight) {
-                }
+            if(center && symbol != -1) {
+                /*
+                gpio_write(&debug_0, true);
+                delay_us(symbol ? 10 : 30);
+                gpio_write(&debug_0, false);
+                */
+
+                buf[symbol_cnt] = symbol;
+                symbol_cnt++;
+            }
+
+            // check preamble
+            if(symbol_cnt <= 9 && symbol == 0) {
+                symbol_cnt = 0;
+                symbol = -1;
+            }
+
+            // check stop bit
+            if(symbol_cnt == 64 && symbol == 1) {
+                symbol_cnt = 0;
+                symbol = -1;
+            }
 
-                if(event.value.input.state && event.value.input.input == InputOk) {
-                    state->on = !state->on;
+            if(symbol_cnt == 64) {
+                if(even_check(&buf[9])) {
+                    State* state = (State*)acquire_mutex_block(&state_mutex);
+                    extract_data(&buf[9], &state->customer_id, &state->em_data);
+                    printf("customer: %02d, data: %010lu\n", state->customer_id, state->em_data);
+                    release_mutex(&state_mutex, state);
+                    gpio_write(led_record, false);
+                    osDelay(100);
+                    gpio_write(led_record, true);
                 }
+
+                symbol_cnt = 0;
             }
         } else {
-            // event timeout
-        }
+            State* state = (State*)acquire_mutex_block(&state_mutex);
 
-        hal_pwmn_set(
-            state->on ? 0.5 : 0.0, (float)(state->freq_khz * 1000), &LFRFID_TIM, LFRFID_CH);
+            if(event_status == osOK) {
+                if(event.type == EventTypeKey) {
+                    // press events
+                    if(event.value.input.state && event.value.input.input == InputBack) {
+                        hal_pwmn_stop(&TIM_C, TIM_CHANNEL_1); // TODO: move to furiac_onexit
+                        gpio_init(pull_pin_record, GpioModeInput);
+                        gpio_init((GpioPin*)&ibutton_gpio, GpioModeInput);
 
-        if(!state->on) {
-            em4100_emulation(emulation_data, pull_pin_record);
-        } else {
-            gpio_write(pull_pin_record, false);
-        }
+                        // TODO remove all widgets create by app
+                        widget_enabled_set(widget, false);
+                        furiac_exit(NULL);
+                    }
+
+                    if(event.value.input.state && event.value.input.input == InputUp) {
+                        state->freq_khz += 10;
+                    }
+
+                    if(event.value.input.state && event.value.input.input == InputDown) {
+                        state->freq_khz -= 10;
+                    }
+
+                    if(event.value.input.state && event.value.input.input == InputLeft) {
+                    }
 
-        // common code, for example, force update UI
-        widget_update(widget);
+                    if(event.value.input.state && event.value.input.input == InputRight) {
+                    }
 
-        release_mutex(&state_mutex, state);
+                    if(event.value.input.state && event.value.input.input == InputOk) {
+                        state->on = !state->on;
+
+                        if(!state->on) {
+                            prepare_data(state->em_data, state->customer_id, emulation_data);
+                        }
+                    }
+                }
+            } else {
+                // event timeout
+            }
+
+            hal_pwmn_set(
+                state->on ? 0.5 : 0.0, (float)(state->freq_khz * 1000), &LFRFID_TIM, LFRFID_CH);
+
+            if(!state->on) {
+                em4100_emulation(emulation_data, pull_pin_record);
+            } else {
+                gpio_write(pull_pin_record, false);
+            }
+
+            // common code, for example, force update UI
+            widget_update(widget);
+
+            release_mutex(&state_mutex, state);
+        }
     }
 }

+ 1 - 0
firmware/targets/f3/Inc/stm32wbxx_it.h

@@ -56,6 +56,7 @@ void DebugMon_Handler(void);
 void EXTI1_IRQHandler(void);
 void EXTI2_IRQHandler(void);
 void USB_LP_IRQHandler(void);
+void COMP_IRQHandler(void);
 void EXTI9_5_IRQHandler(void);
 void TIM1_TRG_COM_TIM17_IRQHandler(void);
 void TIM2_IRQHandler(void);

+ 9 - 4
firmware/targets/f3/Src/comp.c

@@ -31,14 +31,14 @@ void MX_COMP1_Init(void)
 {
 
   hcomp1.Instance = COMP1;
-  hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT;
+  hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT;
   hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
   hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
-  hcomp1.Init.Hysteresis = COMP_HYSTERESIS_NONE;
+  hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH;
   hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
-  hcomp1.Init.Mode = COMP_POWERMODE_HIGHSPEED;
+  hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
   hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
-  hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_NONE;
+  hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING;
   if (HAL_COMP_Init(&hcomp1) != HAL_OK)
   {
     Error_Handler();
@@ -65,6 +65,9 @@ void HAL_COMP_MspInit(COMP_HandleTypeDef* compHandle)
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct);
 
+    /* COMP1 interrupt Init */
+    HAL_NVIC_SetPriority(COMP_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(COMP_IRQn);
   /* USER CODE BEGIN COMP1_MspInit 1 */
 
   /* USER CODE END COMP1_MspInit 1 */
@@ -85,6 +88,8 @@ void HAL_COMP_MspDeInit(COMP_HandleTypeDef* compHandle)
     */
     HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin);
 
+    /* COMP1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(COMP_IRQn);
   /* USER CODE BEGIN COMP1_MspDeInit 1 */
 
   /* USER CODE END COMP1_MspDeInit 1 */

+ 0 - 1
firmware/targets/f3/Src/spi.c

@@ -19,7 +19,6 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "spi.h"
-#include "cmsis_os.h"
 
 /* USER CODE BEGIN 0 */
 void Enable_SPI(SPI_HandleTypeDef* spi);

+ 15 - 0
firmware/targets/f3/Src/stm32wbxx_it.c

@@ -57,6 +57,7 @@
 
 /* External variables --------------------------------------------------------*/
 extern PCD_HandleTypeDef hpcd_USB_FS;
+extern COMP_HandleTypeDef hcomp1;
 extern TIM_HandleTypeDef htim1;
 extern TIM_HandleTypeDef htim2;
 extern TIM_HandleTypeDef htim17;
@@ -206,6 +207,20 @@ void USB_LP_IRQHandler(void)
   /* USER CODE END USB_LP_IRQn 1 */
 }
 
+/**
+  * @brief This function handles COMP1 and COMP2 interrupts through EXTI lines 20 and 21.
+  */
+void COMP_IRQHandler(void)
+{
+  /* USER CODE BEGIN COMP_IRQn 0 */
+
+  /* USER CODE END COMP_IRQn 0 */
+  HAL_COMP_IRQHandler(&hcomp1);
+  /* USER CODE BEGIN COMP_IRQn 1 */
+
+  /* USER CODE END COMP_IRQn 1 */
+}
+
 /**
   * @brief This function handles EXTI line[9:5] interrupts.
   */

+ 8 - 3
firmware/targets/f3/f3.ioc

@@ -17,8 +17,10 @@ VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
 RCC.RTCFreq_Value=32768
 PA3.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
 PA6.GPIO_Label=PA6
+COMP1.Hysteresis=COMP_HYSTERESIS_HIGH
 PD0.Locked=true
 PC5.Mode=INP
+VP_COMP1_VS_VREFINT14.Signal=COMP1_VS_VREFINT14
 USART1.IPParameters=VirtualMode-Asynchronous
 PA3.GPIO_Speed=GPIO_SPEED_FREQ_LOW
 PB13.Signal=TIM1_CH1N
@@ -37,6 +39,7 @@ SPI1.Direction=SPI_DIRECTION_2LINES
 TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICPolarity_CH1,AutoReloadPreload,Prescaler,Channel-Input_Capture2_from_TI1
 RCC.APB2TimFreq_Value=64000000
 PCC.Ble.PowerLevel=Min
+COMP1.Mode=COMP_POWERMODE_MEDIUMSPEED
 PB6.Signal=USART1_TX
 PB6.Mode=Asynchronous
 SPI1.CalculateBaudRate=4.0 MBits/s
@@ -175,7 +178,7 @@ Mcu.Pin50=PB6
 Mcu.Pin55=VP_FREERTOS_VS_CMSIS_V2
 Mcu.Pin56=VP_HSEM_VS_HSEM
 Mcu.Pin53=VP_ADC1_Vref_Input
-Mcu.Pin54=VP_COMP1_VS_VREFINT12
+Mcu.Pin54=VP_COMP1_VS_VREFINT14
 PC6.Locked=true
 PA9.Signal=I2C1_SCL
 VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
@@ -216,6 +219,7 @@ RCC.RNGFreq_Value=32000
 PC2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
 VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input
 Mcu.Pin30=PE4
+NVIC.COMP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true
 PA1.GPIO_Label=LED_RED
 Mcu.Pin33=PB14
 Mcu.Pin34=PB15
@@ -312,7 +316,6 @@ PA11.Mode=Device
 PB0.GPIO_Label=DISPLAY_RST
 VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar
 PB11.GPIO_PuPd=GPIO_PULLUP
-VP_COMP1_VS_VREFINT12.Signal=COMP1_VS_VREFINT12
 PC13.GPIO_Label=BUTTON_BACK
 PB13.GPIO_Label=RFID_OUT
 PB11.Signal=GPXTI11
@@ -401,7 +404,6 @@ PE4.Signal=GPIO_Output
 PB0.Locked=true
 FREERTOS.configTOTAL_HEAP_SIZE=40960
 PC14-OSC32_IN.GPIOParameters=GPIO_Label
-VP_COMP1_VS_VREFINT12.Mode=VREFINT_12
 ProjectManager.ProjectName=f3
 RCC.APB3Freq_Value=16000000
 PA6.Signal=GPIO_Analog
@@ -426,6 +428,7 @@ OSC_IN.GPIO_Label=QUARTZ_32KHZ_IN
 PC2.GPIO_Label=BUTTON_OK
 PC14-OSC32_IN.Locked=true
 PA12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+COMP1.TriggerMode=COMP_TRIGGERMODE_IT_RISING_FALLING
 PB15.Locked=true
 PB3.Locked=true
 PB4.Signal=SPI1_MISO
@@ -463,6 +466,7 @@ PC12.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
 USART1.VirtualMode-Asynchronous=VM_ASYNC
 PA13.Signal=SYS_JTMS-SWDIO
 FREERTOS.configUSE_IDLE_HOOK=1
+VP_COMP1_VS_VREFINT14.Mode=VREFINT_14
 PA9.Mode=I2C
 TIM1.Channel-Output\ Compare1\ CH1N=TIM_CHANNEL_1
 FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1
@@ -492,6 +496,7 @@ TIM16.Period=291
 NVIC.SavedSystickIrqHandlerGenerated=true
 RCC.APB2Freq_Value=64000000
 PC11.PinState=GPIO_PIN_SET
+COMP1.IPParameters=TriggerMode,Hysteresis,Mode
 MxCube.Version=6.0.1
 VP_TIM2_VS_ClockSourceINT.Mode=Internal
 PC13.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI