mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-23 13:21:44 +03:00
[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
|
||||
.idea/
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "applications.h"
|
||||
|
||||
// Services and apps decalartion
|
||||
int32_t irda_monitor_app(void* p);
|
||||
int32_t flipper_test_app(void* p);
|
||||
int32_t application_blink(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},
|
||||
#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);
|
||||
|
@ -41,6 +41,7 @@ APP_EXAMPLE_BLINK = 1
|
||||
APP_EXAMPLE_UART_WRITE = 1
|
||||
APP_EXAMPLE_INPUT_DUMP = 1
|
||||
APP_UNIT_TESTS = 1
|
||||
APP_IRDA_MONITOR = 1
|
||||
endif
|
||||
|
||||
SRV_DOLPHIN ?= 0
|
||||
@ -74,6 +75,11 @@ SRV_GUI = 1
|
||||
CFLAGS += -DAPP_MENU
|
||||
endif
|
||||
|
||||
APP_IRDA_MONITOR ?= 0
|
||||
ifeq ($(APP_IRDA_MONITOR), 1)
|
||||
CFLAGS += -DAPP_IRDA_MONITOR
|
||||
endif
|
||||
|
||||
APP_UNIT_TESTS ?= 0
|
||||
ifeq ($(APP_UNIT_TESTS), 1)
|
||||
CFLAGS += -DAPP_UNIT_TESTS
|
||||
|
255
applications/irda/irda.c → applications/irda/irda_app.c
Executable file → Normal file
255
applications/irda/irda.c → applications/irda/irda_app.c
Executable file → Normal file
@ -4,10 +4,8 @@
|
||||
#include <input/input.h>
|
||||
#include <cli/cli.h>
|
||||
|
||||
#include "irda_nec.h"
|
||||
#include "irda_samsung.h"
|
||||
#include "irda_protocols.h"
|
||||
#include "irda-decoder/irda-decoder.h"
|
||||
#include <api-hal-irda.h>
|
||||
#include "irda.h"
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
@ -15,24 +13,21 @@ typedef enum {
|
||||
EventTypeRX,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
bool edge;
|
||||
uint32_t lasted;
|
||||
} RXValue;
|
||||
typedef IrdaMessage IrDAPacket;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
RXValue rx;
|
||||
IrDAPacket rx;
|
||||
} value;
|
||||
EventType type;
|
||||
} AppEvent;
|
||||
|
||||
typedef struct {
|
||||
IrDAProtocolType protocol;
|
||||
uint32_t address;
|
||||
uint32_t command;
|
||||
} IrDAPacket;
|
||||
//typedef struct {
|
||||
// IrdaProtocol protocol;
|
||||
// uint32_t address;
|
||||
// uint32_t command;
|
||||
//} IrDAPacket;
|
||||
|
||||
#define IRDA_PACKET_COUNT 8
|
||||
|
||||
@ -88,9 +83,9 @@ void render_carrier(Canvas* canvas, State* state) {
|
||||
void input_carrier(AppEvent* event, State* state) {
|
||||
if(event->value.input.key == InputKeyOk) {
|
||||
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) {
|
||||
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, 37, "? /\\ \\/ packet");
|
||||
{
|
||||
const char* protocol;
|
||||
|
||||
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];
|
||||
char buf[30];
|
||||
sprintf(
|
||||
buf,
|
||||
"P[%d]: %s 0x%lX 0x%lX",
|
||||
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].command);
|
||||
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) {
|
||||
if(event->value.input.key == InputKeyOk) {
|
||||
if(event->value.input.type == InputTypeShort) {
|
||||
switch(state->packets[state->packet_id].protocol) {
|
||||
case IRDA_NEC:
|
||||
ir_nec_send(
|
||||
state->packets[state->packet_id].address,
|
||||
state->packets[state->packet_id].command);
|
||||
break;
|
||||
case IRDA_SAMSUNG:
|
||||
ir_samsung_send(
|
||||
state->packets[state->packet_id].address,
|
||||
state->packets[state->packet_id].command);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
IrdaMessage message = {
|
||||
.protocol = state->packets[state->packet_id].protocol,
|
||||
.address = state->packets[state->packet_id].address,
|
||||
.command = state->packets[state->packet_id].command,
|
||||
};
|
||||
irda_send(&message, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,39 +173,10 @@ static void input_callback(InputEvent* input_event, void* ctx) {
|
||||
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(
|
||||
State* state,
|
||||
uint8_t index,
|
||||
IrDAProtocolType protocol,
|
||||
IrdaProtocol protocol,
|
||||
uint32_t address,
|
||||
uint32_t command) {
|
||||
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");
|
||||
while(!exit) {
|
||||
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(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),
|
||||
"%s "
|
||||
"Address:0x%02X Command: 0x%02X %s\r\n",
|
||||
irda_get_protocol_name(packet.protocol),
|
||||
(uint8_t)packet.address,
|
||||
(uint8_t)packet.command);
|
||||
(uint8_t)packet.command,
|
||||
packet.repeat ? "R" : "");
|
||||
}
|
||||
}
|
||||
printf("Interrupt command received");
|
||||
@ -275,7 +215,7 @@ void irda_cli_cmd_tx(string_t args, void* context) {
|
||||
furi_assert(context);
|
||||
ValueMutex* state_mutex = context;
|
||||
// Read protocol name
|
||||
IrDAProtocolType protocol;
|
||||
IrdaProtocol protocol;
|
||||
string_t protocol_str;
|
||||
string_init(protocol_str);
|
||||
size_t ws = string_search_char(args, ' ');
|
||||
@ -289,9 +229,9 @@ void irda_cli_cmd_tx(string_t args, void* context) {
|
||||
string_strim(args);
|
||||
}
|
||||
if(!string_cmp_str(protocol_str, "NEC")) {
|
||||
protocol = IRDA_NEC;
|
||||
protocol = IrdaProtocolNEC;
|
||||
} else if(!string_cmp_str(protocol_str, "SAMSUNG")) {
|
||||
protocol = IRDA_SAMSUNG;
|
||||
protocol = IrdaProtocolSamsung32;
|
||||
} else {
|
||||
printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`");
|
||||
string_clear(protocol_str);
|
||||
@ -320,15 +260,34 @@ void irda_cli_cmd_tx(string_t args, void* context) {
|
||||
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);
|
||||
}
|
||||
|
||||
IrdaMessage message = {
|
||||
.protocol = protocol,
|
||||
.address = address,
|
||||
.command = command,
|
||||
};
|
||||
irda_send(&message, 1);
|
||||
release_mutex(state_mutex, state);
|
||||
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) {
|
||||
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;
|
||||
|
||||
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, 1, IRDA_NEC, 0xF708, 0x59);
|
||||
init_packet(&_state, 2, IRDA_NEC, 0xFF00, 0x10);
|
||||
init_packet(&_state, 3, IRDA_NEC, 0xFF00, 0x15);
|
||||
init_packet(&_state, 4, IRDA_NEC, 0xFF00, 0x25);
|
||||
init_packet(&_state, 5, IRDA_SAMSUNG, 0xE0E, 0xF30C);
|
||||
init_packet(&_state, 6, IRDA_SAMSUNG, 0xE0E, 0xF40D);
|
||||
init_packet(&_state, 7, IRDA_SAMSUNG, 0xE0E, 0xF50E);
|
||||
init_packet(&_state, 0, IrdaProtocolNEC, 0x00, 0x11);
|
||||
init_packet(&_state, 1, IrdaProtocolNEC, 0x08, 0x59);
|
||||
init_packet(&_state, 2, IrdaProtocolNEC, 0x00, 0x10);
|
||||
init_packet(&_state, 3, IrdaProtocolNEC, 0x00, 0x15);
|
||||
init_packet(&_state, 4, IrdaProtocolNEC, 0x00, 0x25);
|
||||
init_packet(&_state, 5, IrdaProtocolSamsung32, 0x0E, 0x0C);
|
||||
init_packet(&_state, 6, IrdaProtocolSamsung32, 0x0E, 0x0D);
|
||||
init_packet(&_state, 7, IrdaProtocolSamsung32, 0x0E, 0x0E);
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
|
||||
@ -377,13 +336,12 @@ int32_t irda(void* p) {
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// setup irda rx timer
|
||||
tim_irda_rx_init();
|
||||
|
||||
// add timer capture interrupt
|
||||
api_interrupt_add(irda_timer_capture_callback, InterruptTypeTimerCapture, event_queue);
|
||||
|
||||
IrDADecoder* decoder = alloc_decoder();
|
||||
IsrContext isr_context = {
|
||||
.handler = irda_alloc_decoder(),
|
||||
.event_queue = event_queue,
|
||||
};
|
||||
api_hal_irda_rx_irq_init();
|
||||
api_hal_irda_rx_irq_set_callback(irda_rx_callback, &isr_context);
|
||||
|
||||
AppEvent event;
|
||||
while(1) {
|
||||
@ -396,7 +354,6 @@ int32_t irda(void* p) {
|
||||
// press events
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyBack) {
|
||||
api_interrupt_remove(irda_timer_capture_callback, InterruptTypeTimerCapture);
|
||||
release_mutex(&state_mutex, state);
|
||||
|
||||
// remove all view_ports create by app
|
||||
@ -404,14 +361,14 @@ int32_t irda(void* p) {
|
||||
view_port_free(view_port);
|
||||
|
||||
// free decoder
|
||||
free_decoder(decoder);
|
||||
|
||||
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");
|
||||
api_hal_irda_rx_irq_deinit();
|
||||
irda_free_decoder(isr_context.handler);
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
@ -437,58 +394,40 @@ int32_t irda(void* p) {
|
||||
view_port_update(view_port);
|
||||
|
||||
} else if(event.type == EventTypeRX) {
|
||||
IrDADecoderOutputData out;
|
||||
const uint8_t out_data_length = 4;
|
||||
uint8_t out_data[out_data_length];
|
||||
api_hal_light_set(LightRed, 0xFF);
|
||||
delay(60);
|
||||
api_hal_light_set(LightRed, 0xFF);
|
||||
|
||||
out.data_length = out_data_length;
|
||||
out.data = out_data;
|
||||
// save only if we in packet mode
|
||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
||||
IrDAPacket packet = event.value.rx;
|
||||
|
||||
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
|
||||
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) {
|
||||
printf("P=NEC ");
|
||||
printf("A=0x%02X%02X ", out_data[1], out_data[0]);
|
||||
printf("C=0x%02X ", out_data[2]);
|
||||
if(out.flags & IRDA_REPEAT) {
|
||||
printf("R");
|
||||
}
|
||||
printf("\r\n");
|
||||
// Save packet to state
|
||||
memcpy(
|
||||
&(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket));
|
||||
} else {
|
||||
printf("Unknown protocol\r\n");
|
||||
}
|
||||
if(state->mode_id == 1) {
|
||||
printf("P=%s ", irda_get_protocol_name(packet.protocol));
|
||||
printf("A=0x%02lX ", packet.address);
|
||||
printf("C=0x%02lX ", packet.command);
|
||||
if(packet.repeat) {
|
||||
printf("R");
|
||||
}
|
||||
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);
|
||||
|
||||
// blink anyway
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
printf("\r\n");
|
||||
// Save packet to state
|
||||
memcpy(&(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket));
|
||||
}
|
||||
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);
|
||||
|
||||
// blink anyway
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
}
|
||||
|
||||
} else {
|
||||
// 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() {
|
||||
mu_assert(false, "please reimplement or delete test");
|
||||
// TODO: reimplement or delete test
|
||||
return;
|
||||
/*
|
||||
// 1. Create holding record
|
||||
ConcurrentValue value = {.a = 0, .b = 0};
|
||||
@ -126,4 +127,4 @@ void test_furi_concurrent_access() {
|
||||
|
||||
mu_check(delete_mutex(&mutex));
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
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 <furi.h>
|
||||
#include "minunit_vars.h"
|
||||
#include "minunit.h"
|
||||
|
||||
// v2 tests
|
||||
@ -66,4 +65,4 @@ int run_minunit() {
|
||||
MU_REPORT();
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
#include "minunit_vars.h"
|
||||
|
||||
int run_minunit();
|
||||
int run_minunit_test_irda_decoder();
|
||||
|
||||
int32_t flipper_test_app(void* p) {
|
||||
uint32_t test_result = 0;
|
||||
|
||||
api_hal_light_set(LightRed, 0x00);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
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) {
|
||||
// test passed
|
||||
api_hal_light_set(LightRed, 0x00);
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
api_hal_light_set(LightBlue, 0x00);
|
||||
} else {
|
||||
// test failed
|
||||
api_hal_light_set(LightRed, 0xFF);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
api_hal_light_set(LightBlue, 0x00);
|
||||
/* power_charging_indication_handler() breaks 1 sec light on */
|
||||
for(int i = 0; i < 1000; ++i) {
|
||||
if(test_result == 0) {
|
||||
// test passed
|
||||
api_hal_light_set(LightRed, 0x00);
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
api_hal_light_set(LightBlue, 0x00);
|
||||
} else {
|
||||
// test failed
|
||||
api_hal_light_set(LightRed, 0xFF);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
api_hal_light_set(LightBlue, 0x00);
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ typedef void (*InterruptCallback)(void*, void*);
|
||||
/** Interupt type */
|
||||
typedef enum {
|
||||
InterruptTypeComparatorTrigger,
|
||||
InterruptTypeTimerCapture,
|
||||
InterruptTypeTimerOutputCompare,
|
||||
InterruptTypeTimerUpdate,
|
||||
InterruptTypeExternalInterrupt,
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <furi/thread.h>
|
||||
#include <furi/valuemutex.h>
|
||||
#include <furi/log.h>
|
||||
#include <furi/utils.h>
|
||||
|
||||
#include <api-hal-gpio.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/targets' -prune \) \
|
||||
-not \( -path './assets' -prune \) \
|
||||
-not \( -path './applications/tests/irda_decoder/test_data' -prune \) \
|
||||
-not \( -path ./lib -prune \) \
|
||||
-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);
|
||||
}
|
||||
|
||||
void TIM2_IRQHandler(void) {
|
||||
HAL_TIM_IRQHandler(&htim2);
|
||||
}
|
||||
|
||||
void HSEM_IRQHandler(void) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel);
|
||||
|
||||
void irda_pwm_set(float value, float freq);
|
||||
void irda_pwm_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,47 +1,46 @@
|
||||
#include "cmsis_os.h"
|
||||
#include "api-hal-tim.h"
|
||||
#include "api-hal-tim_i.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;
|
||||
htim2.Init.Prescaler = 64 - 1;
|
||||
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim2.Init.Period = 4294967295;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if(HAL_TIM_Base_Init(&htim2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
void TIM2_IRQHandler(void)
|
||||
{
|
||||
bool consumed = false;
|
||||
|
||||
if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1) {
|
||||
if (LL_TIM_IsEnabledIT_CC1(TIM2)) {
|
||||
LL_TIM_ClearFlag_CC1(TIM2);
|
||||
|
||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
||||
// input capture
|
||||
api_hal_irda_tim_isr(TimerIRQSourceCCI1);
|
||||
consumed = true;
|
||||
}
|
||||
else {
|
||||
// output compare
|
||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
||||
}
|
||||
}
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
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;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
|
||||
sConfigIC.ICFilter = 0;
|
||||
if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
|
||||
if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
if(LL_TIM_IsActiveFlag_CC2(TIM2) == 1) {
|
||||
if (LL_TIM_IsEnabledIT_CC2(TIM2)) {
|
||||
LL_TIM_ClearFlag_CC2(TIM2);
|
||||
|
||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
||||
// input capture
|
||||
api_hal_irda_tim_isr(TimerIRQSourceCCI2);
|
||||
consumed = true;
|
||||
}
|
||||
else {
|
||||
// output compare
|
||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
|
||||
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
|
||||
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
|
||||
}
|
||||
furi_check(consumed);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* Timer input capture event */
|
||||
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) {
|
||||
api_interrupt_call(InterruptTypeTimerCapture, htim);
|
||||
}
|
||||
|
||||
/* Output compare event */
|
||||
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* 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) {
|
||||
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_i2c.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_usb.c \
|
||||
$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
|
||||
|
@ -86,10 +86,6 @@ void TIM1_CC_IRQHandler(void) {
|
||||
HAL_TIM_IRQHandler(&htim1);
|
||||
}
|
||||
|
||||
void TIM2_IRQHandler(void) {
|
||||
HAL_TIM_IRQHandler(&htim2);
|
||||
}
|
||||
|
||||
void HSEM_IRQHandler(void) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel);
|
||||
|
||||
void irda_pwm_set(float value, float freq);
|
||||
void irda_pwm_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,47 +1,46 @@
|
||||
#include "cmsis_os.h"
|
||||
#include "api-hal-tim.h"
|
||||
#include "api-hal-tim_i.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;
|
||||
htim2.Init.Prescaler = 64 - 1;
|
||||
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim2.Init.Period = 4294967295;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if(HAL_TIM_Base_Init(&htim2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
void TIM2_IRQHandler(void)
|
||||
{
|
||||
bool consumed = false;
|
||||
|
||||
if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1) {
|
||||
if (LL_TIM_IsEnabledIT_CC1(TIM2)) {
|
||||
LL_TIM_ClearFlag_CC1(TIM2);
|
||||
|
||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) {
|
||||
// input capture
|
||||
api_hal_irda_tim_isr(TimerIRQSourceCCI1);
|
||||
consumed = true;
|
||||
}
|
||||
else {
|
||||
// output compare
|
||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
||||
}
|
||||
}
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
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;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
|
||||
sConfigIC.ICFilter = 0;
|
||||
if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
|
||||
if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
if(LL_TIM_IsActiveFlag_CC2(TIM2) == 1) {
|
||||
if (LL_TIM_IsEnabledIT_CC2(TIM2)) {
|
||||
LL_TIM_ClearFlag_CC2(TIM2);
|
||||
|
||||
if (READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) {
|
||||
// input capture
|
||||
api_hal_irda_tim_isr(TimerIRQSourceCCI2);
|
||||
consumed = true;
|
||||
}
|
||||
else {
|
||||
// output compare
|
||||
// HAL_TIM_OC_DelayElapsedCallback(htim);
|
||||
// HAL_TIM_PWM_PulseFinishedCallback(htim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
|
||||
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
|
||||
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
|
||||
}
|
||||
furi_check(consumed);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* Timer input capture event */
|
||||
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) {
|
||||
api_interrupt_call(InterruptTypeTimerCapture, htim);
|
||||
}
|
||||
|
||||
/* Output compare event */
|
||||
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* 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) {
|
||||
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_i2c.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_usb.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
|
||||
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"
|
||||
@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)
|
||||
|
Loading…
Reference in New Issue
Block a user