# STELLA-1 central_logic test code
# Science and Technology Education for Land/ Life Assessment
# Paul Mirel 2022-08-19

# import system libraries
import gc #garbage collection, RAM management
gc.collect()
print("start memory free {} kB".format( gc.mem_free()/1000 ))
last_alloc = gc.mem_alloc()/1000.0
import os
import sys
import board
import time
import busio
import digitalio
import terminalio
import storage

# import display libraries
import displayio
import vectorio # for shapes
import adafruit_ili9341 # TFT (thin film transistor) display
from adafruit_display_text.bitmap_label import Label
from adafruit_display_text import label
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_stmpe610 import Adafruit_STMPE610_SPI # touch screen reader

# import device specific libraries
import adafruit_mlx90614    # thermal infrared
import adafruit_mcp9808     # air temperature
import adafruit_as726x      # visible spectrum
import adafruit_sdcard      # SD card
import adafruit_pcf8523     # real time clock
#from adafruit_bme280 import basic as adafruit_bme280 # weather

# set constants
SCREENSIZE_X = const(320)
SCREENSIZE_Y = const(240)
DATA_FILE = "/sd/data.txt"
VIS_BANDS = ( 450, 500, 550, 570, 600, 650 ) # from amd as7262 datasheet
VIS_BAND_PREFIXES = ( "V", "B",  "G", "Y", "O", "R" )
NIR_BANDS = ( 610, 680, 730, 760, 810, 860 ) # from amd as7263 datasheet
ON = const(0)  #indicator is active low.
OFF = const(1)

def main():
    desired_sample_interval_s = 1.0 # takes ~0.8 to read and record data
    # initialize display screen and touch screen and pushbutton
    spi_bus = initialize_spi()
    i2c_bus = initialize_i2c()
    uart_bus = initialize_uart()
    indicator = initialize_indicator()
    VIS_sensor = initialize_VIS_sensor( i2c_bus )
    NIR_sensor = initialize_NIR_sensor( uart_bus )
    aux_lamp = initialize_auxilliary_lamp()
    # initialize display
    display = initialize_display( spi_bus )
    display_group_table = initialize_display_group( display )
    text_group = create_table_screen( display, display_group_table )
    # initialize inputs
    touch_screen = initialize_touch_screen( spi_bus )
    pushbutton = initialize_pushbutton()

    number_of_record_pause_states = 2 # record_pause_state 0 means the system is recording, 1 means the system is paused
    number_of_source_lamps_states = 2
    number_of_display_states = 1

    record_pause_state = 0
    last_record_pause_state = 0
    screen_record_pause_press_state = True
    screen_record_pause_last_press_state = False
    pushbutton_press_state = False
    pushbutton_last_press_state = False
    press = [0,0,0]

    source_lamps_state = 0
    last_source_lamps_state = 0
    source_lamp_press_state = False
    source_lamps_last_press_state = False

    display_state = 0
    last_display_state = 3 #startup

    show_record_pause_icon( display_group_table, record_pause_state, 0, 0)

    batch_start_s = time.monotonic()
    startup = True
    inputs = check_inputs( pushbutton, touch_screen, pushbutton_last_press_state, screen_record_pause_last_press_state, source_lamps_last_press_state )

    while True:
        gc.collect()
        report_memory( "begin infinite loop" )#, display_state == {}".format (display_state) )
        last_sample_time_s = time.monotonic()


        if record_pause_state == 0:
            if inputs[0] or startup:
                #print( "record_pause_state = 0, which means it's recording")
                last_alloc = gc.mem_alloc()/1000.0
                timestamp = 0 ###read_clock( clock )
                if last_record_pause_state == 1:
                    batch_start_s = time.monotonic()
                    ###batch_label = update_batch( timestamp )
                    last_record_pause_state = 0
                inputs = check_inputs( pushbutton, touch_screen, pushbutton_last_press_state, screen_record_pause_last_press_state, source_lamps_last_press_state )

        else:
            #print( "record_pause_state = 1, which means it's paused")
            last_record_pause_state = 1

        if display_state == 0:                      # if it's in table mode
            if last_display_state != 0:             # if the last state was not table mode
                display.show( display_group_table ) # bring up the table display by loading the table background graphics
            # load data values into the table display
        last_display_state = 0                      # reset the last state to reflect the new mode

        exit_wait = 0
        remaining_wait_time = desired_sample_interval_s - (time.monotonic() - last_sample_time_s)
        while remaining_wait_time > 0 and exit_wait == 0:
            #if inputs[0]:
            inputs = check_inputs( pushbutton, touch_screen, pushbutton_last_press_state, screen_record_pause_last_press_state, source_lamps_last_press_state )
            #print( inputs )
            no_change = inputs[0]
            #pushbutton_press_state = pushbutton_pressed( pushbutton )

            #press = screen_pressed( touch_screen )
            # begin interpret inputs
            screen_record_pause_press_state = inputs[2] #press[0]
            if screen_record_pause_press_state != screen_record_pause_last_press_state and screen_record_pause_press_state == True:
            # if screen circle press state is different than the last; detect either rising or falling edge AND it's pressed now; detect rising edge
                record_pause_state = (record_pause_state + 1) % number_of_record_pause_states   # advance the state by one modulo the number of states
                exit_wait = 1                                                                   # implement the change now, don't wait for the rest of the interval
            screen_record_pause_last_press_state = screen_record_pause_press_state              # reset the last state to prepare for future edge detection

            pushbutton_press_state = inputs[1]
            if pushbutton_press_state:              # if the button is pushed, whatever the current record pause state is...
                if pushbutton_last_press_state == False: # if the button is just now being pushed and wasn't before; detect rising edge
                    exit_wait = 1                   # don't wait for the interval to finish, go ahead and jump to recording (if it's already in record mode, skip the current interval anyway)
                record_pause_state = 0              # set system to recording
                pushbutton_last_press_state = True  # set the last press state to "pressed"
            elif pushbutton_last_press_state:       # if the button goes from last pushed to now not pushed; detect falling edge
                record_pause_state = 1              # set system to pause
                pushbutton_last_press_state = False # set the last press state to "not pressed"
                exit_wait = 1                       # take action to implement pause right now
                # if the button is not pushed and was last not pushed, don't change state

            show_record_pause_icon( display_group_table, record_pause_state, display_state, 1 )

            source_lamps_press_state = inputs[3] #press[1]
            if source_lamps_press_state != source_lamps_last_press_state and source_lamps_press_state == True:
            # if screen trapezoid press state is different than the last; detect either rising or falling edge AND it's pressed now; detect rising edge
                source_lamps_state = (source_lamps_state + 1) % number_of_source_lamps_states # advance the state by one modulo the number of states
            source_lamps_last_press_state = source_lamps_press_state # reset the last state to prepare for future edge detection

            # implement lamp state
            if source_lamps_state == 0:
                source_lamps_off(VIS_sensor, NIR_sensor, aux_lamp)
            else:
                source_lamps_on(VIS_sensor, NIR_sensor, aux_lamp)


            remaining_wait_time = desired_sample_interval_s - (time.monotonic() - last_sample_time_s)
            time.sleep( 0.1 )
        # return to top of infinite loop

# function definitions below

def check_inputs( pushbutton, touch_screen, pushbutton_last_press_state, screen_record_pause_last_press_state, source_lamps_last_press_state ):
    pushbutton_press_state = pushbutton_pressed( pushbutton )
    press = screen_pressed( touch_screen )
    if pushbutton_last_press_state == pushbutton_press_state and screen_record_pause_last_press_state == press[0] and source_lamps_last_press_state == press[1]:
        no_change = True
    else:
        no_change = False
    return no_change, pushbutton_press_state, press[0], press[1]

def stall():
    print("intentionally stalled, press return to continue")
    input_string = False
    while input_string == False:
        input_string = input().strip()

def report_memory( message ):
    gc.collect()
    print("Memory B: Used {:} /Free {:} {}".format(gc.mem_alloc(), gc.mem_free(), message))
    #last_alloc = gc.mem_alloc()
    #print( "memory used here, bytes: {}".format (gc.mem_alloc() - last_alloc))
    #time.sleep(5)

def initialize_pushbutton():
    pushbutton = digitalio.DigitalInOut( board.D12 )
    pushbutton.direction = digitalio.Direction.INPUT
    pushbutton.pull = digitalio.Pull.UP
    return pushbutton

def pushbutton_pressed( pushbutton ):
    pushbutton_press_state = not pushbutton.value   #active low, so True is notpushed and False is pushed
    return pushbutton_press_state                   #pushbutton_press_state is True if button is being pushed

def initialize_spi():
    try:
        # spi has already been initialized by displayio/adafruit_ili9341, but reinitialize it here anyway
        spi_bus = board.SPI()
        # initialized spi bus
        return spi_bus
    except ValueError as err:
        print( "Error: spi bus fail: {:}".format(err) )
        return False

def initialize_touch_screen( spi_bus ):
    touch_screen_chip_select = digitalio.DigitalInOut(board.D6)
    try:
        touch_screen = Adafruit_STMPE610_SPI(spi_bus, touch_screen_chip_select)
        return touch_screen
    except RuntimeError as err:
        print("Error: touch screen runtime fail: {:}".format(err))
        return False
    except ValueError as err:
        print("Error: touch screen value fail {:}".format(err))
        return False

def screen_pressed( touch_screen ):
    if touch_screen != False:
        record_pause_press_state = 0
        table_graph_press_state = 0
        source_lamp_press_state = 0
        while not touch_screen.buffer_empty:
            touch_data = touch_screen.read_data()
            touch_x = touch_data[ 1 ]
            touch_y = touch_data[ 0 ]
            touch_pressure = touch_data[ 2 ]
            print( "X: %d, Y: %d, press: %d" % ( touch_x, touch_y, touch_pressure ) )
            if ( touch_x < 2400 ) and ( touch_y > 1500) and ( touch_y < 3700 ) and ( touch_y > 2400 ): #1750, 2950
                #print ("record_pause_press_state = 1")
                record_pause_press_state = True
            if ( touch_x > 1300 ) and ( touch_y < 2000 ) and ( touch_y < 2000 ): #1800, 1100
                source_lamp_press_state = True
                #print("lamp control pushed")
            #if ( touch_x < 1000 ) and ( touch_y > 1000 ) and ( touch_y < 3000 ):
            #    table_graph_press_state = True
        return (record_pause_press_state, source_lamp_press_state)
    else:
        return ( False, False )

def initialize_display( spi_bus ):
    if spi_bus == False:
        return False
    try:
        # displayio/dafruit_ili9341 library owns the pins until display release
        displayio.release_displays()
        tft_display_cs = board.D9
        tft_display_dc = board.D10
        display_bus = displayio.FourWire( spi_bus, command=tft_display_dc, chip_select=tft_display_cs )
        display = adafruit_ili9341.ILI9341( display_bus, width=SCREENSIZE_X, height=SCREENSIZE_Y, rotation=180 )
        # initialized display
        return display
    except ValueError as err:
        print("Error: display fail {:}".format(err))
        return False

def initialize_display_group( display ):
    if display == False:
        print("no display")
        return False
    display_group = displayio.Group()
    return display_group

def create_table_screen( display, display_group ):
    RED = 0xFF0022
    full_spectrum_frame( display_group, RED )
    text_group = full_spectrum_text_groups( display_group )
    return text_group

def full_spectrum_frame( table_group, border_color ):
    # begin full spectrum frame
    if table_group == False:
        return
    palette = displayio.Palette(1)
    palette[0] = border_color
    background_rectangle = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X, height=SCREENSIZE_Y, x=0, y=0)
    table_group.append( background_rectangle )
    palette = displayio.Palette(1)
    palette[0] = 0xFFFFFF
    border_width = 7 #0 #7
    foreground_rectangle = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X - 2*border_width, height=SCREENSIZE_Y - 2*border_width, x=border_width, y=border_width)
    table_group.append( foreground_rectangle )
    batch_x = 258
    batch_border_offset = 0
    batch_height_y = 26
    palette = displayio.Palette(1)
    palette[0] = border_color
    batch_border = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X - batch_x - border_width - batch_border_offset, height=batch_height_y, x=batch_x, y=border_width + batch_border_offset)
    table_group.append( batch_border )

    batch_area_border_width = 3
    palette = displayio.Palette(1)
    palette[0] = 0xFFFFFF
    batch_clear_area = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X - batch_x - border_width - batch_area_border_width, height=batch_height_y - batch_area_border_width, x=batch_x + batch_area_border_width, y=border_width)
    table_group.append( batch_clear_area )

    #Draw screen switch button:
    if False:
        palette = displayio.Palette(1)
        palette[0] = 0xC1C1C1
        screen_button_triangle = vectorio.Polygon( pixel_shader=palette, points = [(250, 60), (250, 160), (310, 110)], x=0, y=0)
        table_group.append(screen_button_triangle)

    #Draw the record_pause_state circle:
    palette = displayio.Palette(1)
    palette[0] = 0xC1C1C1
    record_pause_circle = vectorio.Circle( pixel_shader=palette, radius=45, x=170, y=70 )
    table_group.append( record_pause_circle )

    #Draw source trapezoid
    source_trapezoid = vectorio.Polygon( pixel_shader=palette, points = [(150, 170), (190, 170), (210, 230), (130, 230)], x=0, y=0)
    table_group.append(source_trapezoid)

def full_spectrum_text_groups( table_group ):
    if table_group == False:
        return False
    # Fixed width font
    fontPixelWidth, fontPixelHeight = terminalio.FONT.get_bounding_box()
    text_color = 0x000000 # black text for readability
    text_group = displayio.Group( scale = 2, x = 15, y = 20 ) #scale sets the text scale in pixels per pixel
    try:
        # Name each text_group with some: GROUP.X = len(text_grup), then use in text_group[ GROUP.X ]
        # Order doesn't matter for that (but is easier to figure out if in "display order")
        # LINE 1
        GROUP.DAY_DATE = len(text_group) # text_group[ i ] day date
        text_area = label.Label( terminalio.FONT, color = text_color ) #text color
        text_area.y = -1
        text_area.x = 0
        text_group.append( text_area )
        GROUP.BATCH = len(text_group) #text_group[ i ] batch_display_string
        text_area = label.Label( terminalio.FONT, color = text_color )
        text_area.y = -2
        text_area.x = 127
        text_group.append( text_area )
        # LINE 2
        GROUP.TIME = len(text_group) #text_group[ i ] time
        text_area = label.Label( terminalio.FONT, color = text_color )
        text_area.y = 12
        text_area.x = 0
        text_group.append( text_area )
        # surface temperature label, doesn't need a name
        text_area = label.Label( terminalio.FONT, text="Surface:", color = text_color )
        text_area.y = 12
        text_area.x = 70
        text_group.append( text_area )
        GROUP.SURFACE_TEMP = len(text_group) #text_group[ i ] surface temperature
        text_area = label.Label( terminalio.FONT, color = text_color )
        text_area.y = text_group[-1].y
        text_area.x = text_group[-1].x + len( text_group[-1].text ) * fontPixelWidth # use the previous text to get offset
        text_group.append( text_area )
        # LINE 3
        # units_string, doesn't need a name
        text_area = label.Label( terminalio.FONT, text="nm: uW/cm^2", color = text_color )
        text_area.y = 24
        text_area.x = 0
        text_group.append( text_area )

        # air temp label, doesn't need a name
        text_area = label.Label( terminalio.FONT, text="Air:", color = text_color )
        text_area.x = 94
        text_area.y = 24
        text_group.append( text_area )
        GROUP.AIR_TEMPERATURE = len(text_group) #text_group[ i ] air temperature
        text_area = label.Label( terminalio.FONT, color = text_color )
        text_area.y = text_group[-1].y
        text_area.x = text_group[-1].x + len(text_group[-1].text) * fontPixelWidth
        text_group.append( text_area )
        # LINE 5..10
        #text groups[ i..+5 ] VIS channels labels
        vis_start_x = 0
        for waveband_index,nm in enumerate(VIS_BANDS):
            vis_start_y = 36 + 12 * waveband_index
            # just labels
            label_string = "{:1}{:03}: ".format( VIS_BAND_PREFIXES[waveband_index], nm )
            text_area = label.Label( terminalio.FONT, text=label_string, color = text_color )
            text_area.x = vis_start_x
            text_area.y = vis_start_y
            text_group.append( text_area )
        GROUP.VIS_VALUES = len(text_group) #text groups[ i..+5 ] VIS channels. Just the first one, we `+ i` it
        # x is always the same: a column
        vis_start_x = vis_start_x + len( label_string ) * fontPixelWidth
        for waveband_index,nm in enumerate(VIS_BANDS):
            vis_start_y = 36 + 12 * waveband_index
            text_area = label.Label( terminalio.FONT, color = text_color )
            text_area.x = vis_start_x
            text_area.y = vis_start_y
            text_group.append( text_area )
        #text groups[ i..+5 ] NIR channels labels
        nir_start_x = 82
        for waveband_index,nm in enumerate(NIR_BANDS):
            nir_start_y = 36 + 12 * waveband_index
            # just labels
            label_string = "{:03}: ".format( nm )
            text_area = label.Label( terminalio.FONT, text=label_string, color = text_color )
            text_area.x = nir_start_x
            text_area.y = nir_start_y
            text_group.append( text_area )
        GROUP.NIR_VALUES = len(text_group) #text groups[ i..+5 ] NIR channels. Just the first one, we `+ i` it
        # x is always the same: a column
        nir_start_x = nir_start_x + len( label_string ) * fontPixelWidth
        for waveband_index,nm in enumerate(NIR_BANDS):
            nir_start_y = 36 + 12 * waveband_index
            text_area = label.Label( terminalio.FONT, color = text_color )
            text_area.x = nir_start_x
            text_area.y = nir_start_y
            text_group.append( text_area )
    except RuntimeError as err:
        if str(err) == "Group full":
            print("### Had this many groups when code failed: {:}".format(len(text_group)))
        raise
    table_group.append( text_group )
    #print("TG max_size {:}".format(len(text_group))) # to figure max_size of group
    return text_group

class GROUP:
    '''
    class GROUP:
      a group to gather the index names

      GROUP.X = 1
      magically creates the class variable X in GROUP,
      so we don't have to explicitly declare it

      = len(text_group)
      how many text_groups already made, == index of this text_group

      something = GROUP.X
      Then you just use it. But, this ensures that you assigned to GROUP.X before you read from it.
    '''
    pass

def create_welcome_screen( display ):
    welcome_group = initialize_display_group( display )
    border_color = 0xFF0022 # red
    front_color = 0x0000FF # blue
    if (display == False) or ( welcome_group == False):
        print("No display")
        return
    border = displayio.Palette(1)
    border[0] = border_color
    front = displayio.Palette(1)
    front[0] = front_color
    outer_rectangle = vectorio.Rectangle(pixel_shader=border, width=320, height=240, x=0, y=0)
    welcome_group.append( outer_rectangle )
    front_rectangle = vectorio.Rectangle(pixel_shader=front, width=280, height=200, x=20, y=20)
    welcome_group.append( front_rectangle )
    text_group = displayio.Group( scale=6, x=50, y=120 )
    text = "STELLA"
    text_area = label.Label( terminalio.FONT, text=text, color=0xFFFFFF )
    text_group.append( text_area ) # Subgroup for text scaling
    welcome_group.append( text_group )
    return welcome_group


def initialize_i2c():
    # Initialize the i2c bus at 100kHz, the fastest speed the tir sensor will accommodate.
    # Default i2c speed is 400kHz. At that speed, the TIR sensor will fail to communicate.
    try:
        i2c_bus = busio.I2C( board.SCL, board.SDA, frequency=100000 )
        # initialized i2c bus
        return i2c_bus
    except ValueError as err:
        print( "Error: i2c bus fail: {:}".format(err) )
        return False

def initialize_uart():
    try:
        uart_bus = busio.UART(board.TX, board.RX, baudrate=115200, bits=8, parity=1, stop=1)
        # initialized uart bus
        return uart_bus
    except ValueError as err: # known error behavior
        print( "Error: uart bus fail: {:}".format(err) )
        return False

def initialize_indicator():
    try:
        indicator_LED = digitalio.DigitalInOut( board.A0 )
        indicator_LED.direction = digitalio.Direction.OUTPUT
        indicator_LED.value = True #active low, True is off
        # initialized indicator
        return indicator_LED
    except Exception as err: # TBD: identify some typcial errors
        print( "Error: led pin init failed {:}".format(err) )
        return False

def initialize_auxilliary_lamp():
    try:
        aux_lamp = digitalio.DigitalInOut( board.D4 )
        aux_lamp.direction = digitalio.Direction.OUTPUT
        aux_lamp.value = True #active low, True is off
        # initialized indicator
        return aux_lamp
    except Exception as err: # TBD: identify some typcial errors
        print( "Error: auxilliary lamp control pin init failed {:}".format(err) )

def initialize_VIS_sensor( i2c_bus ):
    if i2c_bus == False:
        return False
    try:
        VIS_sensor = adafruit_as726x.AS726x_I2C( i2c_bus )
        VIS_sensor.conversion_mode = VIS_sensor.MODE_2
        # initialized visible spectrum sensor
        #TBD why 16 gain and 166 ms integration time? Because those are the values during the sensor calibration.
        VIS_sensor.gain = 16
        VIS_sensor.integration_time = 166
        return VIS_sensor
    except ValueError as err:
        print( "Error: visible spectrum sensor fail: {:}".format(err) )
        return False

def initialize_NIR_sensor( uart_bus ):
    if uart_bus == False:
        return False
    uart_bus.write(b"AT\n")
    data = uart_bus.readline() #typical first response from the device is b'ERROR\n', which indicates it is present.
    if data is None:
        print ( "Error: near infrared spectrum sensor fail" )
        return False
    else:
        # initialized near infrared spectrum sensor
        # check gain setting
        b = b"ATGAIN\n"
        uart_bus.write(b)
        data = uart_bus.readline()
        #print ( "# NIR spectrum default GAIN (2 = 16x gain): {:}".format(data))
        #check integration time setting
        b = b"ATINTTIME\n"
        uart_bus.write(b)
        data = uart_bus.readline()
        # print( "# NIR spectrum default INTTIME (59 * 2.8ms = 165ms): {:}".format(data))
        return uart_bus

def show_record_pause_icon( display_group, record_pause_state, mode, create_update ):
    if display_group == False:
        print("No display")
        return
    #print ( len ( display_group ))
    #WHITE = 0xFFFFFF
    BACKGROUND = 0xC1C1C1
    RED = 0xFF0022
    BLACK = 0x000000
    if mode == 0:
        x_center = 170
        y_center = 70
    else:
        x_center = 170
        y_center = 14
    radius = 8
    x_corner = x_center - radius
    y_corner = y_center - radius
    off_screen_y = 300
    width = 18
    split_width = int( width/3 )
    height = 18
    if create_update == 0:
        blank_icon = Rect( x_corner, y_corner, width, height, fill = BACKGROUND )#WHITE)
        recording_icon = Circle( x_center, y_center, radius, fill = RED)
        pause_square_icon = Rect( x_corner, y_corner, width, height, fill = BLACK)
        pause_split_icon = Rect( x_corner + split_width, y_corner, split_width, height, fill = BACKGROUND) #WHITE)
        display_group.append( blank_icon )
        display_group.append( recording_icon )
        display_group.append( pause_square_icon )
        display_group.append( pause_split_icon )
    else:
        len_group = ( len ( display_group ))
        if record_pause_state== 0:
            display_group[ len_group - 4 ].y = y_corner
            display_group[ len_group - 3 ].y = y_corner
            display_group[ len_group - 2 ].y = off_screen_y
            display_group[ len_group - 1 ].y = off_screen_y
        elif record_pause_state== 1:
            display_group[ len_group - 4 ].y = off_screen_y
            display_group[ len_group - 3 ].y = off_screen_y
            display_group[ len_group - 2 ].y = y_corner
            display_group[ len_group - 1 ].y = y_corner

def remove_record_pause_icon ( display_group ):
    len_group = ( len ( display_group ))
    display_group[ len_group - 2 ].y = 250
    display_group[ len_group - 1 ].y = 250

def source_lamps_on(VIS_sensor, NIR_sensor, aux_lamp):
    if aux_lamp != None:
        aux_lamp.value = True # the lamp circuit is active high

    if VIS_sensor != None:
        VIS_sensor.driver_led_current = 12.5 # mA, options 12.5, 25, 50, 100 mA
        VIS_sensor.driver_led = True

    if NIR_sensor != None:
        s = "ATLEDC=48\n"   #0, 16, 32, 48 set the driver to 12.5, 25, 50, 100 mA
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)
        s = "ATLED1=100\n" #100 is on, 0 is off
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)

def source_lamps_off(VIS_sensor, NIR_sensor, aux_lamp):
    if aux_lamp != None:
        aux_lamp.value = False # the lamp circuit is active high
    if VIS_sensor != None:
        VIS_sensor.driver_led = False
    if NIR_sensor != None:
        s = "ATLED1=0\n" #100 is on, 0 is off
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)

main()

