##
# @file    main.py
# @brief   Test lots of GUI controls
# @version 1.0
#

import ft8xx
import gnss
import gui
import digitalio
import vbox

def tod_to_hmsm(ms):
    hmsm = 4 * [None]
    hmsm[0] = ms // 3600000
    ms -= (hmsm[0] * 3600000)
    hmsm[1] = ms // 60000
    ms -= (hmsm[1] * 60000)
    hmsm[2] = ms // 1000
    ms -= (hmsm[2] * 1000)
    hmsm[3] = ms
    return hmsm

# Callbacks for the GUI controls
def button_example_cb(ctrl):
    global button_count
    button_count += 1
    # Cowbell
    ft8xx.wr16(ft8xx.REG_SOUND, 0x52)
    # Play
    ft8xx.wr16(ft8xx.REG_PLAY, 1)
    # Print a message on console
    print('Button pressed!')
    # Update button text
    ctrl[6] = 'Count: {0}'.format(button_count)

def toggle_example_cb(ctrl):
    # Print a message on console
    print('Toggled!')
    # Switch state
    ctrl[5][0] = 0 if ctrl[5][0] & 0x8000 else 0xffff

# GNSS new data callback
def gnss_example_cb():
    global quality, sats, lat, lng, fix_types
    sample = vbox.get_sample()
    quality[0] = fix_types[sample.fix_type]
    time_tmp = tod_to_hmsm(sample.tod_ms)
    time[0] = '{0:02}:{1:02}:{2:02}.{3}'.format(time_tmp[0], time_tmp[1], time_tmp[2], time_tmp[3])
    sats[0] = sample.sats_used
    latm = sample.lat_minE5
    sign_lat = '+' if latm >= 0 else '-'
    latm = abs(latm)
    latdeg[0] = '{}{}'.format(sign_lat, latm // 6000000)
    latmin[0] = '{:08.5f}\''.format((latm % 6000000) / 1E5)
    lngm = sample.lng_minE5
    sign_lng = '+' if lngm >= 0 else '-'
    lngm = abs(lngm)
    lngdeg[0] = '{}{}'.format(sign_lng, lngm // 6000000)
    lngmin[0] = '{:08.5f}\''.format((lngm % 6000000) / 1E5)
    hdng[0] = sample.heading_deg
    spd[0] = sample.speed_gnd_smooth_mps

    # Take advantage of this 10 Hz callback and display the frame rate
    global fps_calc, fps
    fps_calc = fps_calc[1:11]
    fps_calc.append(ft8xx.rd32(ft8xx.REG_FRAMES))
    fps[0] = fps_calc[10] - fps_calc[0]

    gui.redraw()

# Redraw callback
# Note: other callbacks are passed only its element, but event callbacks are
# passed the entire GUI list structure
def redraw_example_cb(glist):
    global redraw_count
    redraw_count += 1
    glist[2][6] = redraw_count
    global in0, in1
    in0[0], in1[0] = digitalio.get()
    if swiping:
        si = gui.swipe_info()
        swipe_info_l[5] = 'Swipe: {} {}'.format(si.dx, si.dy)

# Vsync callback
# Note: other callbacks are passed only its element, but event callbacks are
# passed the entire GUI list structure
def vsync_example_cb(glist):
    global vsync_count
    vsync_count += 1
    glist[4][6] = vsync_count

fix_types = {
    0x00:'No fix',
    0x01:'Dead reckoning only',
    0x02:'2D fix',
    0x03:'3D fix',
    0x04:'GNSS + dead reckoning combined',
    0x05:'Time only fix',
    0x06:'RTK Float fix',
    0x07:'RTK Fixed fix',
    0x08:'Fixed location',
    0x09:'GNSS with differential corrections',
    0x0A:'Coasting on inertial data',
    0x20:'VIPS solution',
}

# Data to be displayed
redraw_count = 0
vsync_count = 0
button_count = 0

fps_calc = [0] * 11

gvalue = [28000]
fps = [0]

quality = ['No fix']
time = ['--:--:--']
sats = [0]
latdeg = ['0']
lngdeg = ['0']
latmin = ['0']
lngmin = ['0']
hdng = [0]
spd = [0]

in0 = [True]
in1 = [True]

swiping = False
swipe_info_l = [gui.CTRL_TEXT, 590, 370, 28, 0, 'Not swiping']
def swipe_cb(l, start):
    global swiping
    swiping = start
    if not swiping:
        swipe_info_l[5] = 'Not swiping'

_gui_list = [
    # Swipe callback
    [gui.EVT_SWIPE, 50, swipe_cb],
    # Redraw callback
    [gui.EVT_REDRAW, redraw_example_cb],
    # Redraw_count will be displayed on this
    [gui.CTRL_NUMBER, 0, 20, 28, 0, '', 0],
    # Vsync callback
    [gui.EVT_VSYNC, vsync_example_cb],
    # Vsync_count will be displayed on this
    [gui.CTRL_NUMBER, 0, 40, 28, 0, '', 0],
    # Frame rate
    [gui.CTRL_NUMBER, 0, 60, 28, 0, '', fps],
    # Display GNSS information
    [gui.CTRL_TEXT,   260, 330, 28, 0, 'GNSS quality:'],
    [gui.CTRL_TEXT,   260, 350, 28, 0, 'GNSS time:'],
    [gui.CTRL_TEXT,   260, 370, 28, 0, 'GNSS sats:'],
    [gui.CTRL_TEXT,   260, 390, 28, 0, 'GNSS lat:'],
    [gui.CTRL_TEXT,   260, 410, 28, 0, 'GNSS lng:'],
    [gui.CTRL_TEXT,   260, 430, 28, 0, 'GNSS hdng:'],
    [gui.CTRL_TEXT,   260, 450, 28, 0, 'GNSS spd:'],
    [gui.CTRL_TEXT,   410, 330, 28, 0, quality],
    [gui.CTRL_TEXT,   410, 350, 28, 0, time],
    [gui.CTRL_NUMBER, 410, 370, 28, 0, '', sats],
    # Display only the degrees part
    [gui.CTRL_TEXT,   440, 390, 28, gui.OPT_RIGHTX, latdeg],
    [gui.CTRL_TEXT,   440, 410, 28, gui.OPT_RIGHTX, lngdeg],
    # Display degrees symbol
    [gui.CTRL_TEXT,   442, 395, 19, 0, 'x'],
    [gui.CTRL_TEXT,   442, 415, 19, 0, 'x'],
    # Display only the arc-minutes part
    [gui.CTRL_TEXT,   450, 390, 28, 0, latmin],
    [gui.CTRL_TEXT,   450, 410, 28, 0, lngmin],
    [gui.CTRL_NUMBER, 410, 430, 28, 0, '%3.2f', hdng],
    [gui.CTRL_NUMBER, 410, 450, 28, 0, '%3.2f', spd],
    # Display digital input information
    [gui.CTRL_TEXT, 590, 330, 28, 0, 'Input 0:'],
    [gui.CTRL_TEXT, 590, 350, 28, 0, 'Input 1:'],
    [gui.CTRL_NUMBER, 680, 330, 28, 0, '', in0],
    [gui.CTRL_NUMBER, 680, 350, 28, 0, '', in1],
    # text: x, y, font, s
    [gui.CTRL_TEXT, 0, 0, 28, 0, 'GUI Test'],
    # number: x, y, font, fmt, n
    [gui.CTRL_NUMBER, 372, 250, 28, 0, '', gvalue],
    # clock: x, y, r, draw seconds hand, draw hour ticks, draw face background, total seconds
    [gui.CTRL_CLOCK, 150, 120, 100, True, True, True, gvalue],
    # gauge: x, y, r, major, minor, value, range
    [gui.CTRL_GAUGE, 400, 120, 100, 10, 5, gvalue, 0xffff],
    # dial: x, y, r, value (tracked)
    [gui.CTRL_DIAL, 650, 120, 100, gvalue],
    # slider: x, y, w, h, range, value (tracked)
    [gui.CTRL_SLIDER, 50, 250, 300, 20, 0xffff, gvalue],
    # scrollbar: x, y, w, h, size, range, value (tracked)
    [gui.CTRL_SCROLLBAR, 450, 250, 300, 20, 0x4000, 0xffff, gvalue],
    # toggle: x, y, w, font, value, s
    [gui.CTRL_TOGGLE, 50, 350, 50, 28, gvalue, b'no\xffyes', toggle_example_cb],
    # progress: x, y, w, h, value, range
    [gui.CTRL_PROGRESS, 50, 300, 700, 20, gvalue, 0xffff],
    # button: x, y, w, h, font, s
    [gui.CTRL_BUTTON, 20, 400, 160, 40, 28, "I'm a button", button_example_cb],
    # Swipe info
    swipe_info_l,
]


if __name__ == '__main__':
    while (gnss.init_status() > 0):
        pass
    try:
        vbox.init(vbox.VBOX_SRC_GNSS_BASIC)
    except Exception as e:
        if str(e) == 'VBox source already configured':
            pass
        else:
            raise Exception(str(e))
    
    # Set callback to be executed when new GNSS data arrives
    vbox.set_new_data_callback(gnss_example_cb)
    gui.show(_gui_list)