#!/usr/bin/python
import sys, array, time
import serial
from struct import *


# Class definition / Interface for reading sensor values
class ScratchBoard:
    def __init__(self, serialPort):
        # The information received from the picoboard is packed in frames called channels, each channel has a number so we associate them with names ( more easy to be understood by humans :) )
        self.sbChannels = {0: "resistance-D", 1: "resistance-C", 2: "resistance-B", 3: "button", 4: "resistance-A",
                           5: "light", 6: "sound", 7: "slider", 15: "firmware-id"}
        # Everytime we request the values from the picoboard we have to send first a byte with the following value b00000001
        self.pollToken = array.array('B', [1]).tostring()
        # Store
        self.serialPort = serialPort
        self.ser = None

    def open(self):
        # Here we open a serial port using a rate of 38400 for transfer and a timeout of 1 second. Also we flush everything that's on the line.
        self.ser = serial.Serial(self.serialPort, 38400, timeout=1)
        self.ser.read()
        self.ser.flushInput()

    def close(self):
        if self.ser != None:
            self.ser.close()

    def getSensorValues(self):
        # Flush everything that is in the buffer... we need fresh data
        self.ser.flushInput()

        # Poll the scratch board (send 0x01 and receive a 18 bytes packet back)... have a look at the packet structure in the printed documentation
        self.ser.write(self.pollToken)
        sbPacketString = self.ser.read(18)
        sbPacket = unpack("BBBBBBBBBBBBBBBBBB", sbPacketString)

        # Parse the data received and extract useful info.. and store the info into a hast-table (disctionary in python)
        result = {}
        for i in range(9):
            sb_channel = self.sbChannels[(int(sbPacket[2 * i]) - 128) >> 3]
            sb_value = ((int(sbPacket[2 * i]) & 7) << 7) + int(sbPacket[2 * i + 1])
            result[sb_channel] = sb_value

        # Adjust some the values to be more appropiate to be read by humans. So for slider and button we have values between 0 and 100.
        for tmp in ["slider", "button"]:
            result[tmp] = int((100 * result[tmp]) / 1023)

        return result

    # make some adjustmets for the value received from the light sensor
    def light(self, value):
        if value < 25:
            return 100 - value
        return (1023 - value) * (75 / 998)

    # make some adjustmets for the value received from the sound sensor
    def sound(self, value):
        n = max(0, value - 18)
        if n < 50:
            return int(n / 2)
        return 25 + min(75, int((n - 50) * (75 / 580)))

    # return the value of the slider. a value between 0 and 100
    def getSliderValue(self):
        return self.getSensorValues()["slider"]

    # return the button value. 0=pressed, 100=unpressed
    def getButtonValue(self):
        return self.getSensorValues()["button"]

    # return raw information from the light sensor
    def getLightValue(self):
        return self.getSensorValues()["light"]

    # return raw information from the sound sensor
    def getSoundValue(self):
        return self.getSensorValues()["sound"]

    # the result is in kOhm for the resistances
    # def getResistanceAValue(self):
    #	x = self.getSensorValues()["resistance-A"]
    #	return (134.78 + 66.11*x + 2.421*x*x) / 1000

    # Return the resut in mV. The ADC has an linear output between 0 and 1023 for voltages between 0 and 5V
    def getVoltageAValue(self):
        return int(5000 * self.getSensorValues()["resistance-A"] / 1023)

    def getVoltageBValue(self):
        return int(5000 * self.getSensorValues()["resistance-B"] / 1023)

    def getVoltageCValue(self):
        return int(5000 * self.getSensorValues()["resistance-C"] / 1023)

    def getVoltageDValue(self):
        return int(5000 * self.getSensorValues()["resistance-D"] / 1023)

#
# Simple usage example
#
# from pico import *        -> import the pico modules... make sure that the pico.py is in the same directory as your program
# pico = ScratchBoard(2)	-> the number passed as argument is the serial port number. COM1=0, COM2=1, COM3=2, COM4=3 etc
# pico.open()
# print "Button=",pico.getButtonValue()
# print "Slider=",pico.getSliderValue()
# pico.close()
#
