# Christian Fiot 2020
# boot
# 8b from machine import SD
# 8b import os
VERSION = "2.3.10"
BUILD_DATE = "11/18/21"
CHANGELOG = "More logging and catches"


import machine
wdt = machine.WDT(timeout=60*1000) # 60sec to execute boot.py



# 8b acquire config variables
import configurator

wdt.init(30*60*1000) # 30min  2.2.1b
#configurator.runFlashSetup() # 2.2.1b
deviceSettings = configurator.FLASH_CONFIG # 2.2.2b
print("deviceSettings:") # 2.3.10
print(deviceSettings) # 2.3.10

Skyhook = False  # 2.2.2b   skyhook requires FiPy instead of Lopy
if Skyhook: deviceSettings['pycom_socket_version'] = 1  # 2.2.2b

wdt.init(60*1000) # 2.2.1b
''' 2.2.2b
FLASH_CONFIG = configurator.readFlashConfig()
if FLASH_CONFIG == {} or FLASH_CONFIG == None: # It should never be
    SocketVersion = 2  #  2= default  VB,   3 = PyTrack
    print('Err, preset SocketVersion = 2 !!!')  # 2.2.1b
else:
    SocketVersion = FLASH_CONFIG['pycom_socket_version']
    print('pycom_socket_version:' + str(SocketVersion))
'''
if 'pycom_socket_version' in deviceSettings:
    SocketVersion = deviceSettings['pycom_socket_version']   # 2.2.2b    if Skyhook: SocketVersion = 1 # 2.2.2b
print('Skyhook:' + str(Skyhook) + '  pycom_socket_version:' + str(SocketVersion)) # 2.2.2b


# 8b
resetCode = machine.reset_cause()
resetMessage = ''
if resetCode == machine.PWRON_RESET: resetMessage = 'Power On Reset' # 0
if resetCode == machine.HARD_RESET:  resetMessage = 'Hard Reset'  # 1
if resetCode == machine.WDT_RESET: resetMessage = 'Watchdog Reset' # 2
if resetCode == machine.DEEPSLEEP_RESET:  resetMessage = 'Wakeup from Deepsleep' # 3
if resetCode == machine.SOFT_RESET: resetMessage = 'Software Reset'  # 4 Reset by e.g. sys.init()
if resetCode == machine.BROWN_OUT_RESET:  resetMessage = 'Brown Out reset - low voltage' # 5 Reset caused by low voltage
print("Reset cause:" + resetMessage)  # 8b



# 8b
from machine import SD
import os

# Display SD card and Flash Directory
sdAvailable = False # 2.2.9b
sdCardFreeSpace = 0
try:
    sd = SD()  # 32GB  max   FAT32
    os.mount(sd, '/sd') # either  /sd   or   /Flash

    print("")
    print("SD card free space:" + str(os.getfree("/sd")) + "KB")
    sdCardFreeSpace = str(os.getfree("/sd"))
    # try some standard file operations
    f = open('/sd/test.txt', 'w')
    f.write('Testing SD card write operations')
    f.close()
    f = open('/sd/test.txt', 'r')
    print(f.read())
    f.close()
    print(os.listdir('/sd'))
    sdAvailable = True # 2.2.2b

except:
    print("")
    print("SD card not found")

finally:
    print("")
    print("Flash free space:" + str(os.getfree("/flash")) + "KB")
    print(os.listdir('/flash'))
    print("")


# 2.2.18
from machine import I2C
I2C1 = I2C(0, mode=I2C.MASTER, pins=('P22', 'P21'))  # I2C1.scan()

# 2.2.18 to allow trap.py interface with IamAlive() ...
from sensors import PCA9536
DIO = PCA9536(0x41, 0x00, i2c=I2C1, traceDebug=True, sdAccess=sdAvailable)
DIOAvailable = DIO.begin() # 2.2.18   WS power ON
import time
time.sleep(3)

# 2.2.22b sample catcher
from sensors import PCA9955B
LEDIO = PCA9955B(i2c=I2C1) # 2.2.18 traceDebug=True)
catcherAvailable = False
if 'catcher_enabled' in deviceSettings:
    if deviceSettings['catcher_enabled']: # 2.2.18
        catcherAvailable = LEDIO.begin() # execute first to reconfigure I2C mapping to prevent conflict


# 2.2.18 disable weather shield I2C until ready to be used
from sensors import PI4M
wsCommSw = PI4M(0x70, i2c=I2C1, traceDebug=True, sdAccess=sdAvailable) # 2.2.0b  weather shield I2C enable switch
wsoAvailable = False
wsoAvailable = wsCommSw.begin() # should return  'PI4M read: 0x0000'  I2C switch OFF
if wsoAvailable:
    wsCommSw.channel(0x00) # disable weather shield I2C

# 2.2.18
from sensors import MAX17048
battV = 0
fuelGauge = MAX17048(0x36, i2c=I2C1, traceDebug=False, sdAccess=sdAvailable) # 2.2.1b
fuelgaugeAvailable = False
fuelgaugeAvailable = fuelGauge.begin()
if fuelgaugeAvailable == True:
    battV = fuelGauge.read_vcell()
    print("Fuel gauge battV: " + str(battV))


boolAlive = True # 2.2.18

def IamAlive(): # 2.2.18   # Reset WD and signal DogRelay board
    global boolAlive
    if SocketVersion == 3 or SocketVersion == 21:
        if DIOAvailable:
            if boolAlive: # raise b2
                DIO.setLive()
                boolAlive = False
            else:
                DIO.clrLive()
                boolAlive = True
    wdt.feed()
IamAlive() # 2.2.20


def disableAlive(status=0):  # 2.2.20   disable DogRelay for 1hour
    if SocketVersion == 3 or SocketVersion == 21:
        if DIOAvailable:
            # 2.2.21   DIO.setDisable()
            if status == 0: # 2.2.21
                DIO.setDogRate(0) #  0= 14sec,  1= 0.5sec
            else:
                DIO.setDogRate(1)
disableAlive(1) # 2.2.21  enable 2min DogRelay cycle


# 2.2.20
# print(globals())
# globals()["customReset"]()
# global customReset
#
def customReset():  # 2.2.20  disable weathershield I2C prior reseting the fipy
    print("customReset")
    if wsoAvailable == True:
        wsCommSw.channel(0x00)
    machine.reset()


# 2.2.20
def fnWDog(switch):
    if switch == 1:
        IamAlive()
    if switch == 2:
        disableAlive()
    if switch == 3:
        customReset()



# 7b Battery management
from sensors import *
from machine import Pin

''' 2.2.22b
# 2.2.17b sample catcher
LEDIO = PCA9955B(i2c=I2C1) # 2.2.18 traceDebug=True)
catcherAvailable = False
if deviceSettings['catcher_enabled']: # 2.2.18
    catcherAvailable = LEDIO.begin() # execute first to reconfigure I2C mapping to prevent conflict
'''

EEP7 = M24C02(0x057, i2c=I2C1) # , traceDebug=True)
EEP6 = M24C02(0x056, i2c=I2C1)
EEP5 = M24C02(0x055, i2c=I2C1)
EEP4 = M24C02(0x054, i2c=I2C1)
EEP3 = M24C02(0x053, i2c=I2C1)
EEP2 = M24C02(0x052, i2c=I2C1)
EEP1 = M24C02(0x051, i2c=I2C1)
EEP0 = M24C02(0x050, i2c=I2C1)

# 2.2.9b
# 2.2.18 DIO = PCA9536(0x42, 0x00, traceDebug=True, sdAccess = sdAvailable)  # 2.09  All line are output
# 2.2.18 fuelGauge = MAX17048(0x36, i2c=I2C1, traceDebug=False, sdAccess = sdAvailable) # 2.2.1b
# 2.2.18 wsCommSw = PI4M(0x70, i2c=I2C1, traceDebug=True, sdAccess=sdAvailable) # 2.2.0b  weather shield I2C enable switch


# 7b
if SocketVersion == 2 or SocketVersion == 20 or SocketVersion == 21: # 2.2.12b
    HM3300Sdtby = Pin('P10', mode=Pin.OUT)
    HM3300Sdtby.hold(False)
    HM3300Sdtby.value(0)   # Put dust sensor to sleep
    HM3300Sdtby.hold(True)

battVToolow = False
ads1115Available = False

# 2.2.1b
# 2.2.18 fuelgaugeAvailable = False
# 2.2.18 fuelgaugeAvailable = fuelGauge.begin()
if fuelgaugeAvailable == True:
    # 2.2.18 battV = fuelGauge.read_vcell()
    # 2.2.18 print("Fuel gauge battV: " + str(battV))
    if 1 < battV <= 3.2:
        battVToolow = True
        print("Battery too low")
else:
    if Skyhook: # 2.2.2b
        print( "Skyhook, no batt attached")
        battV = deviceSettings['low_battery_voltage_threshold']
    else:
        try: # 2.2.13b
            ads1115 = ADS1115(0x48, i2c=I2C1)   #  !!! same adr as IVCh4
            ads1115Available = ads1115.begin()
            if ads1115Available == True:
                if SocketVersion  == 2 or SocketVersion == 20: # 2.2.12b
                    battV = ads1115.get_voltage(ads1115.read(channel=1, gain=PGA_2_048V))
                # else:
                #    battV = ads1115.get_voltage(ads1115.read(channel=2, gain=PGA_2_048V))
                if SocketVersion  == 1: # 2.2.5b
                    battV = ads1115.get_voltage(ads1115.read(channel=2, gain=PGA_2_048V))

                if SocketVersion == 3:  battV = 0  # 2.3.3b  fuel gauge should have been detected, trigger error

                battV = battV * 220 / 100
                print("ADS battV: " + str(battV))
                if 1 < battV <= 3.2:
                    battVToolow = True
                    print("Battery too low")

            else:
                # 2.2.16b Fuelgauge should have been detected
                if SocketVersion == 3 or SocketVersion == 21: # Pytrack or Pycom Socket VC2
                    file_errLog(0, "Errboot Fuelgauge - Not detected", sdAvailable)
                    battVToolow = True # Stop program execution
                    # - abscence of 3VO will freeze the Fipy as soon as the I2Cswitch is ON and I2C is scanned
                else:
                    # 2.2.13b battVToolow = True2.2.16b   Pytrack or Pycom Socket VC2
                    # 2.2.13b print( "Unable to read battV")
                    file_errLog(0, "Errboot VBatt ADS1115 - Not detected", sdAvailable) # 2.2.13b
                    battV = 5

        except Exception as e: # 2.2.13b
            file_errLog(0, "Errboot VBatt ADS1115 - " + str(e), sdAvailable)
            battV = 5


if battVToolow:
    print( "System goes to sleep for 1h in 10sec (Ctrl C to bypass) !!!")

    # DO NOT REMOVE !!!
    for x in range(10):  # allow 10sec to reset or reflash
        time.sleep(1)
        print('.', end='')

    # 2.2.18
    if wsoAvailable:
        wsCommSw.channel(0x00) # disable weather shield I2C


    if SocketVersion  == 3:
        from pytrack import *
        py = Pytrack()
        if DIOAvailable: # 2.2.18  if DIO.begin():  # 2.2.1b  turn off power to weather shield sensors
            DIO.writePort(0x00) # 2.2.21 disbale DogRelay 1H     1YM5 high level enable     P0(Power shield)=0   P1(PM)=0
            time.sleep(1)
        # FOR DEBUG ONLY,  disable the 4 lines bellow when developping the code
        # 9b py.gps_standby(enabled=True)
        # 9b py.sensor_power(enabled=False)  # Turn off power to GPS and sensors (Pyport pin#1)
        # 9b py.sd_power(enabled=False) # Turn off power to SD card (10 pins header pin#2)
        py.setup_sleep(3600) # 2.2.21 1h   *4)  # machine.deepsleep(3600*1000)
        py.go_to_sleep() # 9b gps=False)

    if SocketVersion == 2 or SocketVersion == 20: # 2.2.5b
        # 2.2.1b from sensors import *
        # 2.2.18 DIO = PCA9536(0x41, 0x00)
        if DIOAvailable: # 2.2.18  if DIO.begin():  # Turn OFF grove ports J4 J8
            DIO.writePort(0x05)
            time.sleep(.2)
            DIO.writePort(0x0FF)
        machine.deepsleep(3600*1000) # 2.2.21 1H   3600*4*1000)

    if SocketVersion == 21: # 2.2.12b
        # 2.2.18  DIO = PCA9536(0x41, 0x00)
        if DIOAvailable:  # 2.2.18   if DIO.begin():
            DIO.writePort(0x00) # 2.2.21  Disable DogRelay for 1H
        machine.deepsleep(3600*1000) # 2.2.21  1h     3600*4*1000)

    if SocketVersion == 1:
        machine.deepsleep(3600*1000) # 2.2.21  1h   3600*4*1000)
