mirror of
https://github.com/openshwprojects/OpenBK7231T_App.git
synced 2026-03-03 14:06:09 +01:00
* add IRRemoteSP * fx * Update IRsend.cpp * f * fix * s * irRemoteESP * Update obk_config_irRemoteESP.h * w
977 lines
27 KiB
C++
977 lines
27 KiB
C++
|
|
#include "../obk_config.h"
|
|
|
|
#if ENABLE_DRIVER_IRREMOTEESP
|
|
// drv_ir_new.cpp - IRremoteESP8266
|
|
|
|
extern "C" {
|
|
// these cause error: conflicting declaration of 'int bk_wlan_mcu_suppress_and_sleep(unsigned int)' with 'C' linkage
|
|
#include "../new_common.h"
|
|
|
|
#include "include.h"
|
|
#include "arm_arch.h"
|
|
#include "../new_pins.h"
|
|
#include "../new_cfg.h"
|
|
#include "../logging/logging.h"
|
|
#include "../obk_config.h"
|
|
#include "../cmnds/cmd_public.h"
|
|
#include "bk_timer_pub.h"
|
|
#include "drv_model_pub.h"
|
|
|
|
// why can;t I call this?
|
|
#include "../mqtt/new_mqtt.h"
|
|
|
|
#include <gpio_pub.h>
|
|
//#include "pwm.h"
|
|
#include "pwm_pub.h"
|
|
|
|
#include "../../beken378/func/include/net_param_pub.h"
|
|
#include "../../beken378/func/user_driver/BkDriverPwm.h"
|
|
#include "../../beken378/func/user_driver/BkDriverI2c.h"
|
|
#include "../../beken378/driver/i2c/i2c1.h"
|
|
#include "../../beken378/driver/gpio/gpio.h"
|
|
|
|
|
|
unsigned long ir_counter = 0;
|
|
uint8_t gEnableIRSendWhilstReceive = 0;
|
|
uint32_t gIRProtocolEnable = 0xFFFFFFFF;
|
|
// 0 == active low. 1 = active hi
|
|
uint8_t gIRPinPolarity = 0;
|
|
|
|
extern int my_strnicmp(const char* a, const char* b, int len);
|
|
}
|
|
|
|
|
|
#include "drv_ir.h"
|
|
|
|
//#define USE_IRREMOTE_HPP_AS_PLAIN_INCLUDE 1
|
|
#undef read
|
|
#undef write
|
|
#undef send
|
|
//#define PROGMEM
|
|
|
|
|
|
//#define NO_LED_FEEDBACK_CODE 1
|
|
|
|
//typedef unsigned char uint_fast8_t;
|
|
typedef unsigned short uint16_t;
|
|
|
|
#define __FlashStringHelper char
|
|
|
|
// dummy functions
|
|
void noInterrupts() {}
|
|
void interrupts() {}
|
|
|
|
unsigned long millis() {
|
|
return 0;
|
|
}
|
|
unsigned long micros() {
|
|
return 0;
|
|
}
|
|
|
|
|
|
void delay(int n) {
|
|
return;
|
|
}
|
|
|
|
void delayMicroseconds(int n) {
|
|
return;
|
|
}
|
|
|
|
class Print {
|
|
public:
|
|
void println(const char *p) {
|
|
return;
|
|
}
|
|
void print(...) {
|
|
return;
|
|
}
|
|
};
|
|
|
|
Print Serial;
|
|
|
|
|
|
|
|
|
|
#define EXTERNAL_IR_TIMER_ISR
|
|
|
|
//////////////////////////////////////////
|
|
// our external timer interrupt stuff
|
|
// this will have already been done
|
|
#define TIMER_RESET_INTR_PENDING
|
|
|
|
|
|
// # if defined(ISR)
|
|
// #undef ISR
|
|
// # endif
|
|
// #define ISR void IR_ISR
|
|
|
|
// THIS function is defined in src/libraries/IRremoteESP8266/src/IRrecv.cpp
|
|
extern "C" void DRV_IR_ISR(UINT8 t);
|
|
extern void IR_ISR();
|
|
|
|
static UINT32 ir_chan = BKTIMER0;
|
|
static UINT32 ir_div = 1;
|
|
static UINT32 ir_periodus = 50;
|
|
|
|
void timerConfigForReceive() {
|
|
// nothing here`
|
|
}
|
|
|
|
void _timerConfigForReceive() {
|
|
ir_counter = 0;
|
|
|
|
timer_param_t params = {
|
|
(unsigned char)ir_chan,
|
|
(unsigned char)ir_div, // div
|
|
ir_periodus, // us
|
|
DRV_IR_ISR
|
|
};
|
|
//GLOBAL_INT_DECLARATION();
|
|
|
|
|
|
UINT32 res;
|
|
// test what error we get with an invalid command
|
|
res = sddev_control((char *)TIMER_DEV_NAME, -1, nullptr);
|
|
|
|
if (res == 1) {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"bk_timer already initialised");
|
|
}
|
|
else {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"bk_timer driver not initialised?");
|
|
if ((int)res == -5) {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"bk_timer sddev not found - not initialised?");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer init");
|
|
// do not need to do this
|
|
//bk_timer_init();
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer init done");
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"will ir timer setup %u", res);
|
|
res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_INIT_PARAM_US, ¶ms);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer setup %u", res);
|
|
res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_UNIT_ENABLE, &ir_chan);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer enabled %u", res);
|
|
}
|
|
|
|
static void timer_enable() {
|
|
}
|
|
static void timer_disable() {
|
|
}
|
|
static void _timer_enable() {
|
|
UINT32 res;
|
|
res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_UNIT_ENABLE, &ir_chan);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer enabled %u", res);
|
|
}
|
|
static void _timer_disable() {
|
|
UINT32 res;
|
|
res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_UNIT_DISABLE, &ir_chan);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer disabled %u", res);
|
|
}
|
|
|
|
#define TIMER_ENABLE_RECEIVE_INTR timer_enable();
|
|
#define TIMER_DISABLE_RECEIVE_INTR timer_disable();
|
|
|
|
//////////////////////////////////////////
|
|
|
|
class SpoofIrReceiver {
|
|
public:
|
|
static void restartAfterSend() {
|
|
|
|
}
|
|
};
|
|
|
|
SpoofIrReceiver IrReceiver;
|
|
|
|
#include "../libraries/IRremoteESP8266/src/IRremoteESP8266.h"
|
|
#include "../libraries/IRremoteESP8266/src/IRsend.h"
|
|
#include "../libraries/IRremoteESP8266/src/IRrecv.h"
|
|
#include "../libraries/IRremoteESP8266/src/IRutils.h"
|
|
#ifdef ENABLE_IRAC
|
|
#include "../libraries/IRremoteESP8266/src/IRac.h"
|
|
#endif
|
|
#include "../libraries/IRremoteESP8266/src/IRproto.h"
|
|
#include "../libraries/IRremoteESP8266/src/digitalWriteFast.h"
|
|
|
|
extern "C" int PIN_GetPWMIndexForPinIndex(int pin);
|
|
|
|
// override aspects of sending for our own interrupt driven sends
|
|
// basically, IRsend calls mark(us) and space(us) to send.
|
|
// we simply note the numbers into a rolling buffer, assume the first is a mark()
|
|
// and then every 50us service the rolling buffer, changing the PWM from 0 duty to 50% duty
|
|
// appropriately.
|
|
#define SEND_MAXBITS 128
|
|
|
|
class myIRsend : public IRsend {
|
|
public:
|
|
myIRsend(uint_fast8_t aSendPin) :IRsend(aSendPin) {
|
|
our_us = 0;
|
|
our_ms = 0;
|
|
resetsendqueue();
|
|
}
|
|
~myIRsend() { }
|
|
|
|
|
|
uint32_t millis() {
|
|
return our_ms;
|
|
}
|
|
|
|
void delay(long int ms) {
|
|
// add a pure delay to our queue
|
|
space(ms * 1000);
|
|
}
|
|
|
|
uint16_t mark(uint16_t aMarkMicros) {
|
|
// sends a high for aMarkMicros
|
|
uint32_t newtimein = (timein + 1) % (SEND_MAXBITS * 2);
|
|
if (newtimein != timeout) {
|
|
// store mark bits in highest +ve bit of count
|
|
times[timein] = aMarkMicros | 0x10000000;
|
|
timein = newtimein;
|
|
timecount++;
|
|
timecounttotal++;
|
|
}
|
|
else {
|
|
overflows++;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void space(uint32_t aMarkMicros) {
|
|
// sends a low for aMarkMicros
|
|
uint32_t newtimein = (timein + 1) % (SEND_MAXBITS * 2);
|
|
if (newtimein != timeout) {
|
|
times[timein] = aMarkMicros;
|
|
timein = newtimein;
|
|
timecount++;
|
|
timecounttotal++;
|
|
}
|
|
else {
|
|
overflows++;
|
|
}
|
|
}
|
|
|
|
void enableIROut(uint32_t freq, uint8_t duty=50) {
|
|
//uint_fast8_t aFrequencyKHz
|
|
if (freq < 1000) // Were we given kHz? Supports the old call usage.
|
|
freq *= 1000;
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"enableIROut %d freq %d duty",(int)freq, (int)duty);
|
|
if(duty<1)
|
|
duty=1;
|
|
if(duty>100)
|
|
duty=100;
|
|
// just setup variables for use in ISR
|
|
//pwmfrequency = ((uint32_t)aFrequencyKHz) * 1000;
|
|
pwmperiod = (26000000 / freq);
|
|
pwmduty = pwmperiod / (100/duty);
|
|
|
|
|
|
#if PLATFORM_BK7231N
|
|
bk_pwm_update_param((bk_pwm_t)this->pwmIndex, this->pwmperiod, pwmduty, 0, 0);
|
|
#else
|
|
bk_pwm_update_param((bk_pwm_t)this->pwmIndex, this->pwmperiod, pwmduty);
|
|
#endif
|
|
}
|
|
|
|
void resetsendqueue() {
|
|
// sends a low for aMarkMicros
|
|
timein = timeout = 0;
|
|
timecount = 0;
|
|
overflows = 0;
|
|
currentsendtime = 0;
|
|
currentbitval = 0;
|
|
timecounttotal = 0;
|
|
}
|
|
int32_t times[SEND_MAXBITS * 2]; // enough for 128 bits
|
|
unsigned short timein;
|
|
unsigned short timeout;
|
|
unsigned short timecount;
|
|
unsigned short overflows;
|
|
uint32_t timecounttotal;
|
|
|
|
int32_t getsendqueue() {
|
|
int32_t val = 0;
|
|
if (timein != timeout) {
|
|
val = times[timeout];
|
|
timeout = (timeout + 1) % (SEND_MAXBITS * 2);
|
|
timecount--;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
int currentsendtime;
|
|
int currentbitval;
|
|
|
|
uint8_t sendPin;
|
|
uint8_t pwmIndex;
|
|
uint32_t pwmfrequency;
|
|
uint32_t pwmperiod;
|
|
uint32_t pwmduty;
|
|
|
|
uint32_t our_ms;
|
|
uint32_t our_us;
|
|
};
|
|
|
|
|
|
// our send/receive instances
|
|
myIRsend *pIRsend = NULL;
|
|
IRrecv *ourReceiver = NULL;
|
|
|
|
// this is our ISR.
|
|
// it is called every 50us, so we need to work on making it as efficient as possible.
|
|
extern "C" void DRV_IR_ISR(UINT8 t) {
|
|
int sending = 0;
|
|
if (pIRsend && (pIRsend->pwmIndex >= 0)) {
|
|
pIRsend->our_us += 50;
|
|
if (pIRsend->our_us > 1000) {
|
|
pIRsend->our_ms++;
|
|
pIRsend->our_us -= 1000;
|
|
}
|
|
|
|
int pinval = 0;
|
|
if (pIRsend->currentsendtime) {
|
|
sending = 1;
|
|
pIRsend->currentsendtime -= ir_periodus;
|
|
if (pIRsend->currentsendtime <= 0) {
|
|
int32_t remains = pIRsend->currentsendtime;
|
|
int32_t newtime = pIRsend->getsendqueue();
|
|
if (0 == newtime) {
|
|
// if it was the last one
|
|
pIRsend->currentsendtime = 0;
|
|
pIRsend->currentbitval = 0;
|
|
}
|
|
else {
|
|
// we got a new time
|
|
// store mark bits in highest +ve bit of count
|
|
pIRsend->currentbitval = (newtime & 0x10000000) ? 1 : 0;
|
|
pIRsend->currentsendtime = (newtime & 0xfffffff);
|
|
// adjust the us value to keep the running accuracy
|
|
// and avoid a running error?
|
|
// note remains is -ve
|
|
pIRsend->currentsendtime += remains;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
int32_t newtime = pIRsend->getsendqueue();
|
|
if (!newtime) {
|
|
pIRsend->currentsendtime = 0;
|
|
pIRsend->currentbitval = 0;
|
|
}
|
|
else {
|
|
sending = 1;
|
|
pIRsend->currentsendtime = (newtime & 0xfffffff);
|
|
pIRsend->currentbitval = (newtime & 0x10000000) ? 1 : 0;
|
|
}
|
|
}
|
|
pinval = pIRsend->currentbitval;
|
|
|
|
uint32_t duty = pIRsend->pwmduty;
|
|
if (!pinval) {
|
|
if (gIRPinPolarity) {
|
|
duty = pIRsend->pwmperiod;
|
|
}
|
|
else {
|
|
duty = 0;
|
|
}
|
|
}
|
|
#if PLATFORM_BK7231N
|
|
bk_pwm_update_param((bk_pwm_t)pIRsend->pwmIndex, pIRsend->pwmperiod, duty, 0, 0);
|
|
#else
|
|
bk_pwm_update_param((bk_pwm_t)pIRsend->pwmIndex, pIRsend->pwmperiod, duty);
|
|
#endif
|
|
}
|
|
|
|
// is someone really wants rx and TX at the same time, then allow it.
|
|
if (gEnableIRSendWhilstReceive) {
|
|
sending = 0;
|
|
}
|
|
|
|
// don't receive if we are currently sending
|
|
if (ourReceiver && !sending){
|
|
IR_ISR();
|
|
}
|
|
ir_counter++;
|
|
}
|
|
|
|
|
|
extern "C" commandResult_t IR_Send_Cmd(const void *context, const char *cmd, const char *args_in, int cmdFlags) {
|
|
if (!args_in) return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
|
char args[128];
|
|
strncpy(args, args_in, sizeof(args) - 1);
|
|
args[sizeof(args) - 1] = 0;
|
|
|
|
// split arg at hyphen;
|
|
char *p = args;
|
|
while (*p && (*p != '-') && (*p != ' ')) {
|
|
p++;
|
|
}
|
|
|
|
if ((*p != '-') && (*p != ' ')) {
|
|
// try to decode "new" format, separated by comma
|
|
// the format is bits,0xDATA[,repeat]
|
|
char *p = args;
|
|
while (*p && (*p != ',')) {
|
|
p++;
|
|
}
|
|
if(*p==',')
|
|
{
|
|
*p='\0';
|
|
decode_type_t protocol = strToDecodeType(args);
|
|
p++;
|
|
char *_bits=p;
|
|
while (*p && (*p != ',')) {
|
|
p++;
|
|
}
|
|
if(*p==',')
|
|
{
|
|
*p='\0';
|
|
uint16_t bits = (uint16_t)strtol(_bits,NULL,10);
|
|
p++;
|
|
if(bits<=64)
|
|
{
|
|
char *_data=p;
|
|
uint64_t data = strtoll(_data,&p,16);
|
|
if(protocol!=decode_type_t::UNKNOWN)
|
|
{
|
|
int repeats=1;
|
|
if(*p==',')
|
|
repeats=strtol(p+1,NULL,10);
|
|
|
|
if( pIRsend->send(protocol,data,bits,repeats) )
|
|
{
|
|
pIRsend->delay(100);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR send %s: protocol %d bits %d data 0x%llX repeats %d", args, (int)protocol, (int)bits, (long long int)data, (int)repeats);
|
|
return CMD_RES_OK;
|
|
} else {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IR can't send %s: protocol %d bits data 0x%llX repeats %d", args, (int)protocol, (long long int)data, (int)repeats);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
}
|
|
} else {
|
|
// TODO: implement longer protocols
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRSend currently only protocol with up to 64bits are supported", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
}
|
|
}
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRSend cmnd not valid [%s] not like [NEC-0-1A] or [NEC 0 1A 1] or [NEC,bits,0xDATA,[repeat]]", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
|
|
*p='\0';
|
|
decode_type_t protocol = strToDecodeType(args);
|
|
if(hasACState(protocol))
|
|
{
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRSend can't send AC commands", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
p++;
|
|
int addr = strtol(p, &p, 16);
|
|
if ((*p != '-') && (*p != ' ')) {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRSend cmnd not valid [%s] not like [NEC-0-1A] or [NEC 0 1A 1].", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
p++;
|
|
int command = strtol(p, &p, 16);
|
|
|
|
int repeats = 0;
|
|
|
|
if ((*p == '-') || (*p == ' ')) {
|
|
p++;
|
|
repeats = strtol(p, &p, 16);
|
|
}
|
|
|
|
if (pIRsend) {
|
|
bool success = true; // Assume success.
|
|
|
|
switch(protocol)
|
|
{
|
|
case decode_type_t::RC5:
|
|
pIRsend->sendRC5((uint64_t)pIRsend->encodeRC5(addr,command));
|
|
break;
|
|
case decode_type_t::RC6:
|
|
pIRsend->sendRC6((uint64_t)pIRsend->encodeRC6(addr,command));
|
|
break;
|
|
case decode_type_t::NEC:
|
|
pIRsend->sendNEC((uint64_t)pIRsend->encodeNEC(addr,command));
|
|
break;
|
|
case decode_type_t::PANASONIC:
|
|
pIRsend->sendPanasonic((uint16_t)addr,(uint32_t)command);
|
|
break;
|
|
case decode_type_t::JVC:
|
|
pIRsend->sendJVC((uint64_t)pIRsend->encodeJVC(addr,command));
|
|
break;
|
|
case decode_type_t::SAMSUNG:
|
|
pIRsend->sendSAMSUNG((uint64_t)pIRsend->encodeSAMSUNG(addr,command));
|
|
break;
|
|
case decode_type_t::LG:
|
|
pIRsend->sendLG((uint64_t)pIRsend->encodeLG(addr,command));
|
|
break;
|
|
default:
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IR send %s protocol not supported", args);
|
|
return CMD_RES_ERROR;
|
|
break;
|
|
};
|
|
|
|
// add a 100ms delay after command
|
|
// NOTE: this is NOT a delay here. it adds 100ms 'space' in the TX queue
|
|
pIRsend->delay(100);
|
|
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR send %s protocol %d addr 0x%X cmd 0x%X repeats %d", args, (int)protocol, (int)addr, (int)command, (int)repeats);
|
|
return CMD_RES_OK;
|
|
}
|
|
else {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR NOT send (no IRsend running) %s protocol %d addr 0x%X cmd 0x%X repeats %d", args, (int)protocol, (int)addr, (int)command, (int)repeats);
|
|
}
|
|
return CMD_RES_ERROR;
|
|
}
|
|
|
|
extern "C" commandResult_t IR_Enable(const void *context, const char *cmd, const char *args_in, int cmdFlags) {
|
|
if (!args_in || !args_in[0]) {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IREnable expects arguments");
|
|
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
|
}
|
|
|
|
char args[128];
|
|
strncpy(args, args_in, sizeof(args)-1);
|
|
args[sizeof(args)-1] = 0;
|
|
char *p = args;
|
|
int enable = 1;
|
|
if (!my_strnicmp(p, "RXTX", 4)) {
|
|
p += 4;
|
|
if (*p == ' ') {
|
|
p++;
|
|
if (*p) {
|
|
enable = atoi(p);
|
|
}
|
|
}
|
|
gEnableIRSendWhilstReceive = enable;
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IREnable RX whilst TX enable set %d", enable);
|
|
return CMD_RES_OK;
|
|
}
|
|
|
|
if (!my_strnicmp(p, "invert", 6)) {
|
|
// default normal.
|
|
enable = 0;
|
|
p += 6;
|
|
if (*p == ' ') {
|
|
p++;
|
|
if (*p) {
|
|
enable = atoi(p);
|
|
}
|
|
}
|
|
gIRPinPolarity = enable;
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IREnable invert set %d", enable);
|
|
return CMD_RES_OK;
|
|
}
|
|
|
|
|
|
// find length of first arg.
|
|
while (*p && (*p != ' ')) {
|
|
p++;
|
|
}
|
|
|
|
//int numProtocols = sizeof(ProtocolNames)/sizeof(*ProtocolNames);
|
|
#if 0 // number of protocols now is 125
|
|
// TODO: reimpleemnt this using bigger mask
|
|
int numProtocols = 0;
|
|
int ournamelen = (p - args);
|
|
int protocol = -1;
|
|
for (int i = 0; i < numProtocols; i++) {
|
|
const char *name = "Unknown"; //= ProtocolNames[i];
|
|
int namelen = strlen(name);
|
|
if (!my_strnicmp(name, args, namelen) && (ournamelen == namelen)) {
|
|
protocol = i;
|
|
break;
|
|
}
|
|
}
|
|
if (*p == ' ') {
|
|
p++;
|
|
if (*p) {
|
|
enable = atoi(p);
|
|
}
|
|
}
|
|
|
|
uint32_t thisbit = (1 << protocol);
|
|
if (protocol < 0) {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IREnable invalid protocol %s", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
else {
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IREnable found protocol %s(%d), enable %d from %s, bitmask 0x%08X", ProtocolNames[protocol], protocol, enable, p, thisbit);
|
|
}
|
|
if (enable) {
|
|
gIRProtocolEnable = gIRProtocolEnable | thisbit;
|
|
}
|
|
else {
|
|
gIRProtocolEnable = gIRProtocolEnable & (~thisbit);
|
|
}
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IREnable Protocol mask now 0x%08X", gIRProtocolEnable);
|
|
#endif //TODO
|
|
return CMD_RES_OK;
|
|
}
|
|
|
|
|
|
extern "C" commandResult_t IR_Param(const void *context, const char *cmd, const char *args_in, int cmdFlags) {
|
|
if (!args_in || !args_in[0]) {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRParam expects two arguments");
|
|
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
|
}
|
|
|
|
if(!ourReceiver)
|
|
{
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRParam: IR reciever disabled");
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
|
|
// Set higher if you get lots of random short UNKNOWN messages when nothing
|
|
// should be sending a message.
|
|
// Set lower if you are sure your setup is working, but it doesn't see messages
|
|
// from your device. (e.g. Other IR remotes work.)
|
|
// NOTE: Set this value very high to effectively turn off UNKNOWN detection.
|
|
int kMinUnknownSize = 12;
|
|
|
|
// How much percentage lee way do we give to incoming signals in order to match
|
|
// it?
|
|
// e.g. +/- 25% (default) to an expected value of 500 would mean matching a
|
|
// value between 375 & 625 inclusive.
|
|
// Note: Default is 25(%). Going to a value >= 50(%) will cause some protocols
|
|
// to no longer match correctly. In normal situations you probably do not
|
|
// need to adjust this value. Typically that's when the library detects
|
|
// your remote's message some of the time, but not all of the time.
|
|
int kTolerancePercentage = 25; // kTolerance is normally 25%
|
|
|
|
int res = sscanf(args_in, "%d %d", &kMinUnknownSize, &kTolerancePercentage);
|
|
|
|
if(res!=2)
|
|
{
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRParam invalid parameters %s", args_in);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
ourReceiver->setUnknownThreshold(kMinUnknownSize);
|
|
ourReceiver->setTolerance(kTolerancePercentage);
|
|
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IRParam MinUnknownSize: %d Noice tolerance: %d%%", kMinUnknownSize,kTolerancePercentage);
|
|
return CMD_RES_OK;
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_IRAC
|
|
extern "C" commandResult_t IR_AC_Cmd(const void *context, const char *cmd, const char *args_in, int cmdFlags) {
|
|
if (!args_in) return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
|
|
|
char args[64];
|
|
strncpy(args, args_in, sizeof(args) - 1);
|
|
args[sizeof(args) - 1] = 0;
|
|
|
|
// split arg at hyphen;
|
|
char *p = args;
|
|
while (*p && (*p != '-') && (*p != ' ')) {
|
|
p++;
|
|
}
|
|
int ournamelen = (p - args);
|
|
if ((*p != '-') && (*p != ' ')) {
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRAC cmnd not valid [%s] ", args);
|
|
return CMD_RES_BAD_ARGUMENT;
|
|
}
|
|
// decode_type_t protocol = strToDecodeType(args);
|
|
|
|
ADDLOG_ERROR(LOG_FEATURE_IR, (char *)"IRAC cmnd not implemented yet", args);
|
|
|
|
return CMD_RES_OK;
|
|
}
|
|
#endif //ENABLE_IRAC
|
|
|
|
|
|
// test routine to start IR RX and TX
|
|
// currently fixed pins for testing.
|
|
extern "C" void DRV_IR_Init() {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"Log from extern C CPP");
|
|
|
|
int pin = -1; //9;// PWM3/25
|
|
int txpin = -1; //24;// PWM3/25
|
|
|
|
// allow user to change them
|
|
pin = PIN_FindPinIndexForRole(IOR_IRRecv, pin);
|
|
txpin = PIN_FindPinIndexForRole(IOR_IRSend, txpin);
|
|
|
|
if (ourReceiver){
|
|
IRrecv *temp = ourReceiver;
|
|
ourReceiver = NULL;
|
|
delete temp;
|
|
}
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"DRV_IR_Init: recv pin %i", pin);
|
|
if ((pin > 0) || (txpin > 0)) {
|
|
}
|
|
else {
|
|
_timer_disable();
|
|
}
|
|
|
|
if (pin > 0) {
|
|
// setup IRrecv pin as input
|
|
//bk_gpio_config_input_pup((GPIO_INDEX)pin); // enabled by enableIRIn
|
|
|
|
//TODO: we should specify buffer size (now set to 1024), timeout (now 90ms) and tolerance
|
|
ourReceiver = new IRrecv(pin);
|
|
ourReceiver->enableIRIn(true);// try with pullup
|
|
}
|
|
|
|
if (pIRsend) {
|
|
myIRsend *pIRsendTemp = pIRsend;
|
|
pIRsend = NULL;
|
|
delete pIRsendTemp;
|
|
}
|
|
|
|
if (txpin > 0) {
|
|
int pwmIndex = PIN_GetPWMIndexForPinIndex(txpin);
|
|
// is this pin capable of PWM?
|
|
if (pwmIndex != -1) {
|
|
uint32_t pwmfrequency = 38000;
|
|
uint32_t period = (26000000 / pwmfrequency);
|
|
uint32_t duty = period / 2;
|
|
#if PLATFORM_BK7231N
|
|
// OSStatus bk_pwm_initialize(bk_pwm_t pwm, uint32_t frequency, uint32_t duty_cycle);
|
|
bk_pwm_initialize((bk_pwm_t)pwmIndex, period, duty, 0, 0);
|
|
#else
|
|
bk_pwm_initialize((bk_pwm_t)pwmIndex, period, duty);
|
|
#endif
|
|
bk_pwm_start((bk_pwm_t)pwmIndex);
|
|
myIRsend *pIRsendTemp = new myIRsend((uint_fast8_t)txpin);
|
|
pIRsendTemp->resetsendqueue();
|
|
pIRsendTemp->enableIROut(pwmfrequency,50);
|
|
pIRsendTemp->pwmIndex = pwmIndex;
|
|
pIRsendTemp->pwmduty = duty;
|
|
pIRsendTemp->pwmperiod = period;
|
|
|
|
pIRsend = pIRsendTemp;
|
|
//bk_pwm_stop((bk_pwm_t)pIRsend->pwmIndex);
|
|
|
|
//cmddetail:{"name":"IRSend","args":"[PROT-ADDR-CMD-REP]",
|
|
//cmddetail:"descr":"Sends IR commands in the form PROT-ADDR-CMD-REP, e.g. NEC-1-1A-0",
|
|
//cmddetail:"fn":"IR_Send_Cmd","file":"driver/drv_ir.cpp","requires":"",
|
|
//cmddetail:"examples":""}
|
|
CMD_RegisterCommand("IRSend", IR_Send_Cmd, NULL);
|
|
//cmddetail:{"name":"IRAC","args":"[TODO]",
|
|
//cmddetail:"descr":"Sends IR commands for HVAC control (TODO)",
|
|
//cmddetail:"fn":"IR_AC_Cmd","file":"driver/drv_ir.cpp","requires":"",
|
|
//cmddetail:"examples":""}
|
|
#ifdef ENABLE_IRAC
|
|
CMD_RegisterCommand("IRAC", IR_AC_Cmd, NULL);
|
|
#endif //ENABLE_IRAC
|
|
//cmddetail:{"name":"IREnable","args":"[Str][1or0]",
|
|
//cmddetail:"descr":"Enable/disable aspects of IR. IREnable RXTX 0/1 - enable Rx whilst Tx. IREnable [protocolname] 0/1 - enable/disable a specified protocol",
|
|
//cmddetail:"fn":"IR_Enable","file":"driver/drv_ir.cpp","requires":"",
|
|
//cmddetail:"examples":""}
|
|
CMD_RegisterCommand("IREnable",IR_Enable, NULL);
|
|
//cmddetail:{"name":"IRParam","args":"[MinSize] [Noise Threshold]",
|
|
//cmddetail:"descr":"Set minimal size of the message and noise threshold",
|
|
//cmddetail:"fn":"IR_Enable","file":"driver/drv_ir.cpp","requires":"",
|
|
//cmddetail:"examples":""}
|
|
CMD_RegisterCommand("IRParam",IR_Param, NULL);
|
|
}
|
|
}
|
|
if ((pin > 0) || (txpin > 0)) {
|
|
// both tx and rx need the interrupt
|
|
_timerConfigForReceive();
|
|
_timer_enable();
|
|
}
|
|
}
|
|
|
|
|
|
void dump(decode_results *results) {
|
|
// Dumps out the decode_results structure.
|
|
// Call this after IRrecv::decode()
|
|
ADDLOG_INFO(LOG_FEATURE_IR, resultToHumanReadableBasic(results).c_str());
|
|
|
|
#ifdef ENABLE_IRAC
|
|
if (hasACState(results->decode_type))
|
|
{
|
|
ADDLOG_INFO(LOG_FEATURE_IR, IRAcUtils::resultAcToString(results).c_str());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
// this polls the IR receive to see if there was any IR received
|
|
extern "C" void DRV_IR_RunFrame() {
|
|
// Debug-only check to see if the timer interrupt is running
|
|
if (ir_counter) {
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR counter: %u", ir_counter);
|
|
}
|
|
if (pIRsend) {
|
|
if (pIRsend->overflows) {
|
|
ADDLOG_DEBUG(LOG_FEATURE_IR, (char *)"##### IR send overflows %d", (int)pIRsend->overflows);
|
|
pIRsend->resetsendqueue();
|
|
}
|
|
else {
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR send count %d remains %d currentus %d", (int)pIRsend->timecounttotal, (int)pIRsend->timecount, (int)pIRsend->currentsendtime);
|
|
}
|
|
}
|
|
|
|
|
|
if (ourReceiver) {
|
|
decode_results results;
|
|
if (ourReceiver->decode(&results)) {
|
|
// TODO: find a better way?
|
|
String proto_name = typeToString(results.decode_type, results.repeat).c_str();
|
|
|
|
#if 0 // TODO: implement different masking
|
|
if (!(gIRProtocolEnable & (1 << (int)results.decode_type))) {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR decode ignore masked protocol %s (%d) - mask 0x%08X", proto_name.c_str(), (int)results.decode_type, gIRProtocolEnable);
|
|
}
|
|
#endif
|
|
|
|
//dump(&results);
|
|
// 'UNKNOWN' protocol is by default disabled in flags
|
|
// This is because I am getting a lot of 'UNKNOWN' spam with no IR signals in room
|
|
if (((results.decode_type != decode_type_t::UNKNOWN) ||
|
|
(results.decode_type == decode_type_t::UNKNOWN && CFG_HasFlag(OBK_FLAG_IR_ALLOW_UNKNOWN))) //&&
|
|
// only process if this protocol is enabled. all by default.
|
|
//(gIRProtocolEnable & (1 << (int)results.decode_type)
|
|
) {
|
|
String lastIrReceived = String((int)results.decode_type, 16) + "," + resultToHexidecimal(&results);
|
|
|
|
if (!hasACState(results.decode_type))
|
|
lastIrReceived += "," + String((int)results.bits);
|
|
else
|
|
ADDLOG_INFO(LOG_FEATURE_IR, "Recieved AC code:%s",proto_name.c_str());
|
|
|
|
char out[128];
|
|
|
|
int repeat = results.repeat?0:1; // not sure how to deal with this
|
|
|
|
if (results.decode_type == decode_type_t::UNKNOWN) {
|
|
//snprintf(out, sizeof(out), "IR_RAW 0x%lX %d", (unsigned long)results.decodedRawData, repeat);
|
|
snprintf(out, sizeof(out), "IR %s %s", "Unknown", lastIrReceived.c_str());
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)out);
|
|
}
|
|
else if (!hasACState(results.decode_type)) {
|
|
snprintf(out, sizeof(out), "IR %s %lX %lX %d", proto_name.c_str(), (long int)results.address, (long int)results.command, repeat);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)out);
|
|
// show new format too
|
|
snprintf(out, sizeof(out), "IR %s,%d,%s", proto_name.c_str(), (int)results.bits, resultToHexidecimal(&results).c_str());
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)out);
|
|
} else {
|
|
#ifdef ENABLE_IRAC
|
|
String description = IRAcUtils::resultAcToString(&results);
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IRAC %s", description.c_str());
|
|
#endif //ENABLE_IRAC
|
|
}
|
|
// if user wants us to publish every received IR data, do it now
|
|
if (CFG_HasFlag(OBK_FLAG_IR_PUBLISH_RECEIVED)) {
|
|
|
|
// another flag required?
|
|
int publishrepeats = 1;
|
|
|
|
if (publishrepeats || !repeat) {
|
|
//ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR MQTT publish %s", out);
|
|
|
|
uint32_t counter_in = ir_counter;
|
|
MQTT_PublishMain_StringString("ir", lastIrReceived.c_str(), 0);
|
|
uint32_t counter_dur = ((ir_counter - counter_in) * 50) / 1000;
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"IR MQTT publish %s took %dms", out, counter_dur);
|
|
}
|
|
else {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)out);
|
|
}
|
|
}
|
|
|
|
if (CFG_HasFlag(OBK_FLAG_IR_PUBLISH_RECEIVED_IN_JSON)) {
|
|
// {"IrReceived":{"Protocol":"RC_5","Bits":0x1,"Data":"0xC"}}
|
|
//
|
|
String _data=resultToHexidecimal(&results);
|
|
snprintf(out, sizeof(out), "{\"IrReceived\":{\"Protocol\":\"%s\",\"Bits\":%i,\"Data\":\"%s\"}}",
|
|
proto_name.c_str(), (int)results.bits, _data.c_str());
|
|
MQTT_PublishMain_StringString("RESULT", out, OBK_PUBLISH_FLAG_FORCE_REMOVE_GET);
|
|
}
|
|
|
|
if (results.decode_type != decode_type_t::UNKNOWN) {
|
|
snprintf(out, sizeof(out), "%X", results.command);
|
|
int tgType = 0;
|
|
switch (results.decode_type)
|
|
{
|
|
case decode_type_t::NEC:
|
|
tgType = CMD_EVENT_IR_NEC;
|
|
break;
|
|
case decode_type_t::SAMSUNG:
|
|
tgType = CMD_EVENT_IR_SAMSUNG;
|
|
break;
|
|
case decode_type_t::SHARP:
|
|
tgType = CMD_EVENT_IR_SHARP;
|
|
break;
|
|
case decode_type_t::RC5:
|
|
tgType = CMD_EVENT_IR_RC5;
|
|
break;
|
|
case decode_type_t::RC6:
|
|
tgType = CMD_EVENT_IR_RC6;
|
|
break;
|
|
case decode_type_t::SONY:
|
|
tgType = CMD_EVENT_IR_SONY;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// we should include repeat here?
|
|
// e.g. on/off button should not toggle on repeats, but up/down probably should eat them.
|
|
uint32_t counter_in = ir_counter;
|
|
EventHandlers_FireEvent2(tgType, results.address, results.command);
|
|
uint32_t counter_dur = ((ir_counter - counter_in) * 50) / 1000;
|
|
ADDLOG_DEBUG(LOG_FEATURE_IR, (char *)"IR fire event took %dms", counter_dur);
|
|
}
|
|
} else {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, "Recieved Unknown IR ");
|
|
}
|
|
/*
|
|
* !!!Important!!! Enable receiving of the next value,
|
|
* since receiving has stopped after the end of the current received data packet.
|
|
*/
|
|
ourReceiver->resume(); // Enable receiving of the next value
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef TEST_CPP
|
|
// routines to test C++
|
|
class cpptest2 {
|
|
public:
|
|
int initialised;
|
|
cpptest2() {
|
|
// remove else static class may kill us!!!ADDLOG_INFO(LOG_FEATURE_IR, "Log from Class constructor");
|
|
initialised = 42;
|
|
};
|
|
~cpptest2() {
|
|
initialised = 24;
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"Log from Class destructor");
|
|
}
|
|
|
|
void print() {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"Log from Class %d", initialised);
|
|
}
|
|
};
|
|
|
|
cpptest2 staticclass;
|
|
|
|
void cpptest() {
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"Log from CPP");
|
|
cpptest2 test;
|
|
test.print();
|
|
cpptest2 *test2 = new cpptest2();
|
|
test2->print();
|
|
ADDLOG_INFO(LOG_FEATURE_IR, (char *)"Log from static class (is it initialised?):");
|
|
staticclass.print();
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|