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

Ir repeat code detection #206

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
111 changes: 87 additions & 24 deletions Esp32_radio/Esp32_radio.ino
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
// 18-09-2018, ES: "uppreset" and "downpreset" for MP3 player.
// 04-10-2018, ES: Fixed compile error OLED 64x128 display.
// 09-10-2018, ES: Bug fix xSemaphoreTake.
// 30-12-2018, DK: Added support for NEC style IR repeat codes
//
//
// Define the version number, also used for webserver as Last-Modified header and to
Expand All @@ -155,10 +156,10 @@
// Define (just one) type of display. See documentation.
//#define BLUETFT // Works also for RED TFT 128x160
//#define OLED // 64x128 I2C OLED
//#define DUMMYTFT // Dummy display
#define DUMMYTFT // Dummy display
//#define LCD1602I2C // LCD 1602 display with I2C backpack
//#define ILI9341 // ILI9341 240*320
#define NEXTION // Nextion display. Uses UART 2 (pin 16 and 17)
//#define NEXTION // Nextion display. Uses UART 2 (pin 16 and 17)
//
#include <nvs.h>
#include <PubSubClient.h>
Expand Down Expand Up @@ -339,6 +340,8 @@ enum datamode_t { INIT = 1, HEADER = 2, DATA = 4, // State for datastream
STOPREQD = 128, STOPPED = 256
} ;

enum ir_state_t { IR_READY, IR_START, IR_NORMAL } ;

// Global variables
int DEBUG = 1 ; // Debug on/off
int numSsid ; // Number of available WiFi networks
Expand All @@ -357,7 +360,7 @@ SemaphoreHandle_t SPIsem = NULL ; // For exclusive SPI us
hw_timer_t* timer = NULL ; // For timer
char timetxt[9] ; // Converted timeinfo
char cmd[130] ; // Command from MQTT or Serial
uint8_t tmpbuff[6000] ; // Input buffer for mp3 or data stream
uint8_t tmpbuff[6000] ; // Input buffer for mp3 or data stream
QueueHandle_t dataqueue ; // Queue for mp3 datastream
QueueHandle_t spfqueue ; // Queue for special functions
qdata_struct outchunk ; // Data to queue
Expand Down Expand Up @@ -397,9 +400,11 @@ int chunkcount = 0 ; // Counter for chunked
String http_getcmd ; // Contents of last GET command
String http_rqfile ; // Requested file
bool http_reponse_flag = false ; // Response required
uint16_t ir_value = 0 ; // IR code
uint32_t ir_0 = 550 ; // Average duration of an IR short pulse
uint32_t ir_1 = 1650 ; // Average duration of an IR long pulse
static volatile uint16_t ir_value = 0 ; // IR code
static volatile bool ir_repeat_flag = false ; // this gets true when ir repeat code is received
static volatile uint8_t ir_state = IR_READY ; // for ir code interpretation
static volatile uint32_t ir_0 = 550 ; // Average duration of an IR short pulse
static volatile uint32_t ir_1 = 1650 ; // Average duration of an IR long pulse
struct tm timeinfo ; // Will be filled by NTP server
bool time_req = false ; // Set time requested
bool SD_okay = false ; // True if SD card in place and readable
Expand Down Expand Up @@ -1837,7 +1842,6 @@ void IRAM_ATTR timer100()
}
}


//**************************************************************************************************
// I S R _ I R *
//**************************************************************************************************
Expand All @@ -1858,19 +1862,33 @@ void IRAM_ATTR isr_IR()
t1 = micros() ; // Get current time
intval = t1 - t0 ; // Compute interval
t0 = t1 ; // Save for next compare
if ( ( intval > 300 ) && ( intval < 800 ) ) // Short pulse?

if ( ( intval > 8750 ) && ( intval < 9250 ) ) // 9 ms start burst?
{
ir_state = IR_START ;
}
else if ( ( intval > 4250 ) && ( intval < 4750 ) && ( ir_state == IR_START ) ) // 4,5 ms pause?
{
ir_state = IR_NORMAL ; // then normal code will follow
}
else if ( ( intval > 2000 ) && ( intval < 2500 ) && ( ir_state == IR_START ) ) // 2,25 ms pause?
{
ir_repeat_flag = true ; // this is a repeat code
ir_state = IR_READY ; // ready for next input
}
else if ( ( intval > 300 ) && ( intval < 800 ) && ( ir_state == IR_NORMAL) ) // Short pulse?
{
ir_locvalue = ir_locvalue << 1 ; // Shift in a "zero" bit
ir_loccount++ ; // Count number of received bits
ir_0 = ( ir_0 * 3 + intval ) / 4 ; // Compute average durartion of a short pulse
}
else if ( ( intval > 1400 ) && ( intval < 1900 ) ) // Long pulse?
else if ( ( intval > 1400 ) && ( intval < 1900 ) && ( ir_state == IR_NORMAL ) ) // Long pulse?
{
ir_locvalue = ( ir_locvalue << 1 ) + 1 ; // Shift in a "one" bit
ir_loccount++ ; // Count number of received bits
ir_1 = ( ir_1 * 3 + intval ) / 4 ; // Compute average durartion of a short pulse
}
else if ( ir_loccount == 65 ) // Value is correct after 65 level changes
else if ( ( ir_loccount == 65 ) && ( ir_state == IR_NORMAL ) ) // Value is correct after 65 level changes
{
while ( mask_in ) // Convert 32 bits to 16 bits
{
Expand All @@ -1882,11 +1900,13 @@ void IRAM_ATTR isr_IR()
mask_out <<= 1 ; // Shift output mask 1 position
}
ir_loccount = 0 ; // Ready for next input
ir_state = IR_READY ;
}
else
else // Illegal intervall length ?
{
ir_locvalue = 0 ; // Reset decoding
ir_loccount = 0 ;
ir_state = IR_READY ;
}
}

Expand Down Expand Up @@ -2343,7 +2363,7 @@ bool connectwifi()
}
tftlog ( pfs ) ; // Show IP
delay ( 3000 ) ; // Allow user to read this
tftlog ( "\f" ) ; // Select new page if NEXTION
tftlog ( "\f" ) ; // Select new page if NEXTION
return ( localAP == false ) ; // Return result of connection
}

Expand Down Expand Up @@ -2402,7 +2422,7 @@ bool do_nextion_update ( uint32_t clength )
}
k = otaclient.read ( tmpbuff, k ) ; // Read a number of bytes from the stream
dbgprint ( "TFT file, read %d bytes", k ) ;
nxtserial->write ( tmpbuff, k ) ;
nxtserial->write ( tmpbuff, k ) ;
while ( !nxtserial->available() ) // Any input seen?
{
delay ( 20 ) ;
Expand Down Expand Up @@ -2433,7 +2453,7 @@ bool do_nextion_update ( uint32_t clength )
bool do_software_update ( uint32_t clength )
{
bool res = false ; // Update result

if ( Update.begin ( clength ) ) // Update possible?
{
dbgprint ( "Begin OTA update, length is %d",
Expand Down Expand Up @@ -2485,7 +2505,7 @@ void update_software ( const char* lstmodkey, const char* updatehost, const char
String line ; // Input header line
String lstmod = "" ; // Last modified timestamp in NVS
String newlstmod ; // Last modified from host

updatereq = false ; // Clear update flag
otastart() ; // Show something on screen
stop_mp3client () ; // Stop input stream
Expand Down Expand Up @@ -2523,7 +2543,7 @@ void update_software ( const char* lstmodkey, const char* updatehost, const char
break ; // Yes, get the OTA started
}
// Check if the HTTP Response is 200. Any other response is an error.
if ( line.startsWith ( "HTTP/1.1" ) ) //
if ( line.startsWith ( "HTTP/1.1" ) ) //
{
if ( line.indexOf ( " 200 " ) < 0 )
{
Expand All @@ -2542,7 +2562,7 @@ void update_software ( const char* lstmodkey, const char* updatehost, const char
{
dbgprint ( "No new version available" ) ; // No, show reason
otaclient.flush() ;
return ;
return ;
}
if ( clength > 0 )
{
Expand Down Expand Up @@ -2815,7 +2835,7 @@ String readprefs ( bool output )
String ( "/*******" ) ;
}
cmd = String ( "" ) ; // Do not analyze this

}
else if ( strstr ( key, "mqttpasswd" ) ) // Is it a MQTT password?
{
Expand Down Expand Up @@ -3007,7 +3027,7 @@ void scanserial2()
dbgprint ( "NEXTION command seen %02X %s",
cmd[0], cmd + 1 ) ;
if ( cmd[0] == 0x70 ) // Button pressed?
{
{
reply = analyzeCmd ( cmd + 1 ) ; // Analyze command and handle it
dbgprint ( reply ) ; // Result for debugging
}
Expand Down Expand Up @@ -3113,22 +3133,63 @@ void scanIR()
char mykey[20] ; // For numerated key
String val ; // Contents of preference entry
const char* reply ; // Result of analyzeCmd
static uint16_t lastCode ; // Store last value for repeat code interpretation
static int16_t repeatDelay ; // Stores the delay until the command gets repeated
static uint32_t nextRepeat ; // Stores the time for next repeat in millis

if ( ir_repeat_flag && repeatDelay ) // It doesn't make sense to repeat all types of codes. Actually only volume+/-. Maybe also preset+/-, but then a longer pause would be needed.
{
if ( millis() > nextRepeat )
{
dbgprint ( " now is time for next repeat (%d)", millis() );
dbgprint ( " last code was:%04X", lastCode );
ir_value = lastCode ; // We inject the last code, which will lead to a new setting of nextRepeat later
}

ir_repeat_flag = false; // Reset ir_repeat_flag
}

if ( ir_value ) // Any input?
{
sprintf ( mykey, "ir_%04X", ir_value ) ; // Form key in preferences
if ( nvssearch ( mykey ) )
{
val = nvsgetstr ( mykey ) ; // Get the contents
dbgprint ( "IR code %04X received. Will execute %s",
ir_value, val.c_str() ) ;
val = nvsgetstr ( mykey ) ; // Get the content

if ( val.indexOf('/') != -1 ) // Does the command contain a '/' ?
{
if ( ( val.indexOf('#') == -1 ) || ( val.indexOf('#') > val.indexOf('/') ) ) // '/' is not in the comment section
{
repeatDelay = val.substring( val.indexOf('/') + 1 ).toInt() ; // '/' delimits the repeat delay (in ms) if any
if ( repeatDelay < 0 )
{
dbgprint ( "Error in IR command. Repeat delay can't be negative, set to zero: %s", val.c_str() );
repeatDelay = 0 ;
}
val = val.substring( 0, val.indexOf('/') ) ; // Now that we know the repeat delay we trim it from the string
}
else
{
repeatDelay = 0 ;
}
}
else
{
repeatDelay = 0 ; // This command does not get repeated
}

dbgprint ( "IR code %04X received. Will execute %s and repeat in %d ms if button is held longer.",
ir_value, val.c_str(), repeatDelay ) ;
reply = analyzeCmd ( val.c_str() ) ; // Analyze command and handle it
dbgprint ( reply ) ; // Result for debugging
nextRepeat = millis() + repeatDelay ;
lastCode = ir_value ; // Store this value for repeat code interpretation
}
else
{
dbgprint ( "IR code %04X received, but not found in preferences! Timing %d/%d",
ir_value, ir_0, ir_1 ) ;
repeatDelay = 0 ; // Deactivate repeat for unknown code
}
ir_value = 0 ; // Reset IR code received
}
Expand Down Expand Up @@ -3452,11 +3513,13 @@ void setup()
#if defined ( NEXTION )
dbgprint ( dtyp, "NEXTION" ) ;
#endif

maintask = xTaskGetCurrentTaskHandle() ; // My taskhandle
SPIsem = xSemaphoreCreateMutex(); ; // Semaphore for SPI bus
pi = esp_partition_find ( ESP_PARTITION_TYPE_DATA, // Get partition iterator for
ESP_PARTITION_SUBTYPE_ANY, // the NVS partition
partname ) ;

if ( pi )
{
nvs = esp_partition_get ( pi ) ; // Get partition struct
Expand Down Expand Up @@ -3497,6 +3560,7 @@ void setup()
}
dbgprint ( "GPIO%d is %s", pinnr, p ) ;
}

readprogbuttons() ; // Program the free input pins
SPI.begin ( ini_block.spi_sck_pin, // Init VSPI bus with default or modified pins
ini_block.spi_miso_pin,
Expand Down Expand Up @@ -4528,7 +4592,7 @@ void loop()
if ( updatereq ) // Software update requested?
{
if ( displaytype == T_NEXTION ) // NEXTION in use?
{
{
update_software ( "lstmodn", // Yes, update NEXTION image from remote image
UPDATEHOST, TFTFILE ) ;
}
Expand Down Expand Up @@ -5682,4 +5746,3 @@ void spftask ( void * parameter )
}
//vTaskDelete ( NULL ) ; // Will never arrive here
}