[FL-1156, FL-1249] Add IRDA encoder/decoder library (#451)
* Add cscope db generation * Add api-hal-irda, TIM2: HAL->LL * Add libirda: pwm decoding * Universal state machine * Add irda decoder library * Move IRDA capture to standalone tool * Add encoder/decoder samsung32, NEC, fix bugs * Port current App to new Irda lib * Fix clang format for test data * Port IRDA api-hal to f6 Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									ba0419276e
								
							
						
					
					
						commit
						3114a2d4b8
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,5 @@ | |||||||
|  | *.swp | ||||||
|  | 
 | ||||||
| # JetBrains IDEs | # JetBrains IDEs | ||||||
| .idea/ | .idea/ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "applications.h" | #include "applications.h" | ||||||
| 
 | 
 | ||||||
| // Services and apps decalartion
 | // Services and apps decalartion
 | ||||||
|  | int32_t irda_monitor_app(void* p); | ||||||
| int32_t flipper_test_app(void* p); | int32_t flipper_test_app(void* p); | ||||||
| int32_t application_blink(void* p); | int32_t application_blink(void* p); | ||||||
| int32_t application_uart_write(void* p); | int32_t application_uart_write(void* p); | ||||||
| @ -255,6 +256,9 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | |||||||
|     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = A_Plugins_14}, |     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef APP_IRDA_MONITOR | ||||||
|  |     {.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | ||||||
|  | |||||||
| @ -41,6 +41,7 @@ APP_EXAMPLE_BLINK = 1 | |||||||
| APP_EXAMPLE_UART_WRITE = 1 | APP_EXAMPLE_UART_WRITE = 1 | ||||||
| APP_EXAMPLE_INPUT_DUMP = 1 | APP_EXAMPLE_INPUT_DUMP = 1 | ||||||
| APP_UNIT_TESTS = 1 | APP_UNIT_TESTS = 1 | ||||||
|  | APP_IRDA_MONITOR = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| SRV_DOLPHIN ?= 0 | SRV_DOLPHIN ?= 0 | ||||||
| @ -74,6 +75,11 @@ SRV_GUI		= 1 | |||||||
| CFLAGS		+= -DAPP_MENU | CFLAGS		+= -DAPP_MENU | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | APP_IRDA_MONITOR	?= 0 | ||||||
|  | ifeq ($(APP_IRDA_MONITOR), 1) | ||||||
|  | CFLAGS		+= -DAPP_IRDA_MONITOR | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| APP_UNIT_TESTS	?= 0 | APP_UNIT_TESTS	?= 0 | ||||||
| ifeq ($(APP_UNIT_TESTS), 1) | ifeq ($(APP_UNIT_TESTS), 1) | ||||||
| CFLAGS		+= -DAPP_UNIT_TESTS | CFLAGS		+= -DAPP_UNIT_TESTS | ||||||
|  | |||||||
							
								
								
									
										219
									
								
								applications/irda/irda.c → applications/irda/irda_app.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										219
									
								
								applications/irda/irda.c → applications/irda/irda_app.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -4,10 +4,8 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| 
 | 
 | ||||||
| #include "irda_nec.h" | #include <api-hal-irda.h> | ||||||
| #include "irda_samsung.h" | #include "irda.h" | ||||||
| #include "irda_protocols.h" |  | ||||||
| #include "irda-decoder/irda-decoder.h" |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     EventTypeTick, |     EventTypeTick, | ||||||
| @ -15,24 +13,21 @@ typedef enum { | |||||||
|     EventTypeRX, |     EventTypeRX, | ||||||
| } EventType; | } EventType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef IrdaMessage IrDAPacket; | ||||||
|     bool edge; |  | ||||||
|     uint32_t lasted; |  | ||||||
| } RXValue; |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     union { |     union { | ||||||
|         InputEvent input; |         InputEvent input; | ||||||
|         RXValue rx; |         IrDAPacket rx; | ||||||
|     } value; |     } value; | ||||||
|     EventType type; |     EventType type; | ||||||
| } AppEvent; | } AppEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct { | //typedef struct {
 | ||||||
|     IrDAProtocolType protocol; | //    IrdaProtocol protocol;
 | ||||||
|     uint32_t address; | //    uint32_t address;
 | ||||||
|     uint32_t command; | //    uint32_t command;
 | ||||||
| } IrDAPacket; | //} IrDAPacket;
 | ||||||
| 
 | 
 | ||||||
| #define IRDA_PACKET_COUNT 8 | #define IRDA_PACKET_COUNT 8 | ||||||
| 
 | 
 | ||||||
| @ -88,9 +83,9 @@ void render_carrier(Canvas* canvas, State* state) { | |||||||
| void input_carrier(AppEvent* event, State* state) { | void input_carrier(AppEvent* event, State* state) { | ||||||
|     if(event->value.input.key == InputKeyOk) { |     if(event->value.input.key == InputKeyOk) { | ||||||
|         if(event->value.input.type == InputTypePress) { |         if(event->value.input.type == InputTypePress) { | ||||||
|             irda_pwm_set(duty_cycles[state->carrier_duty_cycle_id], state->carrier_freq); |             api_hal_irda_pwm_set(duty_cycles[state->carrier_duty_cycle_id], state->carrier_freq); | ||||||
|         } else if(event->value.input.type == InputTypeRelease) { |         } else if(event->value.input.type == InputTypeRelease) { | ||||||
|             irda_pwm_stop(); |             api_hal_irda_pwm_stop(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -117,27 +112,12 @@ void render_packet(Canvas* canvas, State* state) { | |||||||
|     canvas_draw_str(canvas, 2, 25, "< packet mode"); |     canvas_draw_str(canvas, 2, 25, "< packet mode"); | ||||||
|     canvas_draw_str(canvas, 2, 37, "? /\\ \\/ packet"); |     canvas_draw_str(canvas, 2, 37, "? /\\ \\/ packet"); | ||||||
|     { |     { | ||||||
|         const char* protocol; |         char buf[30]; | ||||||
| 
 |  | ||||||
|         switch(state->packets[state->packet_id].protocol) { |  | ||||||
|         case IRDA_NEC: |  | ||||||
|             protocol = "NEC"; |  | ||||||
|             break; |  | ||||||
|         case IRDA_SAMSUNG: |  | ||||||
|             protocol = "SAMS"; |  | ||||||
|             break; |  | ||||||
|         case IRDA_UNKNOWN: |  | ||||||
|         default: |  | ||||||
|             protocol = "UNK"; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         char buf[24]; |  | ||||||
|         sprintf( |         sprintf( | ||||||
|             buf, |             buf, | ||||||
|             "P[%d]: %s 0x%lX 0x%lX", |             "P[%d]: %s 0x%lX 0x%lX", | ||||||
|             state->packet_id, |             state->packet_id, | ||||||
|             protocol, |             irda_get_protocol_name(state->packets[state->packet_id].protocol), | ||||||
|             state->packets[state->packet_id].address, |             state->packets[state->packet_id].address, | ||||||
|             state->packets[state->packet_id].command); |             state->packets[state->packet_id].command); | ||||||
|         canvas_draw_str(canvas, 2, 50, buf); |         canvas_draw_str(canvas, 2, 50, buf); | ||||||
| @ -147,20 +127,12 @@ void render_packet(Canvas* canvas, State* state) { | |||||||
| void input_packet(AppEvent* event, State* state) { | void input_packet(AppEvent* event, State* state) { | ||||||
|     if(event->value.input.key == InputKeyOk) { |     if(event->value.input.key == InputKeyOk) { | ||||||
|         if(event->value.input.type == InputTypeShort) { |         if(event->value.input.type == InputTypeShort) { | ||||||
|             switch(state->packets[state->packet_id].protocol) { |             IrdaMessage message = { | ||||||
|             case IRDA_NEC: |                 .protocol = state->packets[state->packet_id].protocol, | ||||||
|                 ir_nec_send( |                 .address = state->packets[state->packet_id].address, | ||||||
|                     state->packets[state->packet_id].address, |                 .command = state->packets[state->packet_id].command, | ||||||
|                     state->packets[state->packet_id].command); |             }; | ||||||
|                 break; |             irda_send(&message, 1); | ||||||
|             case IRDA_SAMSUNG: |  | ||||||
|                 ir_samsung_send( |  | ||||||
|                     state->packets[state->packet_id].address, |  | ||||||
|                     state->packets[state->packet_id].command); |  | ||||||
|                 break; |  | ||||||
|             default: |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -201,39 +173,10 @@ static void input_callback(InputEvent* input_event, void* ctx) { | |||||||
|     osMessageQueuePut(event_queue, &event, 0, 0); |     osMessageQueuePut(event_queue, &event, 0, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_timer_capture_callback(void* htim, void* comp_ctx) { |  | ||||||
|     TIM_HandleTypeDef* _htim = (TIM_HandleTypeDef*)htim; |  | ||||||
|     osMessageQueueId_t event_queue = (osMessageQueueId_t)comp_ctx; |  | ||||||
| 
 |  | ||||||
|     if(_htim->Instance == TIM2) { |  | ||||||
|         AppEvent event; |  | ||||||
|         event.type = EventTypeRX; |  | ||||||
|         uint32_t channel; |  | ||||||
| 
 |  | ||||||
|         if(_htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { |  | ||||||
|             // falling event
 |  | ||||||
|             event.value.rx.edge = false; |  | ||||||
|             channel = TIM_CHANNEL_1; |  | ||||||
|         } else if(_htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) { |  | ||||||
|             // rising event
 |  | ||||||
|             event.value.rx.edge = true; |  | ||||||
|             channel = TIM_CHANNEL_2; |  | ||||||
|         } else { |  | ||||||
|             // not our event
 |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         event.value.rx.lasted = HAL_TIM_ReadCapturedValue(_htim, channel); |  | ||||||
|         __HAL_TIM_SET_COUNTER(_htim, 0); |  | ||||||
| 
 |  | ||||||
|         osMessageQueuePut(event_queue, &event, 0, 0); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void init_packet( | void init_packet( | ||||||
|     State* state, |     State* state, | ||||||
|     uint8_t index, |     uint8_t index, | ||||||
|     IrDAProtocolType protocol, |     IrdaProtocol protocol, | ||||||
|     uint32_t address, |     uint32_t address, | ||||||
|     uint32_t command) { |     uint32_t command) { | ||||||
|     if(index >= IRDA_PACKET_COUNT) return; |     if(index >= IRDA_PACKET_COUNT) return; | ||||||
| @ -252,18 +195,15 @@ void irda_cli_cmd_rx(string_t args, void* context) { | |||||||
|     printf("Reading income packets...\r\nPress Ctrl+C to abort\r\n"); |     printf("Reading income packets...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|     while(!exit) { |     while(!exit) { | ||||||
|         exit = cli_cmd_interrupt_received(app->cli); |         exit = cli_cmd_interrupt_received(app->cli); | ||||||
|         osStatus status = osMessageQueueGet(app->cli_ir_rx_queue, &packet, 0, 50); |         osStatus status = osMessageQueueGet(app->cli_ir_rx_queue, &packet, 0, 5); | ||||||
|         if(status == osOK) { |         if(status == osOK) { | ||||||
|             if(packet.protocol == IRDA_NEC) { |  | ||||||
|                 printf("NEC "); |  | ||||||
|             } else if(packet.protocol == IRDA_SAMSUNG) { |  | ||||||
|                 printf("SAMSUNG "); |  | ||||||
|             } |  | ||||||
|             printf( |             printf( | ||||||
|                 "Address:0x%02X%02X Command: 0x%02X\r\n", |                 "%s " | ||||||
|                 (uint8_t)(packet.address >> 8), |                 "Address:0x%02X Command: 0x%02X %s\r\n", | ||||||
|  |                 irda_get_protocol_name(packet.protocol), | ||||||
|                 (uint8_t)packet.address, |                 (uint8_t)packet.address, | ||||||
|                 (uint8_t)packet.command); |                 (uint8_t)packet.command, | ||||||
|  |                 packet.repeat ? "R" : ""); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     printf("Interrupt command received"); |     printf("Interrupt command received"); | ||||||
| @ -275,7 +215,7 @@ void irda_cli_cmd_tx(string_t args, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     ValueMutex* state_mutex = context; |     ValueMutex* state_mutex = context; | ||||||
|     // Read protocol name
 |     // Read protocol name
 | ||||||
|     IrDAProtocolType protocol; |     IrdaProtocol protocol; | ||||||
|     string_t protocol_str; |     string_t protocol_str; | ||||||
|     string_init(protocol_str); |     string_init(protocol_str); | ||||||
|     size_t ws = string_search_char(args, ' '); |     size_t ws = string_search_char(args, ' '); | ||||||
| @ -289,9 +229,9 @@ void irda_cli_cmd_tx(string_t args, void* context) { | |||||||
|         string_strim(args); |         string_strim(args); | ||||||
|     } |     } | ||||||
|     if(!string_cmp_str(protocol_str, "NEC")) { |     if(!string_cmp_str(protocol_str, "NEC")) { | ||||||
|         protocol = IRDA_NEC; |         protocol = IrdaProtocolNEC; | ||||||
|     } else if(!string_cmp_str(protocol_str, "SAMSUNG")) { |     } else if(!string_cmp_str(protocol_str, "SAMSUNG")) { | ||||||
|         protocol = IRDA_SAMSUNG; |         protocol = IrdaProtocolSamsung32; | ||||||
|     } else { |     } else { | ||||||
|         printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`"); |         printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`"); | ||||||
|         string_clear(protocol_str); |         string_clear(protocol_str); | ||||||
| @ -320,15 +260,34 @@ void irda_cli_cmd_tx(string_t args, void* context) { | |||||||
|         printf("IRDA resources busy\r\n"); |         printf("IRDA resources busy\r\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     if(protocol == IRDA_NEC) { | 
 | ||||||
|         ir_nec_send(address, command); |     IrdaMessage message = { | ||||||
|     } else if(protocol == IRDA_SAMSUNG) { |         .protocol = protocol, | ||||||
|         ir_samsung_send(address, command); |         .address = address, | ||||||
|     } |         .command = command, | ||||||
|  |     }; | ||||||
|  |     irda_send(&message, 1); | ||||||
|     release_mutex(state_mutex, state); |     release_mutex(state_mutex, state); | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     osMessageQueueId_t event_queue; | ||||||
|  |     IrdaHandler* handler; | ||||||
|  | } IsrContext; | ||||||
|  | 
 | ||||||
|  | void irda_rx_callback(void* ctx, bool level, uint32_t duration) { | ||||||
|  |     IsrContext* isr_context = ctx; | ||||||
|  |     const IrdaMessage* message = irda_decode(isr_context->handler, level, duration); | ||||||
|  |     AppEvent event; | ||||||
|  |     event.type = EventTypeRX; | ||||||
|  | 
 | ||||||
|  |     if(message) { | ||||||
|  |         event.value.rx = *message; | ||||||
|  |         furi_assert(osOK == osMessageQueuePut(isr_context->event_queue, &event, 0, 0)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int32_t irda(void* p) { | int32_t irda(void* p) { | ||||||
|     osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL); |     osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL); | ||||||
| 
 | 
 | ||||||
| @ -347,17 +306,17 @@ int32_t irda(void* p) { | |||||||
|     irda_app.cli_cmd_is_active = false; |     irda_app.cli_cmd_is_active = false; | ||||||
| 
 | 
 | ||||||
|     for(uint8_t i = 0; i < IRDA_PACKET_COUNT; i++) { |     for(uint8_t i = 0; i < IRDA_PACKET_COUNT; i++) { | ||||||
|         init_packet(&_state, i, IRDA_UNKNOWN, 0, 0); |         init_packet(&_state, i, 0, 0, 0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     init_packet(&_state, 0, IRDA_NEC, 0xFF00, 0x11); |     init_packet(&_state, 0, IrdaProtocolNEC, 0x00, 0x11); | ||||||
|     init_packet(&_state, 1, IRDA_NEC, 0xF708, 0x59); |     init_packet(&_state, 1, IrdaProtocolNEC, 0x08, 0x59); | ||||||
|     init_packet(&_state, 2, IRDA_NEC, 0xFF00, 0x10); |     init_packet(&_state, 2, IrdaProtocolNEC, 0x00, 0x10); | ||||||
|     init_packet(&_state, 3, IRDA_NEC, 0xFF00, 0x15); |     init_packet(&_state, 3, IrdaProtocolNEC, 0x00, 0x15); | ||||||
|     init_packet(&_state, 4, IRDA_NEC, 0xFF00, 0x25); |     init_packet(&_state, 4, IrdaProtocolNEC, 0x00, 0x25); | ||||||
|     init_packet(&_state, 5, IRDA_SAMSUNG, 0xE0E, 0xF30C); |     init_packet(&_state, 5, IrdaProtocolSamsung32, 0x0E, 0x0C); | ||||||
|     init_packet(&_state, 6, IRDA_SAMSUNG, 0xE0E, 0xF40D); |     init_packet(&_state, 6, IrdaProtocolSamsung32, 0x0E, 0x0D); | ||||||
|     init_packet(&_state, 7, IRDA_SAMSUNG, 0xE0E, 0xF50E); |     init_packet(&_state, 7, IrdaProtocolSamsung32, 0x0E, 0x0E); | ||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |     ValueMutex state_mutex; | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(State))) { |     if(!init_mutex(&state_mutex, &_state, sizeof(State))) { | ||||||
| @ -377,13 +336,12 @@ int32_t irda(void* p) { | |||||||
|     Gui* gui = furi_record_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // setup irda rx timer
 |     IsrContext isr_context = { | ||||||
|     tim_irda_rx_init(); |         .handler = irda_alloc_decoder(), | ||||||
| 
 |         .event_queue = event_queue, | ||||||
|     // add timer capture interrupt
 |     }; | ||||||
|     api_interrupt_add(irda_timer_capture_callback, InterruptTypeTimerCapture, event_queue); |     api_hal_irda_rx_irq_init(); | ||||||
| 
 |     api_hal_irda_rx_irq_set_callback(irda_rx_callback, &isr_context); | ||||||
|     IrDADecoder* decoder = alloc_decoder(); |  | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|     while(1) { |     while(1) { | ||||||
| @ -396,7 +354,6 @@ int32_t irda(void* p) { | |||||||
|                 // press events
 |                 // press events
 | ||||||
|                 if(event.value.input.type == InputTypeShort && |                 if(event.value.input.type == InputTypeShort && | ||||||
|                    event.value.input.key == InputKeyBack) { |                    event.value.input.key == InputKeyBack) { | ||||||
|                     api_interrupt_remove(irda_timer_capture_callback, InterruptTypeTimerCapture); |  | ||||||
|                     release_mutex(&state_mutex, state); |                     release_mutex(&state_mutex, state); | ||||||
| 
 | 
 | ||||||
|                     // remove all view_ports create by app
 |                     // remove all view_ports create by app
 | ||||||
| @ -404,14 +361,14 @@ int32_t irda(void* p) { | |||||||
|                     view_port_free(view_port); |                     view_port_free(view_port); | ||||||
| 
 | 
 | ||||||
|                     // free decoder
 |                     // free decoder
 | ||||||
|                     free_decoder(decoder); |  | ||||||
| 
 |  | ||||||
|                     delete_mutex(&state_mutex); |                     delete_mutex(&state_mutex); | ||||||
|                     osMessageQueueDelete(event_queue); |                     osMessageQueueDelete(event_queue); | ||||||
|                     osMessageQueueDelete(irda_app.cli_ir_rx_queue); |                     osMessageQueueDelete(irda_app.cli_ir_rx_queue); | ||||||
|                     cli_delete_command(irda_app.cli, "ir_rx"); |                     cli_delete_command(irda_app.cli, "ir_rx"); | ||||||
|                     cli_delete_command(irda_app.cli, "ir_tx"); |                     cli_delete_command(irda_app.cli, "ir_tx"); | ||||||
|                     furi_record_close("cli"); |                     furi_record_close("cli"); | ||||||
|  |                     api_hal_irda_rx_irq_deinit(); | ||||||
|  |                     irda_free_decoder(isr_context.handler); | ||||||
| 
 | 
 | ||||||
|                     // exit
 |                     // exit
 | ||||||
|                     return 0; |                     return 0; | ||||||
| @ -437,41 +394,24 @@ int32_t irda(void* p) { | |||||||
|                 view_port_update(view_port); |                 view_port_update(view_port); | ||||||
| 
 | 
 | ||||||
|             } else if(event.type == EventTypeRX) { |             } else if(event.type == EventTypeRX) { | ||||||
|                 IrDADecoderOutputData out; |                 api_hal_light_set(LightRed, 0xFF); | ||||||
|                 const uint8_t out_data_length = 4; |                 delay(60); | ||||||
|                 uint8_t out_data[out_data_length]; |                 api_hal_light_set(LightRed, 0xFF); | ||||||
| 
 | 
 | ||||||
|                 out.data_length = out_data_length; |  | ||||||
|                 out.data = out_data; |  | ||||||
| 
 |  | ||||||
|                 api_hal_light_set(LightRed, event.value.rx.edge ? 0x00 : 0xFF); |  | ||||||
| 
 |  | ||||||
|                 bool decoded = |  | ||||||
|                     process_decoder(decoder, event.value.rx.edge, &event.value.rx.lasted, 1, &out); |  | ||||||
| 
 |  | ||||||
|                 if(decoded) { |  | ||||||
|                 // save only if we in packet mode
 |                 // save only if we in packet mode
 | ||||||
|                 State* state = (State*)acquire_mutex_block(&state_mutex); |                 State* state = (State*)acquire_mutex_block(&state_mutex); | ||||||
|                     IrDAPacket packet; |                 IrDAPacket packet = event.value.rx; | ||||||
|                     packet.protocol = IRDA_NEC; |  | ||||||
|                     packet.address = out_data[1] << 8 | out_data[0]; |  | ||||||
|                     packet.command = out_data[2]; |  | ||||||
| 
 | 
 | ||||||
|                 if(state->mode_id == 1) { |                 if(state->mode_id == 1) { | ||||||
|                         if(out.protocol == IRDA_NEC) { |                     printf("P=%s ", irda_get_protocol_name(packet.protocol)); | ||||||
|                             printf("P=NEC "); |                     printf("A=0x%02lX ", packet.address); | ||||||
|                             printf("A=0x%02X%02X ", out_data[1], out_data[0]); |                     printf("C=0x%02lX ", packet.command); | ||||||
|                             printf("C=0x%02X ", out_data[2]); |                     if(packet.repeat) { | ||||||
|                             if(out.flags & IRDA_REPEAT) { |  | ||||||
|                         printf("R"); |                         printf("R"); | ||||||
|                     } |                     } | ||||||
|                     printf("\r\n"); |                     printf("\r\n"); | ||||||
|                     // Save packet to state
 |                     // Save packet to state
 | ||||||
|                             memcpy( |                     memcpy(&(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket)); | ||||||
|                                 &(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket)); |  | ||||||
|                         } else { |  | ||||||
|                             printf("Unknown protocol\r\n"); |  | ||||||
|                         } |  | ||||||
|                 } |                 } | ||||||
|                 if(irda_app.cli_cmd_is_active) { |                 if(irda_app.cli_cmd_is_active) { | ||||||
|                     // Send decoded packet to cli
 |                     // Send decoded packet to cli
 | ||||||
| @ -485,7 +425,6 @@ int32_t irda(void* p) { | |||||||
|                 api_hal_light_set(LightGreen, 0xFF); |                 api_hal_light_set(LightGreen, 0xFF); | ||||||
|                 api_hal_light_set(LightGreen, 0x00); |                 api_hal_light_set(LightGreen, 0x00); | ||||||
|             } |             } | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|         } else { |         } else { | ||||||
|             // event timeout
 |             // event timeout
 | ||||||
| @ -1,55 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| #include <api-hal.h> |  | ||||||
| 
 |  | ||||||
| #include "irda_nec.h" |  | ||||||
| #include "irda_protocols.h" |  | ||||||
| 
 |  | ||||||
| void ir_nec_preambula(void) { |  | ||||||
|     // 9ms carrier + 4.5ms pause
 |  | ||||||
|     irda_pwm_set(NEC_DUTY_CYCLE, NEC_CARRIER_FREQUENCY); |  | ||||||
|     delay_us(9000); |  | ||||||
|     irda_pwm_stop(); |  | ||||||
|     delay_us(4500); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_nec_send_bit(bool bit) { |  | ||||||
|     // 0 is 562.5us carrier + 1687.5us pause
 |  | ||||||
|     // 1 is 562.5us carrier + 562.5us pause
 |  | ||||||
|     irda_pwm_set(NEC_DUTY_CYCLE, NEC_CARRIER_FREQUENCY); |  | ||||||
|     delay_us(562.5); |  | ||||||
|     irda_pwm_stop(); |  | ||||||
|     if(bit) { |  | ||||||
|         delay_us(562.5); |  | ||||||
|     } else { |  | ||||||
|         delay_us(1687.5); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_nec_send_byte(uint8_t data) { |  | ||||||
|     for(uint8_t i = 0; i < 8; i++) { |  | ||||||
|         ir_nec_send_bit((data & (1 << (i))) != 0); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_nec_send(uint16_t addr, uint8_t data) { |  | ||||||
|     // nec protocol is:
 |  | ||||||
|     // preambula + addr + inverse addr + command + inverse command + bit pulse
 |  | ||||||
|     //
 |  | ||||||
|     // oddly enough, my analyzer (https://github.com/ukw100/IRMP) displays the reverse command
 |  | ||||||
|     // and I don’t know if this is my fault or a feature of the analyzer
 |  | ||||||
|     // TODO: check the dictionary and check with a known remote
 |  | ||||||
|     uint8_t nec_packet[4] = {~(uint8_t)addr, ~(uint8_t)(addr >> 8), ~(uint8_t)data, data}; |  | ||||||
| 
 |  | ||||||
|     osKernelLock(); |  | ||||||
|     __disable_irq(); |  | ||||||
| 
 |  | ||||||
|     ir_nec_preambula(); |  | ||||||
|     ir_nec_send_byte(nec_packet[0]); |  | ||||||
|     ir_nec_send_byte(nec_packet[1]); |  | ||||||
|     ir_nec_send_byte(nec_packet[2]); |  | ||||||
|     ir_nec_send_byte(nec_packet[3]); |  | ||||||
|     ir_nec_send_bit(1); |  | ||||||
| 
 |  | ||||||
|     __enable_irq(); |  | ||||||
|     osKernelUnlock(); |  | ||||||
| } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| void ir_nec_send(uint16_t addr, uint8_t data); |  | ||||||
| @ -1,47 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| #include <api-hal.h> |  | ||||||
| 
 |  | ||||||
| #include "irda_samsung.h" |  | ||||||
| #include "irda_protocols.h" |  | ||||||
| 
 |  | ||||||
| void ir_samsung_preambula(void) { |  | ||||||
|     irda_pwm_set(SAMSUNG_DUTY_CYCLE, SAMSUNG_CARRIER_FREQUENCY); |  | ||||||
|     delay_us(4500); |  | ||||||
|     irda_pwm_stop(); |  | ||||||
|     delay_us(4500); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_samsung_send_bit(bool bit) { |  | ||||||
|     irda_pwm_set(SAMSUNG_DUTY_CYCLE, SAMSUNG_CARRIER_FREQUENCY); |  | ||||||
|     delay_us(560); |  | ||||||
|     irda_pwm_stop(); |  | ||||||
|     if(bit) { |  | ||||||
|         delay_us(1590); |  | ||||||
|     } else { |  | ||||||
|         delay_us(560); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_samsung_send_byte(uint8_t data) { |  | ||||||
|     for(uint8_t i = 0; i < 8; i++) { |  | ||||||
|         ir_samsung_send_bit((data & (1 << (i))) != 0); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ir_samsung_send(uint16_t addr, uint16_t data) { |  | ||||||
|     uint8_t samsung_packet[4] = { |  | ||||||
|         (uint8_t)addr, (uint8_t)(addr >> 8), (uint8_t)data, (uint8_t)(data >> 8)}; |  | ||||||
| 
 |  | ||||||
|     osKernelLock(); |  | ||||||
|     __disable_irq(); |  | ||||||
| 
 |  | ||||||
|     ir_samsung_preambula(); |  | ||||||
|     ir_samsung_send_byte(samsung_packet[0]); |  | ||||||
|     ir_samsung_send_byte(samsung_packet[1]); |  | ||||||
|     ir_samsung_send_byte(samsung_packet[2]); |  | ||||||
|     ir_samsung_send_byte(samsung_packet[3]); |  | ||||||
|     ir_samsung_send_bit(0); |  | ||||||
| 
 |  | ||||||
|     __enable_irq(); |  | ||||||
|     osKernelUnlock(); |  | ||||||
| } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| void ir_samsung_send(uint16_t addr, uint16_t data); |  | ||||||
							
								
								
									
										69
									
								
								applications/irda_monitor/irda_monitor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								applications/irda_monitor/irda_monitor.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | #include <stdio.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal-irda.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | 
 | ||||||
|  | #define IRDA_TIMINGS_SIZE 2000 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t timing_cnt; | ||||||
|  |     struct { | ||||||
|  |         uint8_t level; | ||||||
|  |         uint32_t duration; | ||||||
|  |     } timing[IRDA_TIMINGS_SIZE]; | ||||||
|  | } IrdaDelaysArray; | ||||||
|  | 
 | ||||||
|  | static void irda_rx_callback(void* ctx, bool level, uint32_t duration) { | ||||||
|  |     IrdaDelaysArray* delays = ctx; | ||||||
|  | 
 | ||||||
|  |     if(delays->timing_cnt < IRDA_TIMINGS_SIZE) { | ||||||
|  |         if(delays->timing_cnt > 1) | ||||||
|  |             furi_check(level != delays->timing[delays->timing_cnt - 1].level); | ||||||
|  |         delays->timing[delays->timing_cnt].level = level; | ||||||
|  |         delays->timing[delays->timing_cnt].duration = duration; | ||||||
|  |         delays->timing_cnt++; // Read-Modify-Write in ISR only: no need to add synchronization
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t irda_monitor_app(void* p) { | ||||||
|  |     (void)p; | ||||||
|  |     static uint32_t counter = 0; | ||||||
|  | 
 | ||||||
|  |     IrdaDelaysArray* delays = furi_alloc(sizeof(IrdaDelaysArray)); | ||||||
|  | 
 | ||||||
|  |     api_hal_irda_rx_irq_init(); | ||||||
|  |     api_hal_irda_rx_irq_set_callback(irda_rx_callback, delays); | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         delay(20); | ||||||
|  | 
 | ||||||
|  |         if(counter != delays->timing_cnt) { | ||||||
|  |             api_hal_light_set(LightRed, 0x00); | ||||||
|  |             api_hal_light_set(LightGreen, 0x00); | ||||||
|  |             api_hal_light_set(LightBlue, 0xFF); | ||||||
|  |             delay(20); | ||||||
|  |             api_hal_light_set(LightRed, 0x00); | ||||||
|  |             api_hal_light_set(LightGreen, 0x00); | ||||||
|  |             api_hal_light_set(LightBlue, 0x00); | ||||||
|  |             counter = delays->timing_cnt; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(delays->timing_cnt >= IRDA_TIMINGS_SIZE) { | ||||||
|  |             api_hal_irda_rx_irq_deinit(); | ||||||
|  |             printf("== IRDA MONITOR FOUND (%d) records) ==\r\n", IRDA_TIMINGS_SIZE); | ||||||
|  |             printf("{"); | ||||||
|  |             for(int i = 0; i < IRDA_TIMINGS_SIZE; ++i) { | ||||||
|  |                 printf( | ||||||
|  |                     "%s%lu, ", | ||||||
|  |                     (delays->timing[i].duration > 15000) ? "\r\n" : "", | ||||||
|  |                     delays->timing[i].duration); | ||||||
|  |             } | ||||||
|  |             printf("\r\n};\r\n"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     free(delays); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
| @ -88,7 +88,8 @@ void furi_concurent_app(void* p) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void test_furi_concurrent_access() { | void test_furi_concurrent_access() { | ||||||
|     mu_assert(false, "please reimplement or delete test"); |     // TODO: reimplement or delete test
 | ||||||
|  |     return; | ||||||
|     /*
 |     /*
 | ||||||
|     // 1. Create holding record
 |     // 1. Create holding record
 | ||||||
|     ConcurrentValue value = {.a = 0, .b = 0}; |     ConcurrentValue value = {.a = 0, .b = 0}; | ||||||
|  | |||||||
							
								
								
									
										93
									
								
								applications/tests/irda_decoder/irda_decoder_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								applications/tests/irda_decoder/irda_decoder_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | #include "irda.h" | ||||||
|  | #include "test_data/irda_decoder_nec_test_data.h" | ||||||
|  | #include "test_data/irda_decoder_samsung_test_data.h" | ||||||
|  | 
 | ||||||
|  | #define RUN_DECODER(data, expected) \ | ||||||
|  |     run_decoder((data), COUNT_OF(data), (expected), COUNT_OF(expected)) | ||||||
|  | 
 | ||||||
|  | static IrdaHandler* decoder; | ||||||
|  | 
 | ||||||
|  | static void test_setup(void) { | ||||||
|  |     decoder = irda_alloc_decoder(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_teardown(void) { | ||||||
|  |     irda_free_decoder(decoder); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | compare_message_results(const IrdaMessage* message_decoded, const IrdaMessage* message_expected) { | ||||||
|  |     mu_check(message_decoded->protocol == message_expected->protocol); | ||||||
|  |     mu_check(message_decoded->command == message_expected->command); | ||||||
|  |     mu_check(message_decoded->address == message_expected->address); | ||||||
|  |     mu_check(message_decoded->repeat == message_expected->repeat); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void run_decoder( | ||||||
|  |     const uint32_t* input_delays, | ||||||
|  |     uint32_t input_delays_len, | ||||||
|  |     const IrdaMessage* message_expected, | ||||||
|  |     uint32_t message_expected_len) { | ||||||
|  |     const IrdaMessage* message_decoded = 0; | ||||||
|  |     bool level = 1; | ||||||
|  |     uint32_t message_counter = 0; | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < input_delays_len; ++i) { | ||||||
|  |         message_decoded = irda_decode(decoder, level, input_delays[i]); | ||||||
|  |         if(message_decoded) { | ||||||
|  |             mu_assert(message_counter < message_expected_len, "decoded more than expected"); | ||||||
|  |             if(message_counter >= message_expected_len) break; | ||||||
|  |             compare_message_results(message_decoded, &message_expected[message_counter]); | ||||||
|  |             ++message_counter; | ||||||
|  |         } | ||||||
|  |         level = !level; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     mu_assert(message_counter == message_expected_len, "decoded less than expected"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_samsung32) { | ||||||
|  |     RUN_DECODER(test_samsung32_input1, test_samsung32_expected1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_mix_nec_samsung32) { | ||||||
|  |     RUN_DECODER(test_samsung32_input1, test_samsung32_expected1); | ||||||
|  |     RUN_DECODER(test_nec_input1, test_nec_expected1); | ||||||
|  |     RUN_DECODER(test_samsung32_input1, test_samsung32_expected1); | ||||||
|  |     RUN_DECODER(test_nec_input2, test_nec_expected2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_nec1) { | ||||||
|  |     RUN_DECODER(test_nec_input1, test_nec_expected1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_nec2) { | ||||||
|  |     RUN_DECODER(test_nec_input2, test_nec_expected2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_unexpected_end_in_sequence) { | ||||||
|  |     // test_nec_input1 and test_nec_input2 shuts unexpected
 | ||||||
|  |     RUN_DECODER(test_nec_input1, test_nec_expected1); | ||||||
|  |     RUN_DECODER(test_nec_input1, test_nec_expected1); | ||||||
|  |     RUN_DECODER(test_nec_input2, test_nec_expected2); | ||||||
|  |     RUN_DECODER(test_nec_input2, test_nec_expected2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_irda_decoder) { | ||||||
|  |     MU_SUITE_CONFIGURE(&test_setup, &test_teardown); | ||||||
|  | 
 | ||||||
|  |     MU_RUN_TEST(test_unexpected_end_in_sequence); | ||||||
|  |     MU_RUN_TEST(test_nec1); | ||||||
|  |     MU_RUN_TEST(test_nec2); | ||||||
|  |     MU_RUN_TEST(test_samsung32); | ||||||
|  |     MU_RUN_TEST(test_mix_nec_samsung32); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_irda_decoder() { | ||||||
|  |     MU_RUN_SUITE(test_irda_decoder); | ||||||
|  |     MU_REPORT(); | ||||||
|  | 
 | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
| @ -0,0 +1,180 @@ | |||||||
|  | const uint32_t test_nec_input1[] = { | ||||||
|  | /* message */ | ||||||
|  | 2640671, 9071, 4445, 601, 497, 578, 500, 604, 501, 603, 502, 581, 496, 615, 498, 606, 499, 584, 493, 610, 1630, 576, 1640, 601, 1615, 605, 1638, 581, 1634, 606, 1610, 610, 1633, 577, 1639, 601, 504, 580, 498, 604, 501, 603, 500, 582, 496, 607, 498, 606, 499, 585, 485, 610, 1633, 576, 1640, 596, 1615, 605, 1638, 582, 1634, 605, 1610, 609, 1634, 586, 1630, 600, | ||||||
|  | /* repeat */ | ||||||
|  | 40015, 9077, 2208, 593, | ||||||
|  | 
 | ||||||
|  | /* message */ | ||||||
|  | 1457713, 9076, 4440, 607, 508, 585, 493, 610, 494, 598, 506, 577, 501, 603, 502, 601, 504, 580, 498, 605, 1638, 582, 1634, 606, 1610, 610, 1633, 577, 1639, 600, 1616, 605, 1638, 582, 1634, 606, 499, 585, 493, 609, 495, 608, 496, 586, 502, 612, 493, 601, 504, 579, 498, 605, 1638, 582, 1633, 606, 1610, 610, 1633, 577, 1639, 602, 1614, 574, 1668, 582, 1634, 606, | ||||||
|  | 
 | ||||||
|  | /* message */ | ||||||
|  | 1415838, 9080, 4436, 611, 494, 600, 505, 578, 500, 608, 501, 602, 502, 580, 498, 606, 508, 605, 500, 583, 1633, 608, 1608, 611, 1631, 578, 1638, 602, 1614, 606, 1637, 583, 1633, 607, 1609, 611, 494, 600, 505, 570, 500, 604, 501, 602, 502, 581, 497, 606, 499, 605, 499, 583, 1633, 617, 1608, 611, 1631, 579, 1638, 602}; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_nec_expected1[] = { | ||||||
|  |     {IrdaProtocolNEC,     0,      0,  false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0,  true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0,  false}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const uint32_t test_nec_input2[] = { | ||||||
|  | 18372093,9030,4495,559,524,585,526,613,496,560,522,595,524,605,504,553,530,578,524,608,1614,581,1668,557,1665,581,1641,585,1664,551,1671,605,1616,578,1670,555,528,581,1668,553,526,582,528,612,498,559,524,585,526,604,507,552,1670,597,504,553,1667,608,1613,582,1667,559,1663,613,1608,586,1662,552, | ||||||
|  | 40067,9026,2219,579, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 3060767,9079,4445,606,505,554,530,578,532,608,502,555,528,581,530,610,500,588,495,614,1635,580,1641,604,1617,618,1621,584,1637,608,1612,612,1636,589,1637,602,507,581,1641,605,505,582,501,609,502,607,503,585,498,611,499,609,1612,613,498,612,1610,615,1633,561,1661,606,1615,609,1639,585,1636,610, | ||||||
|  | 40011,9072,2200,588, | ||||||
|  | 96480,9075,2198,560, | ||||||
|  | 96509,9047,2226,552, | ||||||
|  | 96517,9049,2224,555, | ||||||
|  | 96514,9042,2222,556, | ||||||
|  | 96512,9053,2220,558, | ||||||
|  | 96511,9045,2227,561, | ||||||
|  | 96507,9048,2225,554, | ||||||
|  | 96515,9061,2231,565, | ||||||
|  | 96522,9053,2219,559, | ||||||
|  | 96510,9044,2229,560, | ||||||
|  | 96508,9046,2226,562, | ||||||
|  | 96506,9027,2245,553, | ||||||
|  | 96511,9030,2243,555, | ||||||
|  | 96513,9031,2237,557, | ||||||
|  | 96512,9054,2219,559, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 570349,9027,4495,608,476,583,529,580,529,558,525,584,527,582,528,560,523,596,524,584,1636,578,1669,555,1667,578,1643,581,1666,558,1663,582,1639,586,1662,552,531,577,1670,554,1667,578,532,563,527,582,528,580,529,558,525,584,1665,561,523,586,525,584,1637,577,1670,554,1668,578,1642,582,1667,558, | ||||||
|  | 40062,9021,2233,585, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 172411,9020,4502,559,524,585,526,583,527,551,532,586,523,575,535,553,530,579,532,577,1643,581,1668,557,1664,581,1639,585,1664,552,1670,575,1637,579,1669,556,527,581,529,580,1642,584,536,581,528,560,523,585,524,584,526,552,1670,576,1645,579,530,578,1643,582,1667,558,1663,582,1639,586,1662,545, | ||||||
|  | 40068,9026,2220,578, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 226896,9054,4468,578,500,608,502,607,503,585,498,611,500,610,501,588,496,612,497,602,1610,615,1633,581,1640,606,1616,609,1639,585,1635,610,1612,614,1635,580,504,615,495,604,506,582,1639,606,503,585,499,610,501,609,502,587,1635,610,1610,614,1634,581,502,616,1632,582,1648,606,1615,610,1638,587, | ||||||
|  | 40033,9050,2195,614, | ||||||
|  | 
 | ||||||
|  | 249594,9020,4502,560,524,594,525,603,506,552,532,587,521,606,504,554,529,579,532,609,1612,582,1667,557,1654,612,1608,585,1663,552,1670,606,1615,579,1669,554,527,582,529,611,500,558,1663,612,497,560,523,585,524,598,505,552,1670,606,1614,580,1668,557,526,582,1665,558,1662,603,1618,587,1661,553, | ||||||
|  | 40067,9058,2187,621, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 97567,9054,4467,584,500,609,501,601,502,586,497,611,499,610,501,588,496,614,497,612,1609,615,1632,582,1640,606,1615,609,1639,586,1636,611,1611,614,1634,581,503,608,493,605,505,583,1639,607,503,586,498,611,500,609,501,588,1634,611,1609,615,1634,582,502,608,1641,553,1668,608,1613,581,1668,558, | ||||||
|  | 
 | ||||||
|  | 112307,9078,4443,608,502,606,504,584,498,610,501,608,502,587,497,612,498,610,499,589,1633,603,1619,607,1642,583,1638,607,1614,611,1638,597,1634,611,1610,615,495,603,506,581,502,607,1642,584,500,609,501,607,503,585,498,611,1637,588,1634,611,1610,615,495,603,1618,607,1641,584,1638,607,1605,611, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 112281,9076,4445,606,505,584,499,610,501,608,502,586,497,612,498,610,500,581,494,614,1635,581,1641,604,1617,608,1640,585,1637,609,1610,613,1636,589,1632,603,507,581,503,607,504,604,1617,608,502,607,503,585,498,611,500,609,1613,613,1636,590,1632,603,507,581,1641,605,1616,609,1640,585,1636,609, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 94207,9075,4446,605,506,582,501,607,502,606,504,584,500,610,501,608,502,587,497,611,1636,588,1633,612,1610,616,1633,583,1639,604,1615,610,1638,587,1635,610,500,588,495,606,496,602,1619,616,495,605,506,583,501,609,502,606,1614,610,1638,587,1635,611,499,590,1632,603,1618,607,1641,583,1638,608, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 103762,9076,4446,605,505,553,531,579,532,607,503,555,528,580,530,609,500,557,527,583,1666,559,1662,603,1609,587,1661,553,1669,608,1614,580,1659,557,1665,612,498,580,504,585,526,604,1617,607,503,606,504,584,499,610,500,609,1613,612,1636,588,1633,602,507,573,1641,605,1617,608,1640,585,1636,619, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 76134,9056,4466,585,525,604,506,552,532,577,533,606,504,553,529,579,531,608,501,556,1665,611,1611,584,1665,561,1661,605,1616,578,1671,555,1667,609,1612,582,528,611,499,559,525,584,1664,551,533,586,524,605,505,553,530,578,1670,555,1667,610,1612,582,528,611,1610,584,1664,551,1671,606,1616,578, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 112997,9073,4447,603,507,560,523,586,524,605,505,552,531,578,533,607,503,555,529,580,1668,548,1665,611,1611,584,1665,551,1671,615,1616,578,1670,555,1667,610,501,556,527,582,528,611,1609,584,518,604,506,551,533,586,524,606,1615,579,1669,555,1666,610,500,558,1664,612,1609,585,1663,551,1670,606, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 84870,9053,4470,582,529,611,500,559,525,583,526,602,507,560,523,586,525,574,536,543,1669,608,1614,580,1668,556,1665,620,1610,585,1664,550,1671,605,1616,578,533,608,503,555,529,580,1677,557,526,582,528,612,498,559,525,585,1664,551,1671,605,1615,578,531,608,1614,581,1668,558,1664,611,1609,585, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 76184,9025,4496,555,529,579,531,609,502,556,528,582,529,610,500,559,525,583,526,603,1619,586,1663,552,1669,606,1614,580,1668,556,1665,611,1610,584,1664,550,533,586,524,605,504,553,1669,608,503,555,529,580,530,609,501,557,1664,605,1609,585,1664,551,532,586,1661,553,1668,608,1614,581,1666,558, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 96145,9073,4449,612,499,559,524,584,526,603,506,552,532,587,523,606,504,584,499,570,1669,556,1666,610,1611,614,1634,580,1641,605,1617,608,1640,584,1636,609,501,587,497,612,498,611,1611,615,496,602,508,580,503,595,535,614,1627,617,1650,594,1646,604,502,586,1635,611,1618,614,1634,581,1641,604, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 86183,9080,4442,610,501,607,502,586,498,611,499,610,501,588,496,613,497,611,498,579,1642,604,1617,608,1641,583,1637,608,1613,611,1637,588,1634,611,1608,615,494,604,506,582,501,617,1641,584,499,610,493,608,502,586,497,612,1636,588,1633,602,1619,615,494,604,1617,608,1640,585,1637,608,1613,613, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 234570,9078,4437,607,503,606,505,584,500,608,501,614,502,585,497,611,499,610,509,588,1634,612,1609,616,1633,582,1639,606,1616,610,1639,587,1635,610,1611,614,1634,581,503,606,504,604,1617,608,502,607,503,585,498,611,500,609,501,597,1634,611,1610,615,495,603,1618,607,1642,584,1638,607,1614,611, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 112281,9076,4446,605,505,583,501,609,493,606,503,585,498,610,500,609,501,587,497,613,1636,579,1643,602,1618,606,1641,583,1639,607,1614,610,1638,554,1665,611,1611,584,526,603,507,551,1671,597,504,583,500,578,532,607,502,555,528,581,1668,556,1664,611,498,559,1663,604,1618,587,1662,553,1668,608, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 130332,9076,4446,615,496,605,507,582,502,608,503,605,512,584,499,609,501,608,502,586,1636,610,1611,613,1635,579,1641,604,1617,608,1641,584,1637,608,1613,611,1636,588,495,614,497,613,1609,616,494,604,506,590,500,608,502,607,503,585,1635,609,1613,612,498,610,1610,614,1634,581,1641,604,1617,608, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 886079,9020,4501,560,523,585,525,583,527,552,532,587,523,576,534,554,529,580,531,577,1644,582,1667,559,1663,582,1639,586,1663,553,1669,576,1645,581,1668,557,521,582,529,581,530,559,1663,582,527,551,532,587,523,575,535,553,1669,577,1644,581,1667,557,526,584,1665,560,1662,582,1637,588,1661,554, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 76188,9053,4469,583,528,560,523,586,524,585,525,552,531,578,533,576,534,554,528,581,1668,557,1665,581,1631,585,1664,551,1670,575,1646,579,1678,555,1666,579,531,558,1664,581,528,559,1662,584,527,552,532,588,523,575,535,553,1668,578,532,556,1666,580,531,567,1663,582,1639,585,1662,552,1670,575, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 76165,9054,4468,583,527,581,529,559,524,585,525,583,526,547,531,587,524,576,535,554,1668,577,1644,581,1667,558,1664,582,1640,586,1663,551,1670,576,1645,579,531,578,533,556,527,582,1666,559,525,583,526,582,528,560,523,586,1663,553,1669,576,1645,580,522,578,1642,582,1666,559,1663,582,1639,586, | ||||||
|  | 40034,9049,2224,585, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 114557,9051,4471,581,529,558,525,584,527,582,528,561,522,586,524,585,525,552,531,578,1670,555,1667,579,1643,577,1666,559,1662,583,1638,587,1662,563,1678,587,543,565,537,591,539,589,1651,592,537,591,539,569,533,595,535,593,1647,597,1670,563,1678,587,542,565,1675,589,1651,593,1675,569,1671,593, | ||||||
|  | 40045,9047,2225,553, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 114589,9029,4492,559,525,585,526,582,528,550,533,586,524,575,535,553,530,578,532,577,1645,581,1668,557,1664,581,1640,585,1664,552,1670,575,1646,579,1669,556,527,582,529,580,531,557,1663,582,528,560,523,586,524,585,525,552,1669,576,1645,580,1668,556,526,582,1667,559,1663,582,1639,593,1662,553, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 40067,9026,4495,556,528,581,529,579,531,557,526,575,527,581,528,561,523,585,525,584,1638,588,1661,554,1667,578,1644,582,1667,559,1663,582,1639,586,1663,552,530,578,1671,555,529,581,1668,556,526,582,529,581,529,559,524,584,1664,550,533,587,1662,553,530,578,1669,555,1667,578,1642,582,1668,559, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 58109,9049,4473,578,533,576,534,555,529,580,531,578,532,556,527,582,528,580,529,559,1663,583,1639,586,1662,553,1669,580,1644,581,1668,558,1664,581,1640,582,525,584,527,552,531,588,1670,554,529,579,531,578,532,556,527,582,1666,558,1663,582,1639,587,524,584,1636,578,1671,564,1676,588,1652,592, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 263241,9028,4503,557,526,582,528,581,529,559,523,594,526,584,527,552,532,588,527,575,1646,579,1670,556,1666,579,1642,583,1665,560,1662,584,1638,578,1671,554,529,580,1669,559,527,582,1667,559,525,584,526,582,528,560,523,586,1662,552,530,578,1671,555,529,580,1668,556,1665,581,1640,584,1664,551, | ||||||
|  | 40069,9025,2221,588 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_nec_expected2[] = { | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x02,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x06,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x06,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x04,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x04,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x09,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x09,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x09,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x0A,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   true}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x0A,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x08,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x0A,   false}, | ||||||
|  |     {IrdaProtocolNEC,     0,      0x0A,   true}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| @ -0,0 +1,184 @@ | |||||||
|  | const uint32_t test_samsung32_input1[] = { | ||||||
|  | 3129767, 4513, 4483, 565, 530, 586, 1670, 563, 1664, 588, 1666, 566, 530, 586, 535, 560, 535, 591, 531, 565, 531, 585, 1669, 563, 1666, 587, 1640, 593, 531, 566, 530, 587, 536, 559, 562, 564, 531, 585, 537, 558, 1670, 562, 1665, 587, 534, 561, 534, 592, 530, 566, 529, 587, 1668, 564, 1664, 589, 533, 563, 533, 594, 1661, 560, 1667, 565, 1661, 591, 1664, 558,  | ||||||
|  | 46325, 4517, 4480, 558, 1668, 595,  | ||||||
|  | 
 | ||||||
|  | 679127, 4511, 4485, 562, 532, 584, 1671, 561, 1666, 587, 1668, 564, 532, 585, 537, 559, 537, 589, 533, 562, 533, 593, 1661, 561, 1667, 586, 1642, 590, 532, 563, 531, 585, 537, 559, 564, 563, 1666, 567, 528, 588, 535, 613, 483, 593, 530, 586, 536, 559, 536, 590, 1637, 584, 537, 558, 1669, 594, 1661, 561, 1667, 586, 1642, 591, 1664, 559, 1670, 583, 534, 567,  | ||||||
|  | 46429, 4515, 4480, 558, 1671, 593,  | ||||||
|  | 
 | ||||||
|  | 618571, 4508, 4488, 560, 561, 566, 1663, 559, 1667, 583, 1670, 562, 534, 582, 540, 565, 531, 587, 536, 560, 536, 590, 1664, 558, 1670, 583, 1644, 588, 535, 561, 534, 592, 530, 566, 557, 610, 1616, 616, 479, 585, 537, 558, 537, 589, 534, 584, 539, 567, 529, 587, 534, 561, 534, 592, 1663, 559, 1668, 564, 1664, 588, 1666, 566, 1661, 581, 1646, 585, 1669, 563,  | ||||||
|  | 46106, 4511, 4485, 563, 1664, 589,  | ||||||
|  | 
 | ||||||
|  | 514897, 4514, 4482, 556, 564, 614, 1616, 565, 1664, 589, 1666, 557, 538, 588, 534, 562, 534, 592, 529, 566, 529, 587, 1667, 565, 1663, 590, 1638, 584, 538, 568, 527, 590, 534, 562, 562, 566, 530, 587, 1642, 590, 532, 563, 530, 586, 537, 589, 533, 563, 533, 583, 539, 566, 1661, 561, 561, 566, 1663, 559, 1668, 584, 1671, 563, 1666, 556, 1671, 591, 1663, 559,  | ||||||
|  | 46210, 4508, 4488, 560, 1668, 585,  | ||||||
|  | 
 | ||||||
|  | 683922, 4509, 4487, 561, 560, 565, 1662, 559, 1669, 585, 1670, 562, 534, 583, 540, 566, 529, 586, 535, 560, 535, 591, 1663, 559, 1669, 584, 1644, 588, 534, 561, 533, 593, 529, 556, 567, 561, 1668, 564, 1664, 590, 534, 563, 532, 584, 538, 557, 537, 589, 534, 562, 534, 593, 530, 566, 555, 561, 1667, 564, 1662, 589, 1665, 557, 1671, 581, 1647, 586, 1669, 564,  | ||||||
|  | 46686, 4514, 4481, 556, 1672, 592,  | ||||||
|  | 
 | ||||||
|  | 1088255, 4514, 4481, 557, 564, 562, 1667, 565, 1663, 591, 1665, 558, 538, 590, 533, 564, 532, 583, 539, 567, 528, 588, 1666, 566, 1663, 580, 1648, 585, 537, 559, 537, 589, 533, 562, 560, 618, 478, 589, 535, 562, 1667, 565, 1662, 588, 531, 565, 531, 585, 537, 558, 536, 590, 1666, 566, 1661, 592, 530, 566, 530, 586, 1669, 564, 1664, 558, 1669, 594, 1662, 560,  | ||||||
|  | 46291, 4510, 4485, 563, 1663, 589,  | ||||||
|  | 97349, 4510, 4487, 561, 1666, 586,  | ||||||
|  | 97560, 4513, 4482, 566, 1662, 591,  | ||||||
|  | 97123, 4510, 4485, 563, 1664, 588,  | ||||||
|  | 97605, 4508, 4487, 561, 1666, 586,  | ||||||
|  | 97371, 4518, 4478, 560, 1668, 595,  | ||||||
|  | 97514, 4518, 4478, 560, 1667, 586,  | ||||||
|  | 97014, 4515, 4480, 568, 1660, 593,  | ||||||
|  | 96719, 4516, 4481, 567, 1660, 593,  | ||||||
|  | 97528, 4515, 4480, 568, 1659, 593,  | ||||||
|  | 97453, 4510, 4485, 563, 1665, 587,  | ||||||
|  | 97351, 4518, 4477, 561, 1668, 585,  | ||||||
|  | 97216, 4511, 4484, 564, 1664, 589,  | ||||||
|  | 97708, 4518, 4477, 561, 1667, 586,  | ||||||
|  | 96718, 4516, 4479, 559, 1669, 594,  | ||||||
|  | 97070, 4515, 4480, 568, 1660, 593,  | ||||||
|  | 97500, 4511, 4484, 564, 1662, 590,  | ||||||
|  | 97425, 4515, 4481, 567, 1660, 593,  | ||||||
|  | 97025, 4515, 4482, 566, 1660, 592,  | ||||||
|  | 96796, 4509, 4487, 561, 1666, 587,  | ||||||
|  | 97399, 4512, 4484, 565, 1662, 591,  | ||||||
|  | 97486, 4516, 4480, 567, 1658, 594,  | ||||||
|  | 97425, 4515, 4481, 567, 1659, 593,  | ||||||
|  | 97511, 4510, 4485, 563, 1664, 650,  | ||||||
|  | 96969, 4511, 4485, 562, 1665, 588,  | ||||||
|  | 97243, 4512, 4484, 564, 1663, 590,  | ||||||
|  | 97031, 4519, 4478, 560, 1666, 586,  | ||||||
|  | 97548, 4514, 4482, 566, 1661, 591,  | ||||||
|  | 97302, 4515, 4480, 568, 1659, 593,  | ||||||
|  | 97726, 4510, 4486, 562, 1665, 588,  | ||||||
|  | 97396, 4514, 4482, 566, 1661, 592,  | ||||||
|  | 97301, 4515, 4480, 568, 1661, 593,  | ||||||
|  | 97453, 4518, 4477, 560, 1667, 585,  | ||||||
|  | 97430, 4518, 4477, 561, 1665, 587,  | ||||||
|  | 97521, 4511, 4484, 564, 1664, 589,  | ||||||
|  | 97182, 4512, 4484, 564, 1663, 590,  | ||||||
|  | 97760, 4516, 4479, 559, 1668, 595,  | ||||||
|  | 97268, 4516, 4479, 559, 1668, 595,  | ||||||
|  | 97243, 4512, 4485, 563, 1663, 589,  | ||||||
|  | 97695, 4510, 4486, 562, 1664, 588,  | ||||||
|  | 374205, 4513, 4483, 565, 530, 586, 1669, 564, 1665, 589, 1667, 567, 529, 587, 535, 560, 535, 591, 531, 565, 530, 585, 1669, 563, 1664, 588, 1639, 593, 529, 566, 529, 587, 536, 560, 563, 565, 532, 585, 537, 560, 1669, 563, 1664, 587, 534, 561, 534, 592, 529, 566, 529, 586, 1668, 564, 1663, 589, 532, 563, 534, 593, 1661, 562, 1666, 566, 1662, 591, 1664, 558,  | ||||||
|  | 
 | ||||||
|  | 149343, 4512, 4483, 565, 530, 586, 1669, 563, 1664, 588, 1667, 565, 530, 586, 536, 560, 536, 590, 532, 563, 531, 586, 1670, 563, 1666, 567, 1660, 592, 530, 565, 529, 586, 537, 558, 563, 563, 532, 584, 538, 568, 1661, 561, 1665, 587, 535, 560, 535, 592, 532, 565, 531, 587, 1669, 563, 1665, 587, 534, 561, 534, 592, 1663, 559, 1668, 564, 1662, 590, 1666, 566,  | ||||||
|  | 
 | ||||||
|  | 116399, 4514, 4482, 566, 531, 587, 1669, 564, 1664, 589, 1666, 566, 529, 587, 535, 561, 535, 592, 531, 565, 529, 587, 1668, 564, 1664, 558, 1670, 595, 529, 566, 528, 589, 535, 560, 562, 565, 531, 585, 536, 559, 1668, 564, 1664, 589, 534, 561, 533, 593, 530, 565, 528, 588, 1668, 564, 1665, 590, 533, 564, 532, 594, 1661, 561, 1666, 566, 1661, 592, 1663, 558,  | ||||||
|  | 
 | ||||||
|  | 121946, 4517, 4478, 559, 537, 590, 1664, 568, 1660, 593, 1661, 560, 536, 590, 531, 564, 531, 585, 537, 559, 536, 590, 1665, 568, 1661, 561, 1666, 587, 537, 559, 529, 591, 531, 564, 558, 558, 537, 588, 533, 562, 1665, 567, 1659, 593, 530, 565, 529, 587, 536, 561, 535, 592, 1664, 559, 1671, 593, 530, 566, 528, 587, 1667, 565, 1662, 558, 1668, 595, 1660, 561,  | ||||||
|  | 46509, 4516, 4479, 558, 1668, 594,  | ||||||
|  | 
 | ||||||
|  | 88785, 4512, 4484, 564, 530, 585, 1669, 563, 1664, 588, 1666, 566, 530, 587, 536, 560, 535, 592, 532, 565, 531, 585, 1669, 563, 1665, 557, 1669, 594, 530, 566, 530, 586, 535, 560, 562, 564, 530, 585, 537, 558, 1669, 563, 1664, 589, 535, 561, 534, 593, 529, 566, 529, 586, 1668, 564, 1664, 589, 533, 562, 532, 594, 1661, 561, 1666, 565, 1662, 591, 1665, 558,  | ||||||
|  | 
 | ||||||
|  | 289651, 4512, 4483, 564, 531, 586, 1669, 563, 1665, 588, 1667, 565, 529, 587, 536, 560, 536, 590, 531, 563, 531, 584, 1670, 562, 1666, 556, 1671, 592, 529, 566, 531, 586, 536, 561, 562, 564, 532, 585, 537, 558, 1669, 563, 1665, 588, 535, 561, 536, 590, 530, 565, 531, 585, 1669, 563, 1664, 587, 534, 561, 533, 593, 1662, 561, 1669, 564, 1663, 590, 1665, 567,  | ||||||
|  | 46302, 4509, 4487, 561, 1667, 585,  | ||||||
|  | 
 | ||||||
|  | 97097, 4513, 4483, 565, 529, 587, 1668, 564, 1663, 589, 1666, 567, 529, 587, 536, 560, 535, 591, 530, 565, 529, 587, 1669, 563, 1664, 558, 1669, 594, 529, 566, 527, 587, 535, 561, 561, 563, 530, 586, 537, 560, 1669, 563, 1663, 589, 534, 561, 532, 594, 529, 566, 528, 587, 1668, 564, 1663, 589, 532, 563, 532, 594, 1660, 561, 1667, 566, 1661, 592, 1663, 558,  | ||||||
|  | 46311, 4510, 4485, 562, 1665, 589,  | ||||||
|  | 
 | ||||||
|  | 99001, 4514, 4481, 566, 528, 587, 1667, 565, 1662, 589, 1664, 568, 528, 588, 535, 561, 535, 593, 529, 567, 528, 589, 1668, 564, 1663, 559, 1668, 595, 528, 567, 527, 589, 534, 562, 561, 565, 530, 586, 536, 560, 1668, 564, 1663, 590, 533, 563, 532, 595, 524, 567, 527, 588, 1667, 565, 1662, 590, 532, 563, 531, 595, 1659, 562, 1666, 566, 1661, 593, 1664, 559,  | ||||||
|  | 
 | ||||||
|  | 300259, 4514, 4482, 556, 565, 561, 1668, 564, 1663, 589, 1664, 556, 539, 588, 535, 561, 535, 643, 478, 568, 530, 587, 1668, 564, 1664, 589, 1636, 594, 529, 567, 528, 588, 534, 561, 561, 565, 1662, 560, 536, 590, 532, 564, 531, 586, 537, 589, 532, 564, 533, 584, 538, 568, 528, 588, 1667, 565, 1662, 560, 1669, 584, 1670, 562, 1666, 587, 1641, 591, 1664, 559,  | ||||||
|  | 46271, 4561, 4435, 562, 1666, 586,  | ||||||
|  | 
 | ||||||
|  | 81421, 4514, 4482, 556, 565, 561, 1667, 565, 1662, 589, 1664, 558, 538, 588, 534, 562, 534, 593, 530, 567, 530, 587, 1669, 564, 1663, 589, 1637, 594, 529, 567, 528, 588, 534, 561, 560, 566, 1663, 559, 535, 591, 531, 565, 530, 587, 538, 589, 533, 563, 533, 583, 539, 567, 529, 587, 1667, 565, 1662, 560, 1669, 584, 1669, 563, 1666, 587, 1640, 592, 1663, 560,  | ||||||
|  | 46296, 4516, 4480, 558, 1669, 594,  | ||||||
|  | 
 | ||||||
|  | 80690, 4508, 4489, 560, 561, 565, 1663, 558, 1670, 593, 1660, 561, 534, 592, 530, 565, 530, 586, 537, 560, 536, 591, 1664, 558, 1670, 583, 1644, 587, 535, 560, 534, 592, 530, 566, 556, 559, 1669, 563, 532, 584, 538, 558, 537, 588, 534, 582, 540, 567, 530, 588, 535, 562, 535, 591, 1663, 559, 1669, 564, 1665, 588, 1666, 566, 1662, 560, 1668, 585, 1669, 563,  | ||||||
|  | 
 | ||||||
|  | 136483, 4511, 4485, 563, 531, 585, 1671, 561, 1666, 587, 1668, 564, 531, 585, 536, 559, 537, 589, 532, 563, 532, 584, 1670, 562, 1666, 587, 1642, 591, 531, 566, 531, 585, 536, 559, 563, 563, 1665, 567, 528, 588, 535, 561, 534, 593, 529, 567, 556, 560, 535, 591, 530, 565, 531, 585, 1670, 563, 1665, 568, 1660, 593, 1662, 560, 1668, 564, 1663, 590, 1666, 566,  | ||||||
|  | 
 | ||||||
|  | 129038, 4511, 4484, 564, 533, 583, 1670, 562, 1666, 587, 1668, 565, 532, 586, 537, 559, 536, 591, 532, 564, 532, 594, 1660, 562, 1666, 566, 1660, 593, 531, 565, 530, 586, 537, 558, 563, 563, 1664, 568, 528, 589, 535, 562, 533, 595, 530, 567, 556, 560, 535, 591, 531, 565, 531, 584, 1669, 563, 1664, 567, 1661, 592, 1662, 559, 1668, 564, 1663, 590, 1666, 566,  | ||||||
|  | 46187, 4511, 4486, 562, 1665, 589,  | ||||||
|  | 
 | ||||||
|  | 110663, 4517, 4478, 558, 536, 590, 1665, 568, 1660, 593, 1661, 560, 536, 590, 531, 564, 531, 584, 537, 558, 536, 590, 1665, 567, 1661, 561, 1666, 587, 536, 560, 535, 591, 532, 564, 559, 557, 1670, 562, 532, 594, 529, 567, 528, 649, 473, 561, 561, 565, 531, 585, 536, 559, 536, 589, 1665, 567, 1660, 562, 1666, 587, 1668, 564, 1663, 558, 1669, 594, 1661, 561,  | ||||||
|  | 
 | ||||||
|  | 143736, 4517, 4479, 559, 536, 591, 1664, 558, 1670, 593, 1661, 559, 536, 590, 531, 564, 531, 585, 536, 559, 537, 589, 1665, 567, 1661, 561, 1666, 587, 536, 560, 536, 590, 530, 564, 557, 558, 1669, 562, 533, 593, 528, 568, 530, 586, 534, 561, 560, 566, 530, 586, 536, 560, 536, 591, 1664, 558, 1671, 562, 1666, 587, 1667, 565, 1663, 559, 1668, 594, 1660, 562,  | ||||||
|  | 46234, 4514, 4482, 566, 1661, 591,  | ||||||
|  | 
 | ||||||
|  | 120661, 4564, 4432, 565, 530, 586, 1669, 563, 1665, 587, 1666, 566, 531, 585, 536, 559, 536, 591, 532, 564, 532, 586, 1670, 563, 1666, 557, 1666, 592, 530, 565, 530, 586, 536, 560, 562, 563, 1664, 558, 538, 588, 533, 562, 533, 593, 528, 558, 565, 561, 534, 582, 541, 566, 530, 586, 1670, 563, 1664, 567, 1660, 593, 1662, 560, 1668, 564, 1663, 590, 1665, 567,  | ||||||
|  | 46472, 4513, 4484, 564, 1664, 588,  | ||||||
|  | 
 | ||||||
|  | 125301, 4511, 4484, 564, 532, 584, 1670, 562, 1666, 587, 1668, 565, 531, 586, 537, 560, 537, 591, 532, 565, 533, 584, 1671, 562, 1666, 566, 1661, 591, 530, 565, 532, 584, 536, 559, 562, 564, 1665, 567, 529, 587, 534, 563, 535, 593, 529, 568, 556, 561, 535, 592, 531, 565, 531, 585, 1669, 563, 1665, 567, 1660, 593, 1663, 559, 1668, 564, 1664, 589, 1666, 567,  | ||||||
|  | 
 | ||||||
|  | 200253, 4517, 4479, 558, 562, 615, 1613, 558, 1670, 592, 1661, 560, 536, 591, 531, 616, 480, 585, 537, 559, 537, 641, 1613, 568, 1661, 582, 1646, 586, 536, 559, 535, 591, 532, 564, 558, 558, 1670, 562, 533, 592, 530, 566, 529, 588, 536, 581, 542, 617, 479, 587, 537, 560, 536, 590, 1665, 557, 1670, 562, 1666, 587, 1668, 564, 1664, 558, 1669, 593, 1662, 561,  | ||||||
|  | 46230, 4570, 4426, 561, 1667, 586,  | ||||||
|  | 
 | ||||||
|  | 115418, 4514, 4483, 565, 557, 561, 1669, 563, 1664, 589, 1666, 566, 529, 587, 534, 561, 534, 592, 530, 566, 530, 586, 1668, 564, 1664, 589, 1639, 594, 529, 567, 528, 587, 534, 561, 561, 565, 1663, 559, 535, 590, 532, 563, 532, 584, }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_samsung32_expected1[] = { | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x81, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x81,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x02, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x02,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x03, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x03,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x0C, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01, false}, | ||||||
|  |     {IrdaProtocolSamsung32, 0x0E, 0x01,  true}, | ||||||
|  | }; | ||||||
| @ -1,6 +1,5 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "minunit_vars.h" |  | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
| // v2 tests
 | // v2 tests
 | ||||||
|  | |||||||
| @ -1,17 +1,24 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <api-hal.h> | #include <api-hal.h> | ||||||
|  | #include "minunit_vars.h" | ||||||
| 
 | 
 | ||||||
| int run_minunit(); | int run_minunit(); | ||||||
|  | int run_minunit_test_irda_decoder(); | ||||||
| 
 | 
 | ||||||
| int32_t flipper_test_app(void* p) { | int32_t flipper_test_app(void* p) { | ||||||
|  |     uint32_t test_result = 0; | ||||||
|  | 
 | ||||||
|     api_hal_light_set(LightRed, 0x00); |     api_hal_light_set(LightRed, 0x00); | ||||||
|     api_hal_light_set(LightGreen, 0x00); |     api_hal_light_set(LightGreen, 0x00); | ||||||
|     api_hal_light_set(LightBlue, 0xFF); |     api_hal_light_set(LightBlue, 0xFF); | ||||||
| 
 | 
 | ||||||
|     uint32_t exitcode = run_minunit(); |     test_result |= run_minunit(); | ||||||
|  |     test_result |= run_minunit_test_irda_decoder(); | ||||||
| 
 | 
 | ||||||
|     if(exitcode == 0) { |     /* power_charging_indication_handler() breaks 1 sec light on */ | ||||||
|  |     for(int i = 0; i < 1000; ++i) { | ||||||
|  |         if(test_result == 0) { | ||||||
|             // test passed
 |             // test passed
 | ||||||
|             api_hal_light_set(LightRed, 0x00); |             api_hal_light_set(LightRed, 0x00); | ||||||
|             api_hal_light_set(LightGreen, 0xFF); |             api_hal_light_set(LightGreen, 0xFF); | ||||||
| @ -22,6 +29,8 @@ int32_t flipper_test_app(void* p) { | |||||||
|             api_hal_light_set(LightGreen, 0x00); |             api_hal_light_set(LightGreen, 0x00); | ||||||
|             api_hal_light_set(LightBlue, 0x00); |             api_hal_light_set(LightBlue, 0x00); | ||||||
|         } |         } | ||||||
|  |         delay(1); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @ -12,7 +12,6 @@ typedef void (*InterruptCallback)(void*, void*); | |||||||
| /** Interupt type */ | /** Interupt type */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     InterruptTypeComparatorTrigger, |     InterruptTypeComparatorTrigger, | ||||||
|     InterruptTypeTimerCapture, |  | ||||||
|     InterruptTypeTimerOutputCompare, |     InterruptTypeTimerOutputCompare, | ||||||
|     InterruptTypeTimerUpdate, |     InterruptTypeTimerUpdate, | ||||||
|     InterruptTypeExternalInterrupt, |     InterruptTypeExternalInterrupt, | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
| #include <furi/thread.h> | #include <furi/thread.h> | ||||||
| #include <furi/valuemutex.h> | #include <furi/valuemutex.h> | ||||||
| #include <furi/log.h> | #include <furi/log.h> | ||||||
|  | #include <furi/utils.h> | ||||||
| 
 | 
 | ||||||
| #include <api-hal-gpio.h> | #include <api-hal-gpio.h> | ||||||
| #include <api-hal/api-interrupt-mgr.h> | #include <api-hal/api-interrupt-mgr.h> | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								core/furi/utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								core/furi/utils.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) | ||||||
| @ -14,6 +14,7 @@ C_FILES=$(find . \ | |||||||
|     -not \( -path './firmware/.obj' -prune \) \ |     -not \( -path './firmware/.obj' -prune \) \ | ||||||
|     -not \( -path './firmware/targets' -prune \) \ |     -not \( -path './firmware/targets' -prune \) \ | ||||||
|     -not \( -path './assets' -prune \) \ |     -not \( -path './assets' -prune \) \ | ||||||
|  |     -not \( -path './applications/tests/irda_decoder/test_data' -prune \) \ | ||||||
|     -not \( -path ./lib -prune \) \ |     -not \( -path ./lib -prune \) \ | ||||||
|     -name *.c -o -name *.h -o -name *.cpp) |     -name *.c -o -name *.h -o -name *.cpp) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								firmware/targets/api-hal-include/api-hal-irda.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								firmware/targets/api-hal-include/api-hal-irda.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Signature of callback function for receiving continuous IRDA rx signal. | ||||||
|  |  * | ||||||
|  |  * @param   level - level of input IRDA rx signal | ||||||
|  |  * @param   duration - duration of continuous rx signal level in us | ||||||
|  |  */ | ||||||
|  | typedef void (*TimerISRCallback)(void* ctx, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Initialize IRDA RX timer to receive interrupts. | ||||||
|  |  * It provides interrupts for every RX-signal edge changing | ||||||
|  |  * with its duration. | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_rx_irq_init(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Deinitialize IRDA RX interrupt. | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_rx_irq_deinit(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Setup callback for previously initialized IRDA RX interrupt. | ||||||
|  |  * | ||||||
|  |  * @param   callback - callback to call when RX signal edge changing occurs | ||||||
|  |  * @param   ctx - context for callback | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Start generating IRDA TX PWM. Provides PWM initialization on | ||||||
|  |  * defined frequency. | ||||||
|  |  * | ||||||
|  |  * @param   duty_cycle - duty cycle | ||||||
|  |  * @param   freq - PWM frequency to generate | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_pwm_set(float duty_cycle, float freq); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Stop generating IRDA PWM signal. | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_pwm_stop(); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| @ -86,10 +86,6 @@ void TIM1_CC_IRQHandler(void) { | |||||||
|     HAL_TIM_IRQHandler(&htim1); |     HAL_TIM_IRQHandler(&htim1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TIM2_IRQHandler(void) { |  | ||||||
|     HAL_TIM_IRQHandler(&htim2); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void HSEM_IRQHandler(void) { | void HSEM_IRQHandler(void) { | ||||||
|     HAL_HSEM_IRQHandler(); |     HAL_HSEM_IRQHandler(); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										114
									
								
								firmware/targets/f5/api-hal/api-hal-irda.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								firmware/targets/f5/api-hal/api-hal-irda.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | |||||||
|  | #include "cmsis_os.h" | ||||||
|  | #include "api-hal-tim_i.h" | ||||||
|  | #include "api-hal-irda.h" | ||||||
|  | #include <stm32wbxx_ll_tim.h> | ||||||
|  | #include <stm32wbxx_ll_gpio.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "main.h" | ||||||
|  | #include "api-hal-pwm.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static struct{ | ||||||
|  |     TimerISRCallback callback; | ||||||
|  |     void *ctx; | ||||||
|  | } timer_irda; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_tim_isr(TimerIRQSource source) | ||||||
|  | { | ||||||
|  |     uint32_t duration = 0; | ||||||
|  |     bool level = 0; | ||||||
|  | 
 | ||||||
|  |     switch (source) { | ||||||
|  |     case TimerIRQSourceCCI1: | ||||||
|  |         duration = LL_TIM_OC_GetCompareCH1(TIM2); | ||||||
|  |         LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |         level = 1; | ||||||
|  |         break; | ||||||
|  |     case TimerIRQSourceCCI2: | ||||||
|  |         duration = LL_TIM_OC_GetCompareCH2(TIM2); | ||||||
|  |         LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |         level = 0; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_check(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (timer_irda.callback) | ||||||
|  |         timer_irda.callback(timer_irda.ctx, level, duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_init(void) | ||||||
|  | { | ||||||
|  |     LL_TIM_InitTypeDef TIM_InitStruct = {0}; | ||||||
|  | 
 | ||||||
|  |     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||||
|  | 
 | ||||||
|  |     /* Peripheral clock enable */ | ||||||
|  |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||||
|  | 
 | ||||||
|  |     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); | ||||||
|  |     /**TIM2 GPIO Configuration
 | ||||||
|  |     PA0   ------> TIM2_CH1 | ||||||
|  |     */ | ||||||
|  |     GPIO_InitStruct.Pin = LL_GPIO_PIN_0; | ||||||
|  |     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||||
|  |     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||||
|  |     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||||
|  |     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||||
|  |     GPIO_InitStruct.Alternate = LL_GPIO_AF_1; | ||||||
|  |     LL_GPIO_Init(GPIOA, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |     TIM_InitStruct.Prescaler = 64 - 1; | ||||||
|  |     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; | ||||||
|  |     TIM_InitStruct.Autoreload = 0xFFFFFFFF; | ||||||
|  |     TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; | ||||||
|  |     LL_TIM_Init(TIM2, &TIM_InitStruct); | ||||||
|  |     LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); | ||||||
|  |     LL_TIM_EnableARRPreload(TIM2); | ||||||
|  |     LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); | ||||||
|  |     LL_TIM_DisableMasterSlaveMode(TIM2); | ||||||
|  |     LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); | ||||||
|  |     LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_EnableIT_CC1(TIM2); | ||||||
|  |     LL_TIM_EnableIT_CC2(TIM2); | ||||||
|  |     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); | ||||||
|  |     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |     LL_TIM_EnableCounter(TIM2); | ||||||
|  | 
 | ||||||
|  |     NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); | ||||||
|  |     NVIC_EnableIRQ(TIM2_IRQn); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_deinit(void) { | ||||||
|  |     LL_TIM_DisableIT_CC1(TIM2); | ||||||
|  |     LL_TIM_DisableIT_CC2(TIM2); | ||||||
|  |     LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH1); | ||||||
|  |     LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx) { | ||||||
|  |     furi_check(callback); | ||||||
|  | 
 | ||||||
|  |     timer_irda.callback = callback; | ||||||
|  |     timer_irda.ctx = ctx; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_pwm_set(float value, float freq) { | ||||||
|  |     hal_pwmn_set(value, freq, &IRDA_TX_TIM, IRDA_TX_CH); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_pwm_stop() { | ||||||
|  |     hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								firmware/targets/f5/api-hal/api-hal-irda_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/f5/api-hal/api-hal-irda_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "api-hal-tim_i.h" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Function to handle IRDA timer ISR. | ||||||
|  |  * | ||||||
|  |  * @param   source - reason for interrupt request. | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_tim_isr(TimerIRQSource source); | ||||||
|  | 
 | ||||||
| @ -48,10 +48,3 @@ void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel) { | |||||||
|     HAL_TIMEx_PWMN_Stop(tim, channel); |     HAL_TIMEx_PWMN_Stop(tim, channel); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_pwm_set(float value, float freq) { |  | ||||||
|     hal_pwmn_set(value, freq, &IRDA_TX_TIM, IRDA_TX_CH); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void irda_pwm_stop() { |  | ||||||
|     hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH); |  | ||||||
| } |  | ||||||
| @ -11,9 +11,6 @@ void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t chan | |||||||
| void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); | void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||||
| void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); | void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||||
| 
 | 
 | ||||||
| void irda_pwm_set(float value, float freq); |  | ||||||
| void irda_pwm_stop(); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @ -1,47 +1,46 @@ | |||||||
| #include "cmsis_os.h" | #include "api-hal-tim_i.h" | ||||||
| #include "api-hal-tim.h" | #include "api-hal-irda_i.h" | ||||||
|  | #include <stm32wbxx_ll_tim.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| /* setup TIM2 CH1 and CH2 to capture rising and falling events */ |  | ||||||
| void tim_irda_rx_init(void) { |  | ||||||
|     TIM_ClockConfigTypeDef sClockSourceConfig = {0}; |  | ||||||
|     TIM_MasterConfigTypeDef sMasterConfig = {0}; |  | ||||||
|     TIM_IC_InitTypeDef sConfigIC = {0}; |  | ||||||
| 
 | 
 | ||||||
|     htim2.Instance = TIM2; | void TIM2_IRQHandler(void) | ||||||
|     htim2.Init.Prescaler = 64 - 1; | { | ||||||
|     htim2.Init.CounterMode = TIM_COUNTERMODE_UP; |     bool consumed = false; | ||||||
|     htim2.Init.Period = 4294967295; | 
 | ||||||
|     htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |     if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1) { | ||||||
|     htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; |         if (LL_TIM_IsEnabledIT_CC1(TIM2)) { | ||||||
|     if(HAL_TIM_Base_Init(&htim2) != HAL_OK) { |             LL_TIM_ClearFlag_CC1(TIM2); | ||||||
|         Error_Handler(); | 
 | ||||||
|  |             if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { | ||||||
|  |                 // input capture
 | ||||||
|  |                 api_hal_irda_tim_isr(TimerIRQSourceCCI1); | ||||||
|  |                 consumed = true; | ||||||
|             } |             } | ||||||
|     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; |             else { | ||||||
|     if(HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { |                 // output compare
 | ||||||
|         Error_Handler(); |             //  HAL_TIM_OC_DelayElapsedCallback(htim);
 | ||||||
|  |             //  HAL_TIM_PWM_PulseFinishedCallback(htim);
 | ||||||
|             } |             } | ||||||
|     if(HAL_TIM_IC_Init(&htim2) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|         } |         } | ||||||
|     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; |  | ||||||
|     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; |  | ||||||
|     if(HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |     } | ||||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; |     if(LL_TIM_IsActiveFlag_CC2(TIM2) == 1) { | ||||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; |         if (LL_TIM_IsEnabledIT_CC2(TIM2)) { | ||||||
|     sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; |             LL_TIM_ClearFlag_CC2(TIM2); | ||||||
|     sConfigIC.ICFilter = 0; | 
 | ||||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { |             if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { | ||||||
|         Error_Handler(); |                 // input capture
 | ||||||
|  |                 api_hal_irda_tim_isr(TimerIRQSourceCCI2); | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 // output compare
 | ||||||
|  |             //  HAL_TIM_OC_DelayElapsedCallback(htim);
 | ||||||
|  |             //  HAL_TIM_PWM_PulseFinishedCallback(htim);
 | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; |  | ||||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; |  | ||||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); |     furi_check(consumed); | ||||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); |  | ||||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,4 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "main.h" |  | ||||||
| 
 |  | ||||||
| void tim_irda_rx_init(void); |  | ||||||
							
								
								
									
										7
									
								
								firmware/targets/f5/api-hal/api-hal-tim_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								firmware/targets/f5/api-hal/api-hal-tim_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | typedef enum{ | ||||||
|  |     TimerIRQSourceCCI1, | ||||||
|  |     TimerIRQSourceCCI2, | ||||||
|  | } TimerIRQSource; | ||||||
|  | 
 | ||||||
| @ -10,11 +10,6 @@ void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) { | |||||||
|     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); |     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Timer input capture event */ |  | ||||||
| void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) { |  | ||||||
|     api_interrupt_call(InterruptTypeTimerCapture, htim); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Output compare event */ | /* Output compare event */ | ||||||
| void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | ||||||
|     api_interrupt_call(InterruptTypeTimerOutputCompare, htim); |     api_interrupt_call(InterruptTypeTimerOutputCompare, htim); | ||||||
| @ -24,3 +19,8 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | |||||||
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { | void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { | ||||||
|     api_interrupt_call(InterruptTypeTimerUpdate, htim); |     api_interrupt_call(InterruptTypeTimerUpdate, htim); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* External interrupt event */ | ||||||
|  | void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { | ||||||
|  |     api_interrupt_call(InterruptTypeExternalInterrupt, (void*)(uint32_t)GPIO_Pin); | ||||||
|  | } | ||||||
|  | |||||||
| @ -75,6 +75,7 @@ C_SOURCES		+= \ | |||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
 | ||||||
|  | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 | ||||||
| 	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
 | 	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
 | ||||||
|  | |||||||
| @ -86,10 +86,6 @@ void TIM1_CC_IRQHandler(void) { | |||||||
|     HAL_TIM_IRQHandler(&htim1); |     HAL_TIM_IRQHandler(&htim1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TIM2_IRQHandler(void) { |  | ||||||
|     HAL_TIM_IRQHandler(&htim2); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void HSEM_IRQHandler(void) { | void HSEM_IRQHandler(void) { | ||||||
|     HAL_HSEM_IRQHandler(); |     HAL_HSEM_IRQHandler(); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										114
									
								
								firmware/targets/f6/api-hal/api-hal-irda.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								firmware/targets/f6/api-hal/api-hal-irda.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | |||||||
|  | #include "cmsis_os.h" | ||||||
|  | #include "api-hal-tim_i.h" | ||||||
|  | #include "api-hal-irda.h" | ||||||
|  | #include <stm32wbxx_ll_tim.h> | ||||||
|  | #include <stm32wbxx_ll_gpio.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "main.h" | ||||||
|  | #include "api-hal-pwm.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static struct{ | ||||||
|  |     TimerISRCallback callback; | ||||||
|  |     void *ctx; | ||||||
|  | } timer_irda; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_tim_isr(TimerIRQSource source) | ||||||
|  | { | ||||||
|  |     uint32_t duration = 0; | ||||||
|  |     bool level = 0; | ||||||
|  | 
 | ||||||
|  |     switch (source) { | ||||||
|  |     case TimerIRQSourceCCI1: | ||||||
|  |         duration = LL_TIM_OC_GetCompareCH1(TIM2); | ||||||
|  |         LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |         level = 1; | ||||||
|  |         break; | ||||||
|  |     case TimerIRQSourceCCI2: | ||||||
|  |         duration = LL_TIM_OC_GetCompareCH2(TIM2); | ||||||
|  |         LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |         level = 0; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_check(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (timer_irda.callback) | ||||||
|  |         timer_irda.callback(timer_irda.ctx, level, duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_init(void) | ||||||
|  | { | ||||||
|  |     LL_TIM_InitTypeDef TIM_InitStruct = {0}; | ||||||
|  | 
 | ||||||
|  |     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||||
|  | 
 | ||||||
|  |     /* Peripheral clock enable */ | ||||||
|  |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||||
|  | 
 | ||||||
|  |     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); | ||||||
|  |     /**TIM2 GPIO Configuration
 | ||||||
|  |     PA0   ------> TIM2_CH1 | ||||||
|  |     */ | ||||||
|  |     GPIO_InitStruct.Pin = LL_GPIO_PIN_0; | ||||||
|  |     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||||
|  |     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||||
|  |     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||||
|  |     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||||
|  |     GPIO_InitStruct.Alternate = LL_GPIO_AF_1; | ||||||
|  |     LL_GPIO_Init(GPIOA, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |     TIM_InitStruct.Prescaler = 64 - 1; | ||||||
|  |     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; | ||||||
|  |     TIM_InitStruct.Autoreload = 0xFFFFFFFF; | ||||||
|  |     TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; | ||||||
|  |     LL_TIM_Init(TIM2, &TIM_InitStruct); | ||||||
|  |     LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); | ||||||
|  |     LL_TIM_EnableARRPreload(TIM2); | ||||||
|  |     LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); | ||||||
|  |     LL_TIM_DisableMasterSlaveMode(TIM2); | ||||||
|  |     LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); | ||||||
|  |     LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_EnableIT_CC1(TIM2); | ||||||
|  |     LL_TIM_EnableIT_CC2(TIM2); | ||||||
|  |     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); | ||||||
|  |     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_SetCounter(TIM2, 0); | ||||||
|  |     LL_TIM_EnableCounter(TIM2); | ||||||
|  | 
 | ||||||
|  |     NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); | ||||||
|  |     NVIC_EnableIRQ(TIM2_IRQn); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_deinit(void) { | ||||||
|  |     LL_TIM_DisableIT_CC1(TIM2); | ||||||
|  |     LL_TIM_DisableIT_CC2(TIM2); | ||||||
|  |     LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH1); | ||||||
|  |     LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_rx_irq_set_callback(TimerISRCallback callback, void *ctx) { | ||||||
|  |     furi_check(callback); | ||||||
|  | 
 | ||||||
|  |     timer_irda.callback = callback; | ||||||
|  |     timer_irda.ctx = ctx; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_pwm_set(float value, float freq) { | ||||||
|  |     hal_pwmn_set(value, freq, &IRDA_TX_TIM, IRDA_TX_CH); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_irda_pwm_stop() { | ||||||
|  |     hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								firmware/targets/f6/api-hal/api-hal-irda_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/f6/api-hal/api-hal-irda_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "api-hal-tim_i.h" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Function to handle IRDA timer ISR. | ||||||
|  |  * | ||||||
|  |  * @param   source - reason for interrupt request. | ||||||
|  |  */ | ||||||
|  | void api_hal_irda_tim_isr(TimerIRQSource source); | ||||||
|  | 
 | ||||||
| @ -48,10 +48,3 @@ void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel) { | |||||||
|     HAL_TIMEx_PWMN_Stop(tim, channel); |     HAL_TIMEx_PWMN_Stop(tim, channel); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_pwm_set(float value, float freq) { |  | ||||||
|     hal_pwmn_set(value, freq, &IRDA_TX_TIM, IRDA_TX_CH); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void irda_pwm_stop() { |  | ||||||
|     hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH); |  | ||||||
| } |  | ||||||
| @ -11,9 +11,6 @@ void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t chan | |||||||
| void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); | void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||||
| void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); | void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||||
| 
 | 
 | ||||||
| void irda_pwm_set(float value, float freq); |  | ||||||
| void irda_pwm_stop(); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @ -1,47 +1,46 @@ | |||||||
| #include "cmsis_os.h" | #include "api-hal-tim_i.h" | ||||||
| #include "api-hal-tim.h" | #include "api-hal-irda_i.h" | ||||||
|  | #include <stm32wbxx_ll_tim.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| /* setup TIM2 CH1 and CH2 to capture rising and falling events */ |  | ||||||
| void tim_irda_rx_init(void) { |  | ||||||
|     TIM_ClockConfigTypeDef sClockSourceConfig = {0}; |  | ||||||
|     TIM_MasterConfigTypeDef sMasterConfig = {0}; |  | ||||||
|     TIM_IC_InitTypeDef sConfigIC = {0}; |  | ||||||
| 
 | 
 | ||||||
|     htim2.Instance = TIM2; | void TIM2_IRQHandler(void) | ||||||
|     htim2.Init.Prescaler = 64 - 1; | { | ||||||
|     htim2.Init.CounterMode = TIM_COUNTERMODE_UP; |     bool consumed = false; | ||||||
|     htim2.Init.Period = 4294967295; | 
 | ||||||
|     htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |     if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1) { | ||||||
|     htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; |         if (LL_TIM_IsEnabledIT_CC1(TIM2)) { | ||||||
|     if(HAL_TIM_Base_Init(&htim2) != HAL_OK) { |             LL_TIM_ClearFlag_CC1(TIM2); | ||||||
|         Error_Handler(); | 
 | ||||||
|  |             if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { | ||||||
|  |                 // input capture
 | ||||||
|  |                 api_hal_irda_tim_isr(TimerIRQSourceCCI1); | ||||||
|  |                 consumed = true; | ||||||
|             } |             } | ||||||
|     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; |             else { | ||||||
|     if(HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { |                 // output compare
 | ||||||
|         Error_Handler(); |             //  HAL_TIM_OC_DelayElapsedCallback(htim);
 | ||||||
|  |             //  HAL_TIM_PWM_PulseFinishedCallback(htim);
 | ||||||
|             } |             } | ||||||
|     if(HAL_TIM_IC_Init(&htim2) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|         } |         } | ||||||
|     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; |  | ||||||
|     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; |  | ||||||
|     if(HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |     } | ||||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; |     if(LL_TIM_IsActiveFlag_CC2(TIM2) == 1) { | ||||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; |         if (LL_TIM_IsEnabledIT_CC2(TIM2)) { | ||||||
|     sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; |             LL_TIM_ClearFlag_CC2(TIM2); | ||||||
|     sConfigIC.ICFilter = 0; | 
 | ||||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { |             if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { | ||||||
|         Error_Handler(); |                 // input capture
 | ||||||
|  |                 api_hal_irda_tim_isr(TimerIRQSourceCCI2); | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 // output compare
 | ||||||
|  |             //  HAL_TIM_OC_DelayElapsedCallback(htim);
 | ||||||
|  |             //  HAL_TIM_PWM_PulseFinishedCallback(htim);
 | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; |  | ||||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; |  | ||||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); |     furi_check(consumed); | ||||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); |  | ||||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,4 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "main.h" |  | ||||||
| 
 |  | ||||||
| void tim_irda_rx_init(void); |  | ||||||
							
								
								
									
										7
									
								
								firmware/targets/f6/api-hal/api-hal-tim_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								firmware/targets/f6/api-hal/api-hal-tim_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | typedef enum{ | ||||||
|  |     TimerIRQSourceCCI1, | ||||||
|  |     TimerIRQSourceCCI2, | ||||||
|  | } TimerIRQSource; | ||||||
|  | 
 | ||||||
| @ -10,11 +10,6 @@ void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) { | |||||||
|     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); |     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Timer input capture event */ |  | ||||||
| void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) { |  | ||||||
|     api_interrupt_call(InterruptTypeTimerCapture, htim); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Output compare event */ | /* Output compare event */ | ||||||
| void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | ||||||
|     api_interrupt_call(InterruptTypeTimerOutputCompare, htim); |     api_interrupt_call(InterruptTypeTimerOutputCompare, htim); | ||||||
| @ -24,3 +19,8 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | |||||||
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { | void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { | ||||||
|     api_interrupt_call(InterruptTypeTimerUpdate, htim); |     api_interrupt_call(InterruptTypeTimerUpdate, htim); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* External interrupt event */ | ||||||
|  | void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { | ||||||
|  |     api_interrupt_call(InterruptTypeExternalInterrupt, (void*)(uint32_t)GPIO_Pin); | ||||||
|  | } | ||||||
|  | |||||||
| @ -75,6 +75,7 @@ C_SOURCES		+= \ | |||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
 | ||||||
|  | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 | ||||||
| 	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
 | 	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
 | ||||||
|  | |||||||
							
								
								
									
										111
									
								
								lib/irda/irda.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								lib/irda/irda.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | struct IrdaHandler { | ||||||
|  |     void** ctx; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IrdaAlloc alloc; | ||||||
|  |     IrdaDecode decode; | ||||||
|  |     IrdaFree free; | ||||||
|  | } IrdaDecoders; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IrdaEncode encode; | ||||||
|  | } IrdaEncoders; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IrdaProtocol protocol; | ||||||
|  |     const char* name; | ||||||
|  |     IrdaDecoders decoder; | ||||||
|  |     IrdaEncoders encoder; | ||||||
|  | } IrdaProtocolImplementation; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // TODO: replace with key-value, Now we refer by enum index, which is dangerous.
 | ||||||
|  | static const IrdaProtocolImplementation irda_protocols[] = { | ||||||
|  |     // #0
 | ||||||
|  |     { .protocol = IrdaProtocolSamsung32, | ||||||
|  |       .name ="Samsung32", | ||||||
|  |       .decoder = { | ||||||
|  |           .alloc = irda_decoder_samsung32_alloc, | ||||||
|  |           .decode = irda_decoder_samsung32_decode, | ||||||
|  |           .free = irda_decoder_samsung32_free}, | ||||||
|  |       .encoder = { | ||||||
|  |           .encode = irda_encoder_samsung32_encode} | ||||||
|  |     }, | ||||||
|  |     // #1
 | ||||||
|  |     { .protocol = IrdaProtocolNEC, | ||||||
|  |       .name = "NEC", | ||||||
|  |       .decoder = { | ||||||
|  |           .alloc = irda_decoder_nec_alloc, | ||||||
|  |           .decode = irda_decoder_nec_decode, | ||||||
|  |           .free = irda_decoder_nec_free}, | ||||||
|  |       .encoder = { | ||||||
|  |           .encode = irda_encoder_nec_encode} | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const IrdaMessage* irda_decode(IrdaHandler* handler, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(handler); | ||||||
|  | 
 | ||||||
|  |     IrdaMessage* message = NULL; | ||||||
|  |     IrdaMessage* result = NULL; | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < COUNT_OF(irda_protocols); ++i) { | ||||||
|  |         message = irda_protocols[i].decoder.decode(handler->ctx[i], level, duration); | ||||||
|  |         if (!result && message) { | ||||||
|  |             message->protocol = irda_protocols[i].protocol; | ||||||
|  |             result = message; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IrdaHandler* irda_alloc_decoder(void) { | ||||||
|  |     IrdaHandler* handler = furi_alloc(sizeof(IrdaHandler)); | ||||||
|  |     handler->ctx = furi_alloc(sizeof(void*) * COUNT_OF(irda_protocols)); | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < COUNT_OF(irda_protocols); ++i) { | ||||||
|  |         handler->ctx[i] = irda_protocols[i].decoder.alloc(); | ||||||
|  |         furi_check(handler->ctx[i]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return handler; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_free_decoder(IrdaHandler* handler) { | ||||||
|  |     furi_assert(handler); | ||||||
|  |     furi_assert(handler->ctx); | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < COUNT_OF(irda_protocols); ++i) { | ||||||
|  |         irda_protocols[i].decoder.free(handler->ctx[i]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     free(handler->ctx); | ||||||
|  |     free(handler); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_send(const IrdaMessage* message, int times) { | ||||||
|  |     furi_assert(message); | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < times; ++i) { | ||||||
|  |         osKernelLock(); | ||||||
|  |         __disable_irq(); | ||||||
|  |         irda_protocols[message->protocol].encoder.encode(message->address, message->command, !!i); | ||||||
|  |         __enable_irq(); | ||||||
|  |         osKernelUnlock(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* irda_get_protocol_name(IrdaProtocol protocol) { | ||||||
|  |     return irda_protocols[protocol].name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										72
									
								
								lib/irda/irda.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/irda/irda.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | typedef struct IrdaHandler IrdaHandler; | ||||||
|  | 
 | ||||||
|  | // Do not change protocol order, as it can be saved into memory and fw update can be performed!
 | ||||||
|  | typedef enum { | ||||||
|  |     IrdaProtocolSamsung32 = 0, | ||||||
|  |     IrdaProtocolNEC = 1, | ||||||
|  | } IrdaProtocol; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IrdaProtocol protocol; | ||||||
|  |     uint32_t address; | ||||||
|  |     uint32_t command; | ||||||
|  |     bool repeat; | ||||||
|  | } IrdaMessage; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Initialize decoder. | ||||||
|  |  * | ||||||
|  |  * \return      returns pointer to IRDA decoder handler if success, otherwise - error. | ||||||
|  |  */ | ||||||
|  | IrdaHandler* irda_alloc_decoder(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Provide to decoder next timing. If message is ready, it returns decoded message, | ||||||
|  |  * otherwise NULL. | ||||||
|  |  * | ||||||
|  |  * \param[in]   handler     - handler to irda decoders. Should be aquired with \c irda_alloc_decoder(). | ||||||
|  |  * \param[in]   level       - high(true) or low(false) level of input signal to analyze. | ||||||
|  |  *                          it should alternate every call, otherwise it is an error case, | ||||||
|  |  *                          and decoder resets its state and start decoding from the start. | ||||||
|  |  * \param[in]   duration    - duration of steady high/low input signal. | ||||||
|  |  * \return      if message is ready, returns pointer to decoded message, returns NULL. | ||||||
|  |  */ | ||||||
|  | const IrdaMessage* irda_decode(IrdaHandler* handler, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Deinitialize decoder and free allocated memory. | ||||||
|  |  * | ||||||
|  |  * \param[in]   handler     - handler to irda decoders. Should be aquired with \c irda_alloc_decoder(). | ||||||
|  |  */ | ||||||
|  | void irda_free_decoder(IrdaHandler* handler); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Send message over IRDA. | ||||||
|  |  * | ||||||
|  |  * \param[in]   message     - message to send. | ||||||
|  |  * \param[in]   times       - number of times message should be sent. | ||||||
|  |  */ | ||||||
|  | void irda_send(const IrdaMessage* message, int times); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get protocol name by protocol enum. | ||||||
|  |  * | ||||||
|  |  * \param[in]   protocol    - protocol identifier. | ||||||
|  |  * \return      string to protocol name. | ||||||
|  |  */ | ||||||
|  | const char* irda_get_protocol_name(IrdaProtocol protocol); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
							
								
								
									
										166
									
								
								lib/irda/irda_common_decoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								lib/irda/irda_common_decoder.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | #include <stdbool.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool irda_check_preamble(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     bool result = false; | ||||||
|  |     bool start_level = (decoder->level + decoder->timings_cnt + 1) % 2; | ||||||
|  | 
 | ||||||
|  |     // align to start at Mark timing
 | ||||||
|  |     if (start_level) { | ||||||
|  |         if (decoder->timings_cnt > 0) { | ||||||
|  |             --decoder->timings_cnt; | ||||||
|  |             shift_left_array(decoder->timings, decoder->timings_cnt, 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while ((!result) && (decoder->timings_cnt >= 2)) { | ||||||
|  |         float preamble_tolerance = decoder->protocol->timings.preamble_tolerance; | ||||||
|  |         uint16_t preamble_mark = decoder->protocol->timings.preamble_mark; | ||||||
|  |         uint16_t preamble_space = decoder->protocol->timings.preamble_space; | ||||||
|  | 
 | ||||||
|  |         if ((MATCH_PREAMBLE_TIMING(decoder->timings[0], preamble_mark, preamble_tolerance)) | ||||||
|  |             && (MATCH_PREAMBLE_TIMING(decoder->timings[1], preamble_space, preamble_tolerance))) { | ||||||
|  |             result = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         decoder->timings_cnt -= 2; | ||||||
|  |         shift_left_array(decoder->timings, decoder->timings_cnt, 2); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pulse Distance-Width Modulation
 | ||||||
|  | DecodeStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     uint32_t* timings = decoder->timings; | ||||||
|  |     uint16_t index = 0; | ||||||
|  |     uint8_t shift = 0; | ||||||
|  |     DecodeStatus status = DecodeStatusError; | ||||||
|  |     uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance; | ||||||
|  |     uint16_t bit1_mark = decoder->protocol->timings.bit1_mark; | ||||||
|  |     uint16_t bit1_space = decoder->protocol->timings.bit1_space; | ||||||
|  |     uint16_t bit0_mark = decoder->protocol->timings.bit0_mark; | ||||||
|  |     uint16_t bit0_space = decoder->protocol->timings.bit0_space; | ||||||
|  | 
 | ||||||
|  |     while (1) { | ||||||
|  |         // Stop bit
 | ||||||
|  |         if ((decoder->databit_cnt == decoder->protocol->databit_len) && (decoder->timings_cnt == 1)) { | ||||||
|  |             if (MATCH_BIT_TIMING(timings[0], bit1_mark, bit_tolerance)) { | ||||||
|  |                 decoder->timings_cnt = 0; | ||||||
|  |                 status = DecodeStatusReady; | ||||||
|  |             } else { | ||||||
|  |                 status = DecodeStatusError; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (decoder->timings_cnt >= 2) { | ||||||
|  |             index = decoder->databit_cnt / 8; | ||||||
|  |             shift = decoder->databit_cnt % 8;   // LSB first
 | ||||||
|  |             if (!shift) | ||||||
|  |                 decoder->data[index] = 0; | ||||||
|  |             if (MATCH_BIT_TIMING(timings[0], bit1_mark, bit_tolerance) | ||||||
|  |                 && MATCH_BIT_TIMING(timings[1], bit1_space, bit_tolerance)) { | ||||||
|  |                 decoder->data[index] |= (0x1 << shift);           // add 1
 | ||||||
|  |             } else if (MATCH_BIT_TIMING(timings[0], bit0_mark, bit_tolerance) | ||||||
|  |                 && MATCH_BIT_TIMING(timings[1], bit0_space, bit_tolerance)) { | ||||||
|  |                 (void) decoder->data[index];                      // add 0
 | ||||||
|  |             } else { | ||||||
|  |                 status = DecodeStatusError; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             ++decoder->databit_cnt; | ||||||
|  |             decoder->timings_cnt -= 2; | ||||||
|  |             shift_left_array(decoder->timings, decoder->timings_cnt, 2); | ||||||
|  |         } else { | ||||||
|  |             status = DecodeStatusOk; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     IrdaMessage* message = 0; | ||||||
|  |     DecodeStatus status = DecodeStatusError; | ||||||
|  | 
 | ||||||
|  |     if (decoder->level == level) { | ||||||
|  |         furi_assert(0); | ||||||
|  |         decoder->timings_cnt = 0; | ||||||
|  |     } | ||||||
|  |     decoder->level = level;   // start with high level (Space timing)
 | ||||||
|  | 
 | ||||||
|  |     decoder->timings[decoder->timings_cnt] = duration; | ||||||
|  |     decoder->timings_cnt++; | ||||||
|  |     furi_check(decoder->timings_cnt <= sizeof(decoder->timings)); | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         switch (decoder->state) { | ||||||
|  |         case IrdaCommonStateWaitPreamble: | ||||||
|  |             if (irda_check_preamble(decoder)) { | ||||||
|  |                 decoder->state = IrdaCommonStateDecode; | ||||||
|  |                 decoder->databit_cnt = 0; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case IrdaCommonStateDecode: | ||||||
|  |             status = decoder->protocol->decode(decoder); | ||||||
|  |             if (status == DecodeStatusReady) { | ||||||
|  |                 if (decoder->protocol->interpret(decoder)) { | ||||||
|  |                     message = &decoder->message; | ||||||
|  |                     decoder->state = IrdaCommonStateProcessRepeat; | ||||||
|  |                 } else { | ||||||
|  |                     decoder->state = IrdaCommonStateWaitPreamble; | ||||||
|  |                 } | ||||||
|  |             } else if (status == DecodeStatusError) { | ||||||
|  |                 decoder->state = IrdaCommonStateWaitPreamble; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case IrdaCommonStateProcessRepeat: | ||||||
|  |             if (!decoder->protocol->decode_repeat) { | ||||||
|  |                 decoder->state = IrdaCommonStateWaitPreamble; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             status = decoder->protocol->decode_repeat(decoder); | ||||||
|  |             if (status == DecodeStatusError) { | ||||||
|  |                 decoder->state = IrdaCommonStateWaitPreamble; | ||||||
|  |                 continue; | ||||||
|  |             } else if (status == DecodeStatusReady) { | ||||||
|  |                 decoder->message.repeat = true; | ||||||
|  |                 message = &decoder->message; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return message; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec* protocol) { | ||||||
|  |     furi_assert(protocol); | ||||||
|  | 
 | ||||||
|  |     uint32_t alloc_size = sizeof(IrdaCommonDecoder) | ||||||
|  |                           + protocol->databit_len / 8 | ||||||
|  |                           + !!(protocol->databit_len % 8); | ||||||
|  |     IrdaCommonDecoder* decoder = furi_alloc(alloc_size); | ||||||
|  |     memset(decoder, 0, alloc_size); | ||||||
|  |     decoder->protocol = protocol; | ||||||
|  |     return decoder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_common_decoder_free(void* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     free(decoder); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										72
									
								
								lib/irda/irda_common_decoder_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/irda/irda_common_decoder_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include "irda.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #define MATCH_BIT_TIMING(x, v, delta)       (  ((x) < (v + delta)) \ | ||||||
|  |                                             && ((x) > (v - delta))) | ||||||
|  | 
 | ||||||
|  | #define MATCH_PREAMBLE_TIMING(x, v, delta)  (  ((x) < ((v) * (1 + (delta)))) \ | ||||||
|  |                                             && ((x) > ((v) * (1 - (delta))))) | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DecodeStatusError, | ||||||
|  |     DecodeStatusOk, | ||||||
|  |     DecodeStatusReady, | ||||||
|  | } DecodeStatus; | ||||||
|  | 
 | ||||||
|  | typedef struct IrdaCommonDecoder IrdaCommonDecoder; | ||||||
|  | 
 | ||||||
|  | typedef DecodeStatus (*IrdaCommonDecode)(IrdaCommonDecoder*); | ||||||
|  | typedef bool (*IrdaCommonInterpret)(IrdaCommonDecoder*); | ||||||
|  | typedef DecodeStatus (*IrdaCommonDecodeRepeat)(IrdaCommonDecoder*); | ||||||
|  | 
 | ||||||
|  | typedef enum IrdaCommonState { | ||||||
|  |     IrdaCommonStateWaitPreamble, | ||||||
|  |     IrdaCommonStateDecode, | ||||||
|  |     IrdaCommonStateProcessRepeat, | ||||||
|  | } IrdaCommonState; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint16_t preamble_mark; | ||||||
|  |     uint16_t preamble_space; | ||||||
|  |     uint16_t bit1_mark; | ||||||
|  |     uint16_t bit1_space; | ||||||
|  |     uint16_t bit0_mark; | ||||||
|  |     uint16_t bit0_space; | ||||||
|  |     float    preamble_tolerance; | ||||||
|  |     uint32_t bit_tolerance; | ||||||
|  | } IrdaCommonDecoderTimings; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IrdaCommonDecoderTimings timings; | ||||||
|  |     uint32_t databit_len; | ||||||
|  |     IrdaCommonDecode decode; | ||||||
|  |     IrdaCommonInterpret interpret; | ||||||
|  |     IrdaCommonDecodeRepeat decode_repeat; | ||||||
|  | } IrdaCommonProtocolSpec; | ||||||
|  | 
 | ||||||
|  | struct IrdaCommonDecoder { | ||||||
|  |     const IrdaCommonProtocolSpec* protocol; | ||||||
|  |     IrdaCommonState state; | ||||||
|  |     IrdaMessage message; | ||||||
|  |     uint32_t timings[6]; | ||||||
|  |     uint8_t timings_cnt; | ||||||
|  |     uint32_t level; | ||||||
|  |     uint16_t databit_cnt; | ||||||
|  |     uint8_t data[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static inline void shift_left_array(uint32_t *array, uint32_t len, uint32_t shift) { | ||||||
|  |     for (int i = 0; i < len; ++i) | ||||||
|  |         array[i] = array[i + shift]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | IrdaMessage* irda_common_decode(IrdaCommonDecoder *decoder, bool level, uint32_t duration); | ||||||
|  | void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec *protocol); | ||||||
|  | void irda_common_decoder_free(void* decoder); | ||||||
|  | DecodeStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder); | ||||||
|  | 
 | ||||||
							
								
								
									
										34
									
								
								lib/irda/irda_encoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/irda/irda_encoder.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <api-hal-irda.h> | ||||||
|  | #include <api-hal-delay.h> | ||||||
|  | #include "irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void irda_encode_mark(const IrdaEncoderTimings *timings, uint32_t duration) { | ||||||
|  |     api_hal_irda_pwm_set(timings->duty_cycle, timings->carrier_frequency); | ||||||
|  |     delay_us(duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_encode_space(const IrdaEncoderTimings *timings, uint32_t duration) { | ||||||
|  |     (void) timings; | ||||||
|  |     api_hal_irda_pwm_stop(); | ||||||
|  |     delay_us(duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_encode_bit(const IrdaEncoderTimings *timings, bool bit) { | ||||||
|  |     if (bit) { | ||||||
|  |         irda_encode_mark(timings, timings->bit1_mark); | ||||||
|  |         irda_encode_space(timings, timings->bit1_space); | ||||||
|  |     } else { | ||||||
|  |         irda_encode_mark(timings, timings->bit0_mark); | ||||||
|  |         irda_encode_space(timings, timings->bit0_space); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_encode_byte(const IrdaEncoderTimings *timings, uint8_t data) { | ||||||
|  |     for(uint8_t i = 0; i < 8; i++) { | ||||||
|  |         irda_encode_bit(timings, !!(data & (1 << i))); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										21
									
								
								lib/irda/irda_encoder_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/irda/irda_encoder_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include "irda.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t bit1_mark; | ||||||
|  |     uint32_t bit1_space; | ||||||
|  |     uint32_t bit0_mark; | ||||||
|  |     uint32_t bit0_space; | ||||||
|  |     float duty_cycle; | ||||||
|  |     uint32_t carrier_frequency; | ||||||
|  | } IrdaEncoderTimings; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void irda_encode_byte(const IrdaEncoderTimings *timings, uint8_t data); | ||||||
|  | void irda_encode_bit(const IrdaEncoderTimings *timings, bool bit); | ||||||
|  | void irda_encode_space(const IrdaEncoderTimings *timings, uint32_t duration); | ||||||
|  | void irda_encode_mark(const IrdaEncoderTimings *timings, uint32_t duration); | ||||||
|  | 
 | ||||||
							
								
								
									
										13
									
								
								lib/irda/irda_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/irda/irda_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "irda.h" | ||||||
|  | #include <stddef.h> | ||||||
|  | #include "irda_encoder_i.h" | ||||||
|  | #include "irda_common_decoder_i.h" | ||||||
|  | #include "irda_protocol_defs_i.h" | ||||||
|  | 
 | ||||||
|  | typedef void* (*IrdaAlloc) (void); | ||||||
|  | typedef IrdaMessage* (*IrdaDecode) (void* ctx, bool level, uint32_t duration); | ||||||
|  | typedef void (*IrdaFree) (void*); | ||||||
|  | 
 | ||||||
|  | typedef void (*IrdaEncode)(uint32_t address, uint32_t command, bool repeat); | ||||||
|  | 
 | ||||||
							
								
								
									
										78
									
								
								lib/irda/irda_protocol_defs_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								lib/irda/irda_protocol_defs_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include "irda.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /***************************************************************************************************
 | ||||||
|  | *   NEC protocol description | ||||||
|  | *   https://radioparty.ru/manuals/encyclopedia/213-ircontrol?start=1
 | ||||||
|  | **************************************************************************************************** | ||||||
|  | *     Preamble   Preamble      Pulse Distance/Width          Pause       Preamble   Preamble  Stop | ||||||
|  | *       mark      space            Modulation                             repeat     repeat    bit | ||||||
|  | *                                                                          mark       space | ||||||
|  | * | ||||||
|  | *        9000      4500         32 bit + stop bit         40000/100000     9000       2250 | ||||||
|  | *     __________          _ _ _ _  _  _  _ _ _  _  _ _ _                ___________            _ | ||||||
|  | * ____          __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________           ____________ ___ | ||||||
|  | * | ||||||
|  | ***************************************************************************************************/ | ||||||
|  | 
 | ||||||
|  | #define IRDA_NEC_PREAMBULE_MARK         9000 | ||||||
|  | #define IRDA_NEC_PREAMBULE_SPACE        4500 | ||||||
|  | #define IRDA_NEC_BIT1_MARK              560 | ||||||
|  | #define IRDA_NEC_BIT1_SPACE             1600 | ||||||
|  | #define IRDA_NEC_BIT0_MARK              560 | ||||||
|  | #define IRDA_NEC_BIT0_SPACE             560 | ||||||
|  | #define IRDA_NEC_REPEAT_PAUSE_MIN       30000 | ||||||
|  | #define IRDA_NEC_REPEAT_PAUSE           40000 | ||||||
|  | #define IRDA_NEC_REPEAT_PAUSE_MAX       150000 | ||||||
|  | #define IRDA_NEC_REPEAT_MARK            9000 | ||||||
|  | #define IRDA_NEC_REPEAT_SPACE           2250 | ||||||
|  | #define IRDA_NEC_CARRIER_FREQUENCY      38000 | ||||||
|  | #define IRDA_NEC_DUTY_CYCLE             0.33 | ||||||
|  | #define IRDA_NEC_PREAMBLE_TOLERANCE     0.07    // percents
 | ||||||
|  | #define IRDA_NEC_BIT_TOLERANCE          120     // us
 | ||||||
|  | 
 | ||||||
|  | void* irda_decoder_nec_alloc(void); | ||||||
|  | void irda_encoder_nec_encode(uint32_t address, uint32_t command, bool repeat); | ||||||
|  | void irda_decoder_nec_free(void* decoder); | ||||||
|  | IrdaMessage* irda_decoder_nec_decode(void* decoder, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /***************************************************************************************************
 | ||||||
|  | *   SAMSUNG32 protocol description | ||||||
|  | *   https://www.mikrocontroller.net/articles/IRMP_-_english#SAMSUNG
 | ||||||
|  | **************************************************************************************************** | ||||||
|  | *  Preamble   Preamble     Pulse Distance/Width        Pause       Preamble   Preamble  Bit1  Stop | ||||||
|  | *    mark      space           Modulation                           repeat     repeat          bit | ||||||
|  | *                                                                    mark       space | ||||||
|  | * | ||||||
|  | *     4500      4500        32 bit + stop bit       40000/100000     4500       4500 | ||||||
|  | *  __________          _  _ _  _  _  _ _ _  _  _ _                ___________            _    _ | ||||||
|  | * _          __________ __ _ __ __ __ _ _ __ __ _ ________________           ____________ ____ ___ | ||||||
|  | * | ||||||
|  | ***************************************************************************************************/ | ||||||
|  | 
 | ||||||
|  | #define IRDA_SAMSUNG_PREAMBULE_MARK         4500 | ||||||
|  | #define IRDA_SAMSUNG_PREAMBULE_SPACE        4500 | ||||||
|  | #define IRDA_SAMSUNG_BIT1_MARK              550 | ||||||
|  | #define IRDA_SAMSUNG_BIT1_SPACE             1650 | ||||||
|  | #define IRDA_SAMSUNG_BIT0_MARK              550 | ||||||
|  | #define IRDA_SAMSUNG_BIT0_SPACE             550 | ||||||
|  | #define IRDA_SAMSUNG_REPEAT_PAUSE_MIN       30000 | ||||||
|  | #define IRDA_SAMSUNG_REPEAT_PAUSE           47000 | ||||||
|  | #define IRDA_SAMSUNG_REPEAT_PAUSE_MAX       150000 | ||||||
|  | #define IRDA_SAMSUNG_REPEAT_MARK            4500 | ||||||
|  | #define IRDA_SAMSUNG_REPEAT_SPACE           4500 | ||||||
|  | #define IRDA_SAMSUNG_CARRIER_FREQUENCY      38000 | ||||||
|  | #define IRDA_SAMSUNG_DUTY_CYCLE             0.33 | ||||||
|  | #define IRDA_SAMSUNG_PREAMBLE_TOLERANCE     0.07    // percents
 | ||||||
|  | #define IRDA_SAMSUNG_BIT_TOLERANCE          120     // us
 | ||||||
|  | 
 | ||||||
|  | void* irda_decoder_samsung32_alloc(void); | ||||||
|  | void irda_encoder_samsung32_encode(uint32_t address, uint32_t command, bool repeat); | ||||||
|  | void irda_decoder_samsung32_free(void* decoder); | ||||||
|  | IrdaMessage* irda_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
							
								
								
									
										84
									
								
								lib/irda/nec/irda_decoder_nec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								lib/irda/nec/irda_decoder_nec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "../irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool interpret_nec(IrdaCommonDecoder* decoder); | ||||||
|  | static DecodeStatus decode_repeat_nec(IrdaCommonDecoder* decoder); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static const IrdaCommonProtocolSpec protocol_nec = { | ||||||
|  |     { | ||||||
|  |         IRDA_NEC_PREAMBULE_MARK, | ||||||
|  |         IRDA_NEC_PREAMBULE_SPACE, | ||||||
|  |         IRDA_NEC_BIT1_MARK, | ||||||
|  |         IRDA_NEC_BIT1_SPACE, | ||||||
|  |         IRDA_NEC_BIT0_MARK, | ||||||
|  |         IRDA_NEC_BIT0_SPACE, | ||||||
|  |         IRDA_NEC_PREAMBLE_TOLERANCE, | ||||||
|  |         IRDA_NEC_BIT_TOLERANCE, | ||||||
|  |     }, | ||||||
|  |     32, | ||||||
|  |     irda_common_decode_pdwm, | ||||||
|  |     interpret_nec, | ||||||
|  |     decode_repeat_nec, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool interpret_nec(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     bool result = false; | ||||||
|  |     uint8_t address = decoder->data[0]; | ||||||
|  |     uint8_t address_inverse = decoder->data[1]; | ||||||
|  |     uint8_t command = decoder->data[2]; | ||||||
|  |     uint8_t command_inverse = decoder->data[3]; | ||||||
|  | 
 | ||||||
|  |     if ((command == (uint8_t) ~command_inverse) && (address == (uint8_t) ~address_inverse)) { | ||||||
|  |         decoder->message.command = command; | ||||||
|  |         decoder->message.address = address; | ||||||
|  |         decoder->message.repeat = false; | ||||||
|  |         result = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // timings start from Space (delay between message and repeat)
 | ||||||
|  | static DecodeStatus decode_repeat_nec(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     float preamble_tolerance = decoder->protocol->timings.preamble_tolerance; | ||||||
|  |     uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance; | ||||||
|  |     DecodeStatus status = DecodeStatusError; | ||||||
|  | 
 | ||||||
|  |     if (decoder->timings_cnt < 4) | ||||||
|  |         return DecodeStatusOk; | ||||||
|  | 
 | ||||||
|  |     if ((decoder->timings[0] > IRDA_NEC_REPEAT_PAUSE_MIN) | ||||||
|  |         && (decoder->timings[0] < IRDA_NEC_REPEAT_PAUSE_MAX) | ||||||
|  |         && MATCH_PREAMBLE_TIMING(decoder->timings[1], IRDA_NEC_REPEAT_MARK, preamble_tolerance) | ||||||
|  |         && MATCH_PREAMBLE_TIMING(decoder->timings[2], IRDA_NEC_REPEAT_SPACE, preamble_tolerance) | ||||||
|  |         && MATCH_BIT_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance)) { | ||||||
|  |         status = DecodeStatusReady; | ||||||
|  |         decoder->timings_cnt = 0; | ||||||
|  |     } else { | ||||||
|  |         status = DecodeStatusError; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* irda_decoder_nec_alloc(void) { | ||||||
|  |     return irda_common_decoder_alloc(&protocol_nec); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IrdaMessage* irda_decoder_nec_decode(void* decoder, bool level, uint32_t duration) { | ||||||
|  |     return irda_common_decode(decoder, level, duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_decoder_nec_free(void* decoder) { | ||||||
|  |     irda_common_decoder_free(decoder); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										44
									
								
								lib/irda/nec/irda_encoder_nec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								lib/irda/nec/irda_encoder_nec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #include <stdint.h> | ||||||
|  | #include "../irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static const IrdaEncoderTimings encoder_timings = { | ||||||
|  |     .bit1_mark = IRDA_NEC_BIT1_MARK, | ||||||
|  |     .bit1_space = IRDA_NEC_BIT1_SPACE, | ||||||
|  |     .bit0_mark =IRDA_NEC_BIT0_MARK, | ||||||
|  |     .bit0_space = IRDA_NEC_BIT0_SPACE, | ||||||
|  |     .duty_cycle = IRDA_NEC_DUTY_CYCLE, | ||||||
|  |     .carrier_frequency = IRDA_NEC_CARRIER_FREQUENCY, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void irda_encode_nec_preamble(void) { | ||||||
|  |     irda_encode_mark(&encoder_timings, IRDA_NEC_PREAMBULE_MARK); | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_NEC_PREAMBULE_SPACE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void irda_encode_nec_repeat(void) { | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_NEC_REPEAT_PAUSE); | ||||||
|  |     irda_encode_mark(&encoder_timings, IRDA_NEC_REPEAT_MARK); | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_NEC_REPEAT_SPACE); | ||||||
|  |     irda_encode_bit(&encoder_timings, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_encoder_nec_encode(uint32_t addr, uint32_t cmd, bool repeat) { | ||||||
|  |     uint8_t address = addr & 0xFF; | ||||||
|  |     uint8_t command = cmd & 0xFF; | ||||||
|  |     uint8_t address_inverse = (uint8_t) ~address; | ||||||
|  |     uint8_t command_inverse = (uint8_t) ~command; | ||||||
|  | 
 | ||||||
|  |     if (!repeat) { | ||||||
|  |         irda_encode_nec_preamble(); | ||||||
|  |         irda_encode_byte(&encoder_timings, address); | ||||||
|  |         irda_encode_byte(&encoder_timings, address_inverse); | ||||||
|  |         irda_encode_byte(&encoder_timings, command); | ||||||
|  |         irda_encode_byte(&encoder_timings, command_inverse); | ||||||
|  |         irda_encode_bit(&encoder_timings, 1); | ||||||
|  |     } else { | ||||||
|  |         irda_encode_nec_repeat(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										87
									
								
								lib/irda/samsung/irda_decoder_samsung.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								lib/irda/samsung/irda_decoder_samsung.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "../irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool interpret_samsung32(IrdaCommonDecoder* decoder); | ||||||
|  | static DecodeStatus decode_repeat_samsung32(IrdaCommonDecoder* decoder); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static const IrdaCommonProtocolSpec protocol_samsung32 = { | ||||||
|  |     { | ||||||
|  |         IRDA_SAMSUNG_PREAMBULE_MARK, | ||||||
|  |         IRDA_SAMSUNG_PREAMBULE_SPACE, | ||||||
|  |         IRDA_SAMSUNG_BIT1_MARK, | ||||||
|  |         IRDA_SAMSUNG_BIT1_SPACE, | ||||||
|  |         IRDA_SAMSUNG_BIT0_MARK, | ||||||
|  |         IRDA_SAMSUNG_BIT0_SPACE, | ||||||
|  |         IRDA_SAMSUNG_PREAMBLE_TOLERANCE, | ||||||
|  |         IRDA_SAMSUNG_BIT_TOLERANCE, | ||||||
|  |     }, | ||||||
|  |     32, | ||||||
|  |     irda_common_decode_pdwm, | ||||||
|  |     interpret_samsung32, | ||||||
|  |     decode_repeat_samsung32, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool interpret_samsung32(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     bool result = false; | ||||||
|  |     uint8_t address1 = decoder->data[0]; | ||||||
|  |     uint8_t address2 = decoder->data[1]; | ||||||
|  |     uint8_t command = decoder->data[2]; | ||||||
|  |     uint8_t command_inverse = decoder->data[3]; | ||||||
|  | 
 | ||||||
|  |     if ((address1 == address2) && (command == (uint8_t) ~command_inverse)) { | ||||||
|  |         decoder->message.command = command; | ||||||
|  |         decoder->message.address = address1; | ||||||
|  |         decoder->message.repeat = false; | ||||||
|  |         result = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // timings start from Space (delay between message and repeat)
 | ||||||
|  | static DecodeStatus decode_repeat_samsung32(IrdaCommonDecoder* decoder) { | ||||||
|  |     furi_assert(decoder); | ||||||
|  | 
 | ||||||
|  |     float preamble_tolerance = decoder->protocol->timings.preamble_tolerance; | ||||||
|  |     uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance; | ||||||
|  |     DecodeStatus status = DecodeStatusError; | ||||||
|  | 
 | ||||||
|  |     if (decoder->timings_cnt < 6) | ||||||
|  |         return DecodeStatusOk; | ||||||
|  | 
 | ||||||
|  |     if ((decoder->timings[0] > IRDA_SAMSUNG_REPEAT_PAUSE_MIN) | ||||||
|  |         && (decoder->timings[0] < IRDA_SAMSUNG_REPEAT_PAUSE_MAX) | ||||||
|  |         && MATCH_PREAMBLE_TIMING(decoder->timings[1], IRDA_SAMSUNG_REPEAT_MARK, preamble_tolerance) | ||||||
|  |         && MATCH_PREAMBLE_TIMING(decoder->timings[2], IRDA_SAMSUNG_REPEAT_SPACE, preamble_tolerance) | ||||||
|  |         && MATCH_BIT_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance) | ||||||
|  |         && MATCH_BIT_TIMING(decoder->timings[4], decoder->protocol->timings.bit1_space, bit_tolerance) | ||||||
|  |         && MATCH_BIT_TIMING(decoder->timings[5], decoder->protocol->timings.bit1_mark, bit_tolerance) | ||||||
|  |         ) { | ||||||
|  |         status = DecodeStatusReady; | ||||||
|  |         decoder->timings_cnt = 0; | ||||||
|  |     } else { | ||||||
|  |         status = DecodeStatusError; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* irda_decoder_samsung32_alloc(void) { | ||||||
|  |     return irda_common_decoder_alloc(&protocol_samsung32); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IrdaMessage* irda_decoder_samsung32_decode(void* decoder, bool level, uint32_t duration) { | ||||||
|  |     return irda_common_decode(decoder, level, duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_decoder_samsung32_free(void* decoder) { | ||||||
|  |     irda_common_decoder_free(decoder); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										44
									
								
								lib/irda/samsung/irda_encoder_samsung.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								lib/irda/samsung/irda_encoder_samsung.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #include <stdint.h> | ||||||
|  | #include "../irda_i.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static const IrdaEncoderTimings encoder_timings = { | ||||||
|  |     .bit1_mark = IRDA_SAMSUNG_BIT1_MARK, | ||||||
|  |     .bit1_space = IRDA_SAMSUNG_BIT1_SPACE, | ||||||
|  |     .bit0_mark =IRDA_SAMSUNG_BIT0_MARK, | ||||||
|  |     .bit0_space = IRDA_SAMSUNG_BIT0_SPACE, | ||||||
|  |     .duty_cycle = IRDA_SAMSUNG_DUTY_CYCLE, | ||||||
|  |     .carrier_frequency = IRDA_SAMSUNG_CARRIER_FREQUENCY, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void irda_encode_samsung32_preamble(void) { | ||||||
|  |     irda_encode_mark(&encoder_timings, IRDA_SAMSUNG_PREAMBULE_MARK); | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_SAMSUNG_PREAMBULE_SPACE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void irda_encode_samsung32_repeat(void) { | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_SAMSUNG_REPEAT_PAUSE); | ||||||
|  |     irda_encode_mark(&encoder_timings, IRDA_SAMSUNG_REPEAT_MARK); | ||||||
|  |     irda_encode_space(&encoder_timings, IRDA_SAMSUNG_REPEAT_SPACE); | ||||||
|  |     irda_encode_bit(&encoder_timings, 1); | ||||||
|  |     irda_encode_bit(&encoder_timings, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void irda_encoder_samsung32_encode(uint32_t addr, uint32_t cmd, bool repeat) { | ||||||
|  |     uint8_t address = addr & 0xFF; | ||||||
|  |     uint8_t command = cmd & 0xFF; | ||||||
|  |     uint8_t command_inverse = (uint8_t) ~command; | ||||||
|  | 
 | ||||||
|  |     if (!repeat) { | ||||||
|  |         irda_encode_samsung32_preamble(); | ||||||
|  |         irda_encode_byte(&encoder_timings, address); | ||||||
|  |         irda_encode_byte(&encoder_timings, address); | ||||||
|  |         irda_encode_byte(&encoder_timings, command); | ||||||
|  |         irda_encode_byte(&encoder_timings, command_inverse); | ||||||
|  |         irda_encode_bit(&encoder_timings, 1); | ||||||
|  |     } else { | ||||||
|  |         irda_encode_samsung32_repeat(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @ -94,3 +94,7 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/drivers/*.c) | |||||||
| CFLAGS			+= -I$(LIB_DIR)/version | CFLAGS			+= -I$(LIB_DIR)/version | ||||||
| C_SOURCES		+= $(LIB_DIR)/version/version.c | C_SOURCES		+= $(LIB_DIR)/version/version.c | ||||||
| 
 | 
 | ||||||
|  | #irda lib
 | ||||||
|  | CFLAGS			+= -I$(LIB_DIR)/irda | ||||||
|  | C_SOURCES		+= $(wildcard $(LIB_DIR)/irda/*.c) | ||||||
|  | C_SOURCES		+= $(wildcard $(LIB_DIR)/irda/*/*.c) | ||||||
|  | |||||||
| @ -123,4 +123,12 @@ format: | |||||||
| 	@echo "Formatting sources with clang-format" | 	@echo "Formatting sources with clang-format" | ||||||
| 	@clang-format -style=file -i $(FORMAT_SOURCES) | 	@clang-format -style=file -i $(FORMAT_SOURCES) | ||||||
| 
 | 
 | ||||||
|  | generate_cscope_db: $(ASSETS) | ||||||
|  | 	@echo "$(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/source.list.p | ||||||
|  | 	@cat ~/headers.list >> $(OBJ_DIR)/source.list.p | ||||||
|  | 	@cat $(OBJ_DIR)/source.list.p | sed -e "s|^[^//]|$$PWD/&|g" > $(OBJ_DIR)/source.list | ||||||
|  | 	@cscope -b -k -i $(OBJ_DIR)/source.list -f $(OBJ_DIR)/cscope.out | ||||||
|  | 	@rm -rf $(OBJ_DIR)/source.list $(OBJ_DIR)/source.list.p | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| -include $(DEPS) | -include $(DEPS) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov