Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support IR in the simulator with FLIRC #93

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/build-platformio-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/cache@v4
with:
path: |
Expand All @@ -27,7 +29,7 @@ jobs:

- name: Install SDL2
run: |
brew install sdl2 sdl2_image
brew install sdl2 sdl2_image hidapi



Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/build-platformio-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/cache@v4
with:
path: |
Expand All @@ -29,7 +31,7 @@ jobs:
run: |
sudo apt update
sudo apt upgrade -y
sudo apt install -y libsdl2-dev libsdl2-image-dev
sudo apt install -y libsdl2-dev libsdl2-image-dev libusb-1.0-0-dev libhidapi-dev libhidapi-hidraw0



Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/build-platformio-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
- { sys: mingw32, env: i686 }
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/cache@v4
with:
path: |
Expand All @@ -25,7 +27,7 @@ jobs:
with:
python-version: "3.12"

- name: Install MSYS2 MINGW64/32 and SDL2
- name: Install MSYS2 MINGW64/32, SDL2, SDL2_image, hidapi, libusb
if: ${{matrix.sys != 'xtensa'}}
uses: msys2/setup-msys2@v2
with:
Expand All @@ -35,6 +37,8 @@ jobs:
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-SDL2
mingw-w64-${{matrix.env}}-SDL2_image
mingw-w64-${{matrix.env}}-hidapi
mingw-w64-${{matrix.env}}-libusb
- name: Add paths mingw64
if: ${{matrix.sys == 'mingw64'}}
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "Platformio/hardware/windows_linux/lib/flirc_sdk"]
path = Platformio/hardware/windows_linux/lib/flirc_sdk
url = https://github.com/flirc/sdk
45 changes: 45 additions & 0 deletions Platformio/.macos_universal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Combine the macos ARM and x86 libraries into a fat library
# This makes it so we don't have to do more work on the build config to get the right platform
# It also helps work around an issue where the linker sees the dylib files in the flirc sdk folder
# and tries to link against and fails. This way we have a folder with only the static libraries
# The linker can handle that correctly.

import os
import subprocess

Import("env")

script_dir = env['PROJECT_DIR']

# Define paths
libs_folder = os.path.join(script_dir, 'hardware', 'windows_linux', 'lib', 'flirc_sdk', 'libs')
arm_path = os.path.join(script_dir, libs_folder, 'Darwin_arm64')
x86_path = os.path.join(script_dir, libs_folder, 'Darwin_x86_64')
universal_path = os.path.join(script_dir, libs_folder, 'Darwin_universal')

# Create directory if it doesn't exist
os.makedirs(universal_path, exist_ok=True)

# Define output files
libir_universal = os.path.join(universal_path, 'libir.a')
libflirc_universal = os.path.join(universal_path, 'libflirc.a')

# Check and create libir.a if it doesn't exist
if not os.path.exists(libir_universal):
try:
subprocess.run(['lipo', '-create', f'{arm_path}/libir.a', f'{x86_path}/libir.a', '-o', libir_universal], check=True)
print("libir.a universal binary created successfully.")
except subprocess.CalledProcessError as e:
print(f"An error occurred while creating libir.a: {e}")
else:
print("libir.a already exists. Skipping creation.")

# Check and create libflirc.a if it doesn't exist
if not os.path.exists(libflirc_universal):
try:
subprocess.run(['lipo', '-create', f'{arm_path}/libflirc.a', f'{x86_path}/libflirc.a', '-o', libflirc_universal], check=True)
print("libflirc.a universal binary created successfully.")
except subprocess.CalledProcessError as e:
print(f"An error occurred while creating libflirc.a: {e}")
else:
print("libflirc.a already exists. Skipping creation.")
29 changes: 29 additions & 0 deletions Platformio/.win_ranlib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Make sure that the windows flirc archives have an index
# if they don't mingw can't link against them

import os
import subprocess

Import("env")

script_dir = env['PROJECT_DIR']

def update_archive_and_stamp(archive_path):
# Determine the directory and stamp file's path
directory = os.path.dirname(archive_path)

# Run the 'ar s' command to add an index to the archive
try:
subprocess.run(['ar', 's', archive_path], check=True)
print(f"Indexed {archive_path} successfully.")
except subprocess.CalledProcessError as e:
print(f"An error occurred while indexing {archive_path}: {e}")
return

archives = [
os.path.join(script_dir, "hardware/windows_linux/lib/flirc_sdk/libs/Win/libflirc.a"),
os.path.join(script_dir, "hardware/windows_linux/lib/flirc_sdk/libs/Win64/libflirc.a")
]

for archive in archives:
update_archive_and_stamp(archive)
Original file line number Diff line number Diff line change
@@ -1,15 +1,108 @@
#include "infrared_receiver_hal_windows_linux.h"

#include <map>
#include <string>

#include <flirc/flirc.h>
#include <ir/ir.h>

#include "util.h"

bool irReceiverEnabled = false;

std::map<enum rc_proto, std::string> protoToString = {
{RC_PROTO_UNKNOWN, "UNKNOWN"},
{RC_PROTO_INVALID, "INVALID"},
{RC_PROTO_OTHER, "OTHER"},
{RC_PROTO_RC5, "RC5"},
{RC_PROTO_RC5X_20, "RC5X_20"},
{RC_PROTO_RC5_SZ, "RC5_SZ"},
{RC_PROTO_JVC, "JVC"},
{RC_PROTO_SONY12, "SONY12"},
{RC_PROTO_SONY15, "SONY15"},
{RC_PROTO_SONY20, "SONY20"},
{RC_PROTO_NEC, "NEC"},
{RC_PROTO_NECX, "NECX"},
{RC_PROTO_NEC32, "NEC32"},
{RC_PROTO_NEC48, "NEC48"},
{RC_PROTO_SANYO, "SANYO"},
{RC_PROTO_MCIR2_KBD, "MCIR2_KBD"},
{RC_PROTO_MCIR2_MSE, "MCIR2_MSE"},
{RC_PROTO_RC6_0, "RC6_0"},
{RC_PROTO_RC6_6A_20, "RC6_6A_20"},
{RC_PROTO_RC6_6A_24, "RC6_6A_24"},
{RC_PROTO_RC6_6A_32, "RC6_6A_32"},
{RC_PROTO_RC6_MCE, "RC6_MCE"},
{RC_PROTO_SHARP, "SHARP"},
{RC_PROTO_XMP, "XMP"},
{RC_PROTO_CEC, "CEC"},
{RC_PROTO_IMON, "IMON"},
{RC_PROTO_RCMM12, "RCMM12"},
{RC_PROTO_RCMM24, "RCMM24"},
{RC_PROTO_RCMM32, "RCMM32"},
{RC_PROTO_ORTEK, "ORTEK"},
{RC_PROTO_DENON, "DENON"},
{RC_PROTO_DENONK, "DENONK"},
{RC_PROTO_FLIRC, "FLIRC"},
{RC_PROTO_NOKIA12, "NOKIA12"},
{RC_PROTO_NOKIA24, "NOKIA24"},
{RC_PROTO_NOKIA32, "NOKIA32"},
{RC_PROTO_TDC, "TDC"},
{RC_PROTO_AMINO, "AMINO"},
{RC_PROTO_NEC_APPLE, "NEC_APPLE"},
{RC_PROTO_NEC_REPEAT, "NEC_REPEAT"},
{RC_PROTO_PANASONIC, "PANASONIC"},
{RC_PROTO_GAP, "GAP"},
};

void start_infraredReceiver_HAL() {
fl_dev_flush();
}

void shutdown_infraredReceiver_HAL() {
}

// The repeating section of the code
tAnnounceNewIRmessage_cb thisAnnounceNewIRmessage_cb = NULL;
void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb) {
thisAnnounceNewIRmessage_cb = pAnnounceNewIRmessage_cb;
}

struct ir_prot d;
struct ir_packet p;

void infraredReceiver_loop_HAL() {
switch (fl_ir_packet_poll(&p)) {
case (1):
{
printf("----------------\n");
ir_decode_packet(&p, &d);

printf("0x%08X - %s : %d : hash: 0x%08X\n",
d.scancode, d.desc, d.protocol, d.hash);
printf("----------------\n");
fflush(stdout);

fl_dev_flush();

char code[11];
unsigned long reverse = reverseBits(d.scancode);
std::string typeString = protoToString[d.protocol];
snprintf(code, sizeof(code), "0x%08lX", reverse);

if (thisAnnounceNewIRmessage_cb != NULL) {
thisAnnounceNewIRmessage_cb(typeString + " " + code);
}
}
break;
case (0):
break;
case (-1):
printf("flirc: error, disconnecting\n");
break;
default:
printf("flirc: UNKNOWN ERROR\n");
break;
}
}

bool get_irReceiverEnabled_HAL() {
Expand All @@ -19,4 +112,8 @@ void set_irReceiverEnabled_HAL(bool aIrReceiverEnabled) {
irReceiverEnabled = aIrReceiverEnabled;
}

void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb) {}





Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
#include <string>
#include <list>
#include <cstdio>
#include <inttypes.h>

#include <flirc/flirc.h>
#include <ir/ir.h>

#include "util.h"

static int fl_transmit_fake(uint16_t *buf, uint16_t len, uint16_t ik, uint8_t repeat)
{
int i = 0;
while (repeat --) {
for (i = 0; i < len; i++) {
i & 0x1 ? printf("-") : printf("+");
printf("%d ", buf[i]);
}
printf("\n");
printf("-%d\n", ik*1000);
}
return 0;
}

void init_infraredSender_HAL(void) {
printf("%-20s %-10s\n", "Lib Flirc Version: ", fl_lib_version());
printf("%-20s %-10s\n", "Lib IR Version: ", ir_lib_version());

if (fl_open_device_alt(0x20A0, "flirc.tv") < 0) {
printf("Error: unable to open device\n");
/**
* We can't open the device, so let's fake print the output to
* stdout.
*/
ir_register_tx(fl_transmit_fake);
} else {
/**
* Only necessary if you want to transmit. Purpose of libir is to
* support any transmitter.
*/
ir_register_tx(fl_transmit_raw);
}
}

// IR protocols
Expand All @@ -14,5 +52,79 @@ enum IRprotocols {
IR_PROTOCOL_DENON = 5,
IR_PROTOCOL_SAMSUNG36 = 6
};

void sendIRcode_HAL(int protocol, std::list<std::string> commandPayloads, std::string additionalPayload) {
// first determine if data was provided by commandPayload or by additionalPayload. Only one of these will be used.
std::string::size_type sz = 0; // alias of size_t
std::string dataStr;
uint64_t data;
if (commandPayloads.empty() && (additionalPayload == "")) {
printf("execute: cannot send IR command, because both data and payload are empty\r\n");
return;
} else {
if (additionalPayload != "") {
dataStr = additionalPayload;
} else {
auto current = commandPayloads.begin();
dataStr = *current;
}
}

switch (protocol) {
case IR_PROTOCOL_GC: {

break;
}

case IR_PROTOCOL_NEC: {
data = std::stoull(dataStr, &sz, 0);

printf("execute: will send IR NEC, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);

uint64_t test = reverseBits(data);

printf("test: (%" PRIu64 ")\r\n", test);

ir_tx(RC_PROTO_NEC, test, 0);
break;
}

case IR_PROTOCOL_SAMSUNG: {
data = std::stoull(dataStr, &sz, 0);
printf("execute: will send IR SAMSUNG, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);
//IrSender.sendSAMSUNG(data);
break;
}

case IR_PROTOCOL_SONY: {
data = std::stoull(dataStr, &sz, 0);
printf("execute: will send IR SONY 15 bit, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);
ir_tx(RC_PROTO_SONY15, data, 2);
break;
}

case IR_PROTOCOL_RC5: {
data = std::stoull(dataStr, &sz, 0);
printf("execute: will send IR RC5, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);
// todo?? IrSender.encodeRC5X(0x00, data),
ir_tx(RC_PROTO_RC5, data, 0);
break;
}

case IR_PROTOCOL_DENON: {
data = std::stoull(dataStr, &sz, 0);
printf("execute: will send IR DENON 48 bit, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);
//IrSender.sendDenon(data, 48);
ir_tx(RC_PROTO_DENON, data, 0);
break;
}

case IR_PROTOCOL_SAMSUNG36: {
data = std::stoull(dataStr, &sz, 0);
printf("execute: will send IR SAMSUNG36, data %s (%" PRIu64 ")\r\n", dataStr.c_str(), data);
//IrSender.sendSamsung36(data);
break;
}
}

}
1 change: 1 addition & 0 deletions Platformio/hardware/windows_linux/lib/flirc_sdk
Submodule flirc_sdk added at 280ccc
Loading