[FL-1062] Add cli commands for IrDA (#409)
* irda: add ir_tx command * api-hal-vcp: add receive with timeout * cli: add command termination check function * irda: add cli_rx command * cli: reduce timeout for Ctrl+C command check * irda: fix ir_rx command * irda: add ir_tx cli command hints Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									aa20a78b0e
								
							
						
					
					
						commit
						239c174610
					
				| @ -50,6 +50,12 @@ size_t cli_read(Cli* cli, uint8_t* buffer, size_t size) { | ||||
|     return api_hal_vcp_rx(buffer, size); | ||||
| } | ||||
| 
 | ||||
| bool cli_cmd_interrupt_received(Cli* cli) { | ||||
|     char c; | ||||
|     api_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1); | ||||
|     return c == CliSymbolAsciiETX; | ||||
| } | ||||
| 
 | ||||
| void cli_print_version(const Version* version) { | ||||
|     if(version) { | ||||
|         printf("\tVersion:\t%s\r\n", version_get_version(version)); | ||||
|  | ||||
| @ -42,6 +42,11 @@ void cli_delete_command(Cli* cli, const char* name); | ||||
|  */ | ||||
| size_t cli_read(Cli* cli, uint8_t* buffer, size_t size); | ||||
| 
 | ||||
| /* Not blocking check for interrupt command received
 | ||||
|  * @param cli - Cli instance | ||||
|  */ | ||||
| bool cli_cmd_interrupt_received(Cli* cli); | ||||
| 
 | ||||
| /* Write to terminal
 | ||||
|  * Do it only from inside of cli call. | ||||
|  * @param cli - Cli instance | ||||
|  | ||||
| @ -18,6 +18,7 @@ DICT_DEF2(CliCommandDict, string_t, STRING_OPLIST, CliCommand, M_POD_OPLIST) | ||||
| 
 | ||||
| typedef enum { | ||||
|     CliSymbolAsciiSOH = 0x01, | ||||
|     CliSymbolAsciiETX = 0x03, | ||||
|     CliSymbolAsciiEOT = 0x04, | ||||
|     CliSymbolAsciiBell = 0x07, | ||||
|     CliSymbolAsciiBackspace = 0x08, | ||||
|  | ||||
							
								
								
									
										122
									
								
								applications/irda/irda.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										122
									
								
								applications/irda/irda.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -2,6 +2,7 @@ | ||||
| #include <api-hal.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| #include <cli/cli.h> | ||||
| 
 | ||||
| #include "irda_nec.h" | ||||
| #include "irda_samsung.h" | ||||
| @ -35,6 +36,12 @@ typedef struct { | ||||
| 
 | ||||
| #define IRDA_PACKET_COUNT 8 | ||||
| 
 | ||||
| typedef struct { | ||||
|     osMessageQueueId_t cli_ir_rx_queue; | ||||
|     Cli* cli; | ||||
|     bool cli_cmd_is_active; | ||||
| } IrDAApp; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t mode_id; | ||||
|     uint16_t carrier_freq; | ||||
| @ -235,6 +242,93 @@ void init_packet( | ||||
|     state->packets[index].command = command; | ||||
| } | ||||
| 
 | ||||
| void irda_cli_cmd_rx(string_t args, void* context) { | ||||
|     furi_assert(context); | ||||
|     IrDAPacket packet; | ||||
|     IrDAApp* app = context; | ||||
|     app->cli_cmd_is_active = true; | ||||
|     bool exit = false; | ||||
| 
 | ||||
|     printf("Reading income packets...\r\nPress Ctrl+C to abort\r\n"); | ||||
|     while(!exit) { | ||||
|         exit = cli_cmd_interrupt_received(app->cli); | ||||
|         osStatus status = osMessageQueueGet(app->cli_ir_rx_queue, &packet, 0, 50); | ||||
|         if(status == osOK) { | ||||
|             if(packet.protocol == IRDA_NEC) { | ||||
|                 printf("NEC "); | ||||
|             } else if(packet.protocol == IRDA_SAMSUNG) { | ||||
|                 printf("SAMSUNG "); | ||||
|             } | ||||
|             printf( | ||||
|                 "Address:0x%02X%02X Command: 0x%02X\r\n", | ||||
|                 (uint8_t)(packet.address >> 8), | ||||
|                 (uint8_t)packet.address, | ||||
|                 (uint8_t)packet.command); | ||||
|         } | ||||
|     } | ||||
|     printf("Interrupt command received"); | ||||
|     app->cli_cmd_is_active = false; | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| void irda_cli_cmd_tx(string_t args, void* context) { | ||||
|     furi_assert(context); | ||||
|     ValueMutex* state_mutex = context; | ||||
|     // Read protocol name
 | ||||
|     IrDAProtocolType protocol; | ||||
|     string_t protocol_str; | ||||
|     string_init(protocol_str); | ||||
|     size_t ws = string_search_char(args, ' '); | ||||
|     if(ws == STRING_FAILURE) { | ||||
|         printf("Invalid input. Use ir_tx PROTOCOL ADDRESS COMMAND"); | ||||
|         string_clear(protocol_str); | ||||
|         return; | ||||
|     } else { | ||||
|         string_set_n(protocol_str, args, 0, ws); | ||||
|         string_right(args, ws); | ||||
|         string_strim(args); | ||||
|     } | ||||
|     if(!string_cmp_str(protocol_str, "NEC")) { | ||||
|         protocol = IRDA_NEC; | ||||
|     } else if(!string_cmp_str(protocol_str, "SAMSUNG")) { | ||||
|         protocol = IRDA_SAMSUNG; | ||||
|     } else { | ||||
|         printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`"); | ||||
|         string_clear(protocol_str); | ||||
|         return; | ||||
|     } | ||||
|     string_clear(protocol_str); | ||||
|     // Read address
 | ||||
|     uint16_t address = strtoul(string_get_cstr(args), NULL, 16); | ||||
|     ws = string_search_char(args, ' '); | ||||
|     if(!(ws == 4 || ws == 6)) { | ||||
|         printf("Invalid address format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats"); | ||||
|         return; | ||||
|     } | ||||
|     string_right(args, ws); | ||||
|     string_strim(args); | ||||
|     // Read command
 | ||||
|     uint16_t command = strtoul(string_get_cstr(args), NULL, 16); | ||||
|     ws = string_search_char(args, '\0'); | ||||
|     if(!(ws == 4 || ws == 6)) { | ||||
|         printf("Invalid command format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     State* state = (State*)acquire_mutex(state_mutex, 25); | ||||
|     if(state == NULL) { | ||||
|         printf("IRDA resources busy\r\n"); | ||||
|         return; | ||||
|     } | ||||
|     if(protocol == IRDA_NEC) { | ||||
|         ir_nec_send(address, command); | ||||
|     } else if(protocol == IRDA_SAMSUNG) { | ||||
|         ir_samsung_send(address, command); | ||||
|     } | ||||
|     release_mutex(state_mutex, state); | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| int32_t irda(void* p) { | ||||
|     osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL); | ||||
| 
 | ||||
| @ -247,6 +341,11 @@ int32_t irda(void* p) { | ||||
|     _state.mode_id = 0; | ||||
|     _state.packet_id = 0; | ||||
| 
 | ||||
|     IrDAApp irda_app; | ||||
|     irda_app.cli = furi_record_open("cli"); | ||||
|     irda_app.cli_ir_rx_queue = osMessageQueueNew(1, sizeof(IrDAPacket), NULL); | ||||
|     irda_app.cli_cmd_is_active = false; | ||||
| 
 | ||||
|     for(uint8_t i = 0; i < IRDA_PACKET_COUNT; i++) { | ||||
|         init_packet(&_state, i, IRDA_UNKNOWN, 0, 0); | ||||
|     } | ||||
| @ -271,6 +370,9 @@ int32_t irda(void* p) { | ||||
|     view_port_draw_callback_set(view_port, render_callback, &state_mutex); | ||||
|     view_port_input_callback_set(view_port, input_callback, event_queue); | ||||
| 
 | ||||
|     cli_add_command(irda_app.cli, "ir_rx", irda_cli_cmd_rx, &irda_app); | ||||
|     cli_add_command(irda_app.cli, "ir_tx", irda_cli_cmd_tx, &state_mutex); | ||||
| 
 | ||||
|     // Open GUI and register view_port
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||
| @ -306,6 +408,10 @@ int32_t irda(void* p) { | ||||
| 
 | ||||
|                     delete_mutex(&state_mutex); | ||||
|                     osMessageQueueDelete(event_queue); | ||||
|                     osMessageQueueDelete(irda_app.cli_ir_rx_queue); | ||||
|                     cli_delete_command(irda_app.cli, "ir_rx"); | ||||
|                     cli_delete_command(irda_app.cli, "ir_tx"); | ||||
|                     furi_record_close("cli"); | ||||
| 
 | ||||
|                     // exit
 | ||||
|                     return 0; | ||||
| @ -346,6 +452,10 @@ int32_t irda(void* p) { | ||||
|                 if(decoded) { | ||||
|                     // save only if we in packet mode
 | ||||
|                     State* state = (State*)acquire_mutex_block(&state_mutex); | ||||
|                     IrDAPacket packet; | ||||
|                     packet.protocol = IRDA_NEC; | ||||
|                     packet.address = out_data[1] << 8 | out_data[0]; | ||||
|                     packet.command = out_data[2]; | ||||
| 
 | ||||
|                     if(state->mode_id == 1) { | ||||
|                         if(out.protocol == IRDA_NEC) { | ||||
| @ -356,15 +466,17 @@ int32_t irda(void* p) { | ||||
|                                 printf("R"); | ||||
|                             } | ||||
|                             printf("\r\n"); | ||||
| 
 | ||||
|                             state->packets[state->packet_id].protocol = IRDA_NEC; | ||||
|                             state->packets[state->packet_id].address = out_data[1] << 8 | | ||||
|                                                                        out_data[0]; | ||||
|                             state->packets[state->packet_id].command = out_data[2]; | ||||
|                             // Save packet to state
 | ||||
|                             memcpy( | ||||
|                                 &(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket)); | ||||
|                         } else { | ||||
|                             printf("Unknown protocol\r\n"); | ||||
|                         } | ||||
|                     } | ||||
|                     if(irda_app.cli_cmd_is_active) { | ||||
|                         // Send decoded packet to cli
 | ||||
|                         osMessageQueuePut(irda_app.cli_ir_rx_queue, &packet, 0, 0); | ||||
|                     } | ||||
| 
 | ||||
|                     release_mutex(&state_mutex, state); | ||||
|                     view_port_update(view_port); | ||||
|  | ||||
| @ -23,6 +23,16 @@ void api_hal_vcp_init(); | ||||
|  */ | ||||
| size_t api_hal_vcp_rx(uint8_t* buffer, size_t size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Recieve data from VCP with timeout | ||||
|  * Waits till some data arrives during timeout | ||||
|  * @param buffer - pointer to buffer | ||||
|  * @param size - buffer size | ||||
|  * @param timeout - rx timeout in ms | ||||
|  * @return items copied in buffer, 0 if channel closed or timeout occurs | ||||
|  */ | ||||
| size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout); | ||||
| 
 | ||||
| /**
 | ||||
|  * Transmit data to VCP | ||||
|  * @param buffer - pointer to buffer | ||||
|  | ||||
| @ -74,6 +74,11 @@ size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) { | ||||
|     return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { | ||||
|     furi_assert(api_hal_vcp); | ||||
|     return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, timeout); | ||||
| } | ||||
| 
 | ||||
| void api_hal_vcp_tx(const uint8_t* buffer, size_t size) { | ||||
|     furi_assert(api_hal_vcp); | ||||
| 
 | ||||
|  | ||||
| @ -74,6 +74,11 @@ size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) { | ||||
|     return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { | ||||
|     furi_assert(api_hal_vcp); | ||||
|     return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, timeout); | ||||
| } | ||||
| 
 | ||||
| void api_hal_vcp_tx(const uint8_t* buffer, size_t size) { | ||||
|     furi_assert(api_hal_vcp); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich