SWR_IRcpp_IRh.ino


/*
 * IR.cpp
 *
 *  Created on: 11.08.2017
 *      Author: Wolle
 *  Updated on: 04.07.2022
 *----------------------------------------------------------------
 *  Changed for use with datalink: Kurt Nielsen kurtn.nypost@hotmail.dk
 */
#include "IR.h"

// global var
DRAM_ATTR int8_t ir_resp; // set from isr

IR::IR(uint8_t IR_PIN){
    ir_pin=IR_PIN;
    ir_result=0;
    ir_resp=(-1);
    t0=0;
    //log_i("init");
}

IR::~IR(){

}

void IR::begin(){
    if(ir_pin >= 0){
        pinMode(ir_pin, INPUT);
        attachInterrupt(ir_pin, isr_IR, CHANGE); // Interrupts will be handle by isr_IR
    }
}
void IRAM_ATTR IR::setIRresult(uint8_t result){
    ir_resp=result;
}
void IR::loop(){
// transform raw data from IR to ir_result

    if(f_entry == false){t0 = millis(); f_entry = true;}
    if((t0 + 49 > millis()) && (t0 <= millis())) return;   // wait 50ms (not if millis overflow)
    f_entry = false;
    // entry every 50ms in this routine
    if(downcount) downcount--;                             // 1.5 sec countdown
    else{
        if(f_send){
            if(ir_res) ir_res(ir_num);
            //log_i("ir_res %i", ir_num);
            idx = 0;
            ir_num = 0;
            f_send  =false;
        }
    }

    if(tmp_resp == ir_resp) return;   // new value from IR?
    tmp_resp = ir_resp;
    ir_resp = (-1);                     // yes, set ir_resp to default

    if(tmp_resp >= 10){               // it is a function key in ir_result
        switch(tmp_resp){
        case 10: ir_resultstr[0] = 'k'; break; //OK
        case 11: ir_resultstr[0] = 'u'; break; //up
        case 12: ir_resultstr[0] = 'd'; break; //down
        case 13: ir_resultstr[0] = 'r'; break; //up volume
        case 14: ir_resultstr[0] = 'l'; break; //down volume
        case 15: ir_resultstr[0] = '#'; break; //mute
        case 16: ir_resultstr[0] = '*'; break; //toogle RADIO / SLEEP
        }
        ir_resultstr[1] = 0;
        if(ir_key) ir_key(ir_resultstr);
        //log_i("ir_key %s", ir_resultstr);
        downcount = 0;
        ir_num = 0;
        f_send=false;
        tmp_resp = -1;
        return;
    }
    if(tmp_resp > (-1)){   // it is a number key in ir_result, can be 0...9
        if(idx < 3){
            ir_resultstr[idx] = tmp_resp + 48;  // convert in ASCII
            idx++;
            ir_resultstr[idx] = 0;              // terminate
            if(ir_number) ir_number(ir_resultstr);
            //log_i("ir_number %s", ir_resultstr);
            ir_num = ir_num * 10 + tmp_resp;
            f_send = true;
            downcount = 30;                     // await nex tmp_resp
            tmp_resp = -1;
        }
    }
}

//**************************************************************************************************
//                                          I S R _ I R                                            *
//**************************************************************************************************
// Interrupts received from VS1838B on every change of the signal.                                 *
// Intervals are 640 or 1640 microseconds for data.  syncpulses are 3400 micros or longer.         *
// Input is complete after 65 level changes.                                                       *
// Only the last 32 level changes are significant.                                                 *
//**************************************************************************************************
void IRAM_ATTR isr_IR()
{
    extern IR ir;

    int8_t          ir_resp=(-1);
    uint16_t        address=0;                 // The first 4 bytes of IR code
    uint16_t        command=0;                 // The last 4 bytes of IR code
    uint32_t        t1, intval;                // Current time and interval since last change

    static uint8_t  levelcounter=0;             // Counts the level changes
    static uint8_t  pulsecounter=0;             // Counts the pulse
    static uint32_t t0=0;                       // To get the interval
    static uint32_t ir_value=0;                 // IR code
    static boolean  ir_begin=false;        // set if HIGH/LOW change
    static boolean  last = 1;
    static int i = 0;     

    t1=micros();                                // Get current time
    intval=t1 - t0;                             // Compute interval
    t0=t1;                                      // Save for next compare

    if(intval > 80000)//&&(intval <= 5500))    // begin sequence of code?
    {
        pulsecounter=0;                         // Reset counter
        ir_value=0;
    last = 1;
        levelcounter=0;
        ir_begin=true;
        return;
    }

    /*if(ir_begin==false) return;
    levelcounter++;
    if(levelcounter%2==1)return;*/                // only falling edge can pass

    if ((pulsecounter == 8) && ir_begin)
    {
        ir_begin=false;
        ir_resp=(-1);
    pulsecounter = 0;
    //Serial.println(ir_value);
        address=255;//(ir_value&0xFFFF0000)>>16;
        command=ir_value;(ir_value&0x0000FFFF);
    ir_value = 0;
        if(address==0x00FF){
            switch(command){
                case 126: ir_resp=0;  break; //ZERO 
                case 124: ir_resp=1;  break; //ONE  
                case 122: ir_resp=2;  break; //TWO  
                case 120: ir_resp=3;  break; //THREE
                case 118: ir_resp=4;  break; //FOUR 
                case 116 : ir_resp=5;  break; //FIVE 
                case 114: ir_resp=6;  break; //SIX  
                case 112 : ir_resp=7;  break; //SEVEN
                case 110: ir_resp=8;  break; //EIGHT
                case 108: ir_resp=9;  break; //NINE 
                case 84:  ir_resp=10; break; //OK
                case 86:  ir_resp=10; break; //OK   
                case 106: ir_resp=11; break; //UP   
                case 102: ir_resp=11; break; //UP
                case 12: ir_resp=12; break; //DOWN 
                case 76: ir_resp=12; break; //DOWN
                case 44: ir_resp=13; break; //RIGHT
                case 78: ir_resp=13; break; //RIGHT
                case 46: ir_resp=14; break; //LEFT
                    case 80: ir_resp=14; break; //LEFT
                case 74: ir_resp=15; break; //HASH 
                case 50: ir_resp=15; break; //HASH
                case 52: ir_resp=16; break; //STAR
                default: ir_resp=(-1);
            }


            if(ir_resp>(-1))ir.setIRresult(ir_resp);
        }
    }
    if (intval < 20000)
    {
    if((intval > 2600) && (intval < 3600))
    {
    if (last == 0)
      {  
          ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
          pulsecounter = pulsecounter + 1;        // Count number of received bits
          last = 1;
        }
    else
      {
      ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 1;
      last = 0;
      }
    }
    if ((intval > 5700) && (intval < 6700))  
    {
    if (last == 0)
      {
          ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
      ir_value=(ir_value << 1) + 1;
          pulsecounter = pulsecounter + 2;                // Count number of received bits
          last = 1;
    }
    else
      {
      ir_value=(ir_value << 1) + 0;
      ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 2;
      last = 0;
      }
    }
    if ((intval > 8800) && (intval < 9800))
    {
    if (last == 0)  
      {
      for (i = 1; i < 4; i++)
        ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
          pulsecounter = pulsecounter + 3;                // Count number of received bits
      last = 1;
        }
    else
    {
    for (i = 1; i < 4; i++)
        ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 3;
      last = 0;
      }
    }
    if ((intval > 11900) && (intval < 12900))
    {  
    if (last == 0)  
      {
      for (i = 1; i < 5; i++)
            ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
        pulsecounter = pulsecounter + 4;                // Count number of received bits
    last = 1;
    }
    else
    {
    for (i = 1; i < 5; i++)
        ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 4;
      last = 0;
      }
    }
    if ((intval > 15000) && (intval < 16000))
    {  
    if (last == 0)  
      {
      for (i = 1; i < 6; i++)
            ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
          pulsecounter = pulsecounter + 5;                // Count number of received bits
      last = 1;
        }
    else
    {
    for (i = 1; i < 6; i++)
        ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 5;
      last = 0;
      }
    }
    if ((intval > 18100) && (intval < 19100))
    {  
    if (last == 0)  
      {
      for (i = 1; i < 7; i++)
        ir_value=(ir_value << 1) + 1;               // Shift in a "one" bit
        pulsecounter = pulsecounter + 6;                // Count number of received bits
    last = 1;
    }
    else
    {
    for (i = 1; i < 7; i++)
        ir_value=(ir_value << 1) + 0;
      pulsecounter = pulsecounter + 6;
      last = 0;
      }
        }
    }
 
    //Serial.println(pulsecounter);
}


/*
 * IR.h
 *
 *  Created on: 11.08.2017
 *      Author: Wolle
 */

#ifndef IR_H_
#define IR_H_

#include "Arduino.h"
#include <vector>
extern __attribute__((weak)) void ir_res(uint32_t res);
extern __attribute__((weak)) void ir_number(const char*);
extern __attribute__((weak)) void ir_key(const char*);

// prototypes
void IRAM_ATTR isr_IR();

struct ir_btn{
    uint8_t val;
    char    ch;
};
typedef ir_btn irBtn_t;

class IR {

    private:
        boolean  f_entry=false;  // entryflag
        boolean  f_send=false;   // entryflag
        uint32_t t0;
        uint32_t ir_num=0;
        int8_t   ir_pin;
        uint8_t  ir_result;
        uint8_t  idx=0;
        char     ir_resultstr[10];
        uint16_t downcount=0;
        int8_t   tmp_resp =(-1);

    protected:
        irBtn_t ir_buttons[20];
    public:
        IR(uint8_t IR_PIN);
        ~IR();
        void begin();
        void defineButtons(irBtn_t* b);
        void setIRresult(uint8_t result);
        void loop();


};

#endif /* IR_H_ */