 'Program to sense if a slow oscillation is occurring in Battery/Solar indicator or if 1 day has passed
 'If not it switches power off for 15 secs, then power on and delays 15 secs before monitoring pins again
 'Add set pin high to save variables.
 'Written by John Drew VK5DJ
 'modified 23/5/26

'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config1 FOSC_INTOSC, WDTE_ON, PWRTE_OFF, MCLRE_ON, CP_OFF, CPD_OFF, BOREN_ON, CLKOUTEN_OFF, IESO_OFF, FCMEN_OFF
Config2 WRT_OFF, PLLEN_OFF, STVREN_ON, LVP_OFF

'**** End of Fuse Configurator Settings ****
'-------------------------------------------------------------------------------

Device = 16F1827
Declare Xtal = 4
Symbol Up = PORTB.0              'fire the pulse measure
Symbol SaveData = PORTB.1        'output to RPi to initiate save - currently unused due to save 3 hourly
Symbol ResetPi = PORTB.2         'to reset pin of pico pin 30  (low to reset)
Symbol Led = PORTA.2

Dim dTimeout As Dword            'counter in timer
Dim Timeout1Day As Dword         'fires reset each day
Dim SecsFlag As Bit              'fires when interrupt times out from dTimeout  (15 secs
Dim DayTimeOutFlag As Bit        'fires after 1 day 

Symbol IOCIF INTCON.0            'when at least one of the IOC pins changed state
Symbol T0IF INTCON.2             'timer overflow flag
Symbol EnableIOC INTCON.3        'enables IOC if 1
Symbol INTE INTCON.4             'enables external interrupts
Symbol TMR0IE INTCON.5           'timer 0 enable
Symbol PEIE INTCON.6             'enable interrupts on peripherals
Symbol GIE INTCON.7              'enable global interrupts
Symbol PS0 OPTION_REG.0          '111 = max divide if 0,1,2 set
Symbol PS1 OPTION_REG.1
Symbol PS2 OPTION_REG.2
Symbol PSA OPTION_REG.3          'prescaler set
Symbol EdgeSelect OPTION_REG.4   'edge select
Symbol T0CS OPTION_REG.5         'timer transition 1= Fosc/4 0= timer 0
Symbol RisingEdge OPTION_REG.6   '1=rising edge
Symbol RBPU OPTION_REG.7         'weak pullups
Symbol WATCH WDTCON              'watchdog
Symbol SetLeadingEdge IOCBP.0    'set interrupt on leading edge +ve going  on B0
Symbol FlagIOC IOCBF.0           'flag for IOC

WATCH =  %00100101               'WDT set for 256 seconds  (4 min 16secs)
OSCCON = %01101010               'set the internal oscilator to 4MHz
OPTION_REG.7 = 1                 'disable weak pullups
TRISB =%00000001                 'pin b.0 IOC set for +ve edge detect, B.1 (To PIC to save data), B2 reset
TRISA =%00100000                 'RA5 = mclr

'setup IOC on portb.0
  EnableIOC = 0       'if 0 then doesn't interrupt but sets flag on IOC
  SetLeadingEdge = 1  'sets edge on B.0
  EdgeSelect = 1      'edge select
  RisingEdge = 1      'rising edge

'Setup interrupts for timer:
  GIE=0         'turn off interrupts while initiating
  PSA=0         'assign prescaler to timer0
  PS0=1         'prescaler   111 gives max time 1/15 sec at 4MHz
  PS1=1
  PS2=1
  T0CS=0        'assign tmr0 clock to internal source (not PortA.4)
  TMR0=0        'clear tmr0 initially
  TMR0IE=1      'enable tmr0 overflow interrupt
  PEIE = 1      'enable interrupts on peripherals
  TMR0IE = 1 
  GIE=1         'enable global interrupts


On_Hardware_Interrupt Timeouts   'define the interrupt routine

GoTo Initialise                  'Jump over all the sub routines

Timeouts:                        'the interrupt routine runs at 15.3Hz
    Context Save
        If dTimeout>0 Then
            Dec dTimeout         '230 = 15 secs, 920 = 1 minute, 15 min = 13800, 60 min = 55200, 24 hrs = 1324800
        Else
            SecsFlag = 1         'timed out
        EndIf
        If Timeout1Day > 0 Then  'dword is max of 4294967295
            Dec Timeout1Day      '24 hrs = 1324800
            DayTimeOutFlag = 0
        Else
            DayTimeOutFlag = 1    'fires at zero after count to 1321920 represnting 86400 secs
        EndIf
        T0IF=0
    Context Restore

TurnoffSequence:
     Clrwdt
     ResetPi = 0                  'turn off RPI reset pin
     DelayMS 200                  'power off for 0.2 secs
     ResetPi = 1                  'release RST pin (3)
     Clrwdt
     DelayMS 20000                'wait for twenty secs before again watching the pins
     Clrwdt
     GoSub SetUpDayTimeout        'reset the day timer
     GoSub SetUp15secsTimeout     'reset 15 sec timer
Return

SetUpDayTimeout:
     GIE = 0
     Timeout1Day = 1324800        '24 hrs worth of 15.3Hz
     GIE = 1
     DayTimeOutFlag = 0
Return

SetUp15secsTimeout:
     dTimeout = 230              '15secs worth of 15.3Hz
     SecsFlag = 0
Return

Initialise:
   ResetPi = 1                    'reset pin on Pi released
   FlagIOC = 0                    'start at 0
   SaveData = 1                   'saves data if 0
   GIE = 0                        'turn off interrupts
   Clrwdt
   DelayMS 25000                  'let the PICO settle down for 15 secs   
   GoSub SetUpDayTimeout          'initiates switching process
   GoSub SetUp15secsTimeout       'time relay is off
   GIE = 1                        'get the timers working

Main:
  Clrwdt
  If FlagIOC = 1 Then              'it saw an edge so flip led
     PORTA.6 = ~ PORTA.6           'this interrupt not firing the interrupt vector 
     FlagIOC = 0                   'reset the flag
     GoSub SetUp15secsTimeout      'essentially stop the 15 sec timer
  EndIf
  
  If DayTimeOutFlag = 1 Then
     Clrwdt
     SaveData = 0               'saves on a zero
     DelayMS 1000               'delay 1s and vk5djbat.bas has a wait for no low after one save to stop multiple saves
     SaveData = 1
     GoSub TurnoffSequence
   EndIf  

  If SecsFlag = 1 Then         'sets output1 high etc if 15sec timeout (B.0 not oscillating )
     Clrwdt
     GoSub TurnoffSequence
  EndIf
    
  GoTo Main
