' Fuses PIC16LF88
@ DEVICE HS_OSC ; External OSC - 8MHz Resonator / Xtal
@ DEVICE PROTECT_OFF
@ DEVICE WDT_OFF
@ DEVICE PWRT_OFF
@ DEVICE MCLR_OFF
@ DEVICE BOD_OFF
@ DEVICE LVP_OFF
@ DEVICE CPD_OFF
@ DEVICE DEBUG_OFF
@ DEVICE CCPMX_OFF
@ DEVICE2 IESO_OFF  ;N
@ DEVICE2 FCMEN_OFF

'-------------------------------------------------------------------------------
' Registers   76543210
OPTION_REG = %10000000 'PORTB Pull-Ups disabled
ANSEL      = %00000000 'Disable analog inputs
ADCON0     = %00000000 'A/D Module is OFF
CMCON      = %00000111 'Comparator Module is OFF
INTCON     = %00000000 'All Interrupts are disabled
TRISA      = %00000000 'Set Input/Output
PORTA      = %00000100 'Ports High/Low
TRISB      = %00111110 'Set Input/Output
PORTB      = %00000000 'Ports High/Low

T2CON   = %00000100 'Timer2 = ON, prescaler = 1:1
CCP1CON = %00001100 'Select PWM Mode
CCPR1L  = 0         'percentage of Duty Cycle value from PR2
PR2     = 49        '@8MHz 1:1 58=34kHz, 55=36kHz, 52=38kHz, 49=40kHz, 47=42kHz
                    '58,55,52,50,49,47

'_______________________________________________________________________________
' Defines
DEFINE OSC 8 '@8MHz, PULSIN res is 5s

'_______________________________________________________________________________
' Variables
IRM_Out var TRISA.0 'IR RX Module VDD (VCC)
IRM_VDD var PORTA.1 'IR RX Module Out (OUT)
S_Sw    var PORTA.2 'Soft-Switch
C_Led   var PORTA.3 'Control Led
IR_Led  var PORTB.0 'IR Led (CCP1)
N_Key_E var PORTB.1
N_Key_B var PORTB.2
N_Key_A var PORTB.3
N_Key_C var PORTB.4
N_Key_D var PORTB.5
N_Keys  VAR PORTB   'alias for "PORTB"
Ctr_A   var word    'counter
Ctr_B   var word    'counter
Ctr_C   var byte    'counter
Max_Bit var byte    'number of possible bits c depending (max is 40)
L_Bit   var word(40)'incoming IR lo pulse (becomes the High Pulse when sent)
H_Bit   var word(40)'incoming IR hi pulse (becomes the Low Pulse when sent)
MemStrt var word    'Starting prg memory address for button F1
Mem_Loc var word    'Memory Location Pointer
Dy_Cycl var byte    'CCPR1L's Duty-Cycle value
Int_Pat var word    'Inter-Pattern time (pause-time between incoming patterns)
Pat_Cnt var word    'number of bits in IR original pattern

'_______________________________________________________________________________
' Subroutines

'_______________________________________________________________________________
' Program
INIT:
CCPR1L  = 0
Ctr_A   = 0
Ctr_B   = 0
Ctr_C   = 0
Max_Bit = 39
MemStrt = 0
Mem_Loc = 0
dy_cycl = 0
Int_Pat = 0
Pat_Cnt = 0

'________________________________
' Select Command (Button pressed)
if N_Key_a = 1 then memstrt = $900
if N_Key_b = 1 then memstrt = $CC0
if N_Key_c = 1 then memstrt = $A40
if N_Key_d = 1 then memstrt = $E00
if N_Key_e = 1 then memstrt = $B80

while (n_keys & %00111110) <> 0 'check if the button is still pressed
   if ctr_a > 9000 then        'after 0.3secs, Valid is selected
      memstrt = memstrt + $A0  'Add $A0 to first address
      goto READ_DATA:
   endif
   ctr_a = ctr_a + 1
wend

'__________________________________________________________
' READ data from memory and load to L_Bit & H_Bit variables
READ_DATA:
mem_loc = memstrt

for Ctr_A = 0 to Max_Bit
   readcode mem_loc, l_bit[ctr_a]
      mem_loc = mem_loc + 1
   readcode mem_loc, h_bit[ctr_a]
      mem_loc = mem_loc + 1
next Ctr_A

if l_bit[0] = H_bit[0] then CHECK_N_Key_PRESS: 'nothing in memory, skip SEND!
PR2     = l_bit[39] 'specific duty-cycle for this command
pat_cnt = h_bit[39] 'number of bits in this command

'____________________________________________________
'PWM mode (only PWM signal - set or reset Duty-Cycle)
SEND:
Dy_Cycl = PR2 / 3          'set duty-cycle to 30%
for Ctr_A = 0 to pat_cnt
  CCPR1L = Dy_Cycl         'activate duty-cylce
  pauseus (L_bit[ctr_a]*5) '
  CCPR1L = 0               'de-activate duty-cylce = no signal transmission
  pauseus (H_bit[ctr_a]*5)
next ctr_a

'________________________________________________
' Check if button is kept pressed during ~10 secs
' -> No, go to PRG_END:
' -> Yes, a btn is still pressed, go to LEARN:
CHECK_N_Key_PRESS:
ctr_a = 0
while (n_keys & %00111110) <> 0 'check if a button is still pressed
   if ctr_a > 65534 then       'make a 10 seconds loop
      IRM_VDD = 1              'power-ON IR Module
      IRM_Out = 1              'set port as Input
      pause 200                'allow IR Module to settle (VERY IMPORTANT!)
      mem_loc = memstrt
      Ctr_A   = 0
      int_pat = 0
      pat_cnt = 0
      read 16, PR2
      goto LEARN:
   endif
   ctr_a = ctr_a + 1
   pauseus 50                  'adjust the loop's time to match 10 seconds   
wend

'_______________________________
' Program END and PIC switch-OFF
PRG_END:
clear         'reset all
CCPR1L  = 0   'make sure the IR led is OFF!!!
IRM_Out = 0   'make IR-Module's pin an output
IRM_VDD = 0   'power-OFF IR Module
toggle C_Led  'make the led fade-out blinky
s_sw    = 0   'switch-off circuit
goto PRG_END: 'make it stop for ever

'___________________________________________
' Receive streaming IR pattern max (40 bits)
' First learned command is the "long Press" one
LEARN:
PULSIN IRM_Out, 0, l_Bit[0]        'get the first Low pulse
toggle C_Led                       'indicate the "waiting state" to user
if l_Bit[0] = 0 then LEARN:        'wait for the first pulse to start recording
C_Led = 1                          'led is ON, learn has started
RCTIME IRM_Out, 1, h_Bit[0]        'get first High pulse from IR Module
for Ctr_A = 1 to (Max_Bit - 1)
   rctime IRM_Out, 0, l_Bit[Ctr_A] 'get Low pulse (1 to 38) from IR Module
   rctime IRM_Out, 1, h_Bit[Ctr_A] 'get High pulse (1 to 38) from IR Module
next Ctr_A
RCTIME IRM_Out, 0, l_bit[Max_Bit]  'get last Low pulse from IR Module
RCTIME IRM_Out, 1, H_bit[Max_Bit]  'get last High pulse from IR Module
C_Led = 0
pause 1000                         'wait before continue

'_____________________________________________
' Find the longest H_Bit (= inter-pattern bit)
for Ctr_A = 0 to Max_Bit
	if H_Bit[Ctr_A] > int_pat then
      int_pat = H_Bit[Ctr_A] 'store the highest H_Bit value in Int_Pat
      Pat_Cnt = Ctr_A        'is the number of bits in the original pattern
   endif   
next Ctr_A

'replace all following bits with value "zero"
for ctr_a = (Pat_Cnt + 1) to Max_Bit
   l_bit[ctr_a] = 0
   H_bit[ctr_a] = 0
next ctr_a

'_______________________________
' Store data into program memory
STORE_DATA:
l_bit[39] = PR2     'set PR2 value
h_bit[39] = Pat_cnt 'number of bits in this command

' Cleanup at least 80 memory locations
erasecode mem_loc
erasecode mem_loc + 32
erasecode mem_loc + 64

' Write data to program memory
for Ctr_A = 0 to Max_Bit
   WRITEcode mem_loc, l_bit[Ctr_A]
      mem_loc = mem_loc + 1
   WRITEcode mem_loc, H_bit[Ctr_A]
      mem_loc = mem_loc + 1
next Ctr_A

goto PRG_END:
end