main

Code listing

"""
Main programme that is run when the microcontroller powers on.

Defines the :class:`Supervisor` class, which is responsible for:

* Collecting together the various component modules that make up the system,
  which are specified in the :attr:`components` attribute.
* Holding the system state, specified in the :attr:`config` attribute.
* Synchronising the system state with the python code running on the connected
  computer, using the :meth:`pull_config` method.
* Sending recorded sensors data to the computer, using the :meth:`push_data`
  method.
* Executing the main control loop, implemented by the :meth:`Supervisor.run` 
  method.

"""
import asyncio
import time

from log import Log
from client import SerialClient
from PID import PIDState
from sensor import TempSensor, TimeSensor, PIDSensor
from setup import *
from utils import ResponsiveDict


class Supervisor:
    """
    The Supervisor 
    
    """
    def __init__(self, serial_client, PID, log):
        
        self.components = [serial_client, PID, log]
        self.client = serial_client
    
        self.config = {
             'RUN': False,
             'MODE': False,
             'LOG': False,
             'TARGET': 23,
             'KP': 35.0,
             'KD': 2.0,
             'KI': 3.5,
             'INTERVAL':0.25
            }
        
    def pull_config(self):
        """
        
        """
        for msg in self.client.buf_in.copy():
            try:
                config = eval(msg.decode('utf-8'))
                for key,val in zip(config.keys(), config.values()):
                    for component in self.components:
                        if key in component.config.keys():
                            if component.config[key] != val:
                                component.config[key] = val
                    self.config[key] = val
                self.client.write(b'ACK:'+str(self.config).encode('utf-8')+b'\n')
                self.client.buf_in.remove(msg)
            except NameError as err:
                self.client.buf_in.remove(msg)
            except SyntaxError as err:
                self.client.buf_in.remove(msg)
        
    def push_data(self):
        # Message size scales as approximately 65 + (5+4+5)*(number of readings sent)
        bytesFree = self.client.buf_out_bytes_free
        if bytesFree > 160:
            num_request = (bytesFree -65) // 14
            data, n = self.log.read(num_request)
            message_string = b'DATA:' + str(data).encode('utf-8') + b'\n'
            message_len = len(message_string)
            self.client.buf_out[bytesFree-message_len:bytesFree] = message_string
            self.client.buf_out_bytes_free -= message_len
        

    def run(self):
        _ = [component.update() for component in self.components]
        self.pull_config()
        self.push_data()
        
    def wait(self, lastTimeStamp):
        while(time.monotonic_ns()-lastTimeStamp<self.config['INTERVAL']*1E9):
            time.sleep(0.001)
        return time.monotonic_ns()
            
thisPID = PIDState(max31865b,kp=7.0, ki=2.5, kd=0.1)

tempSensorA = TempSensor('TEMP', max31865a)
tempSensorB = TempSensor('TEMP', max31865b)
dTempSensor = TempSensor('DTEMP', max31856a, precision=2)
timeSensor = TimeSensor('TIME')
pidSensor = PIDSensor('PID', thisPID)

thisLog = Log(0.25, [ pidSensor, tempSensorA, tempSensorB, dTempSensor, timeSensor])

thisClient = SerialClient()

thisSupervisor = Supervisor(thisClient, thisPID, thisLog)
        
def main():
    lastTimeStamp = time.monotonic_ns()
    while True:
        thisSupervisor.run()
        lastTimeStamp = thisSupervisor.wait(lastTimeStamp)

main()