LEX_Threaded_Programming
Dependencies: Heater_V2 MODSERIAL Nanopb FastPWM ADS8568_ADC
main.cpp
- Committer:
- justinbuckland
- Date:
- 2019-09-12
- Revision:
- 9:9474da78cec3
- Parent:
- 8:58c6d51957df
- Child:
- 10:f8202e71e765
File content as of revision 9:9474da78cec3:
#include "mbed.h" #include "pb.h" #include "pb_decode.h" #include "pb_encode.h" #include "MODSERIAL.h" #include "ADS8568_ADC.h" #include "Heater.h" #include "FastPWM.h" #include "memspcr.pb.h" #include <vector> #include <iterator> #define BUFFER_SIZE 4096 #define LED_PULSE_PERIOD 8400 // ticks, 10kHz when CPU clock is 84MHz #define LED_PULSE_WIDTH 4200 // ticks, 50% duty cycle Heater * heater; float r_gradient; //setpoint setting MODSERIAL pc(PA_9, PA_10, BUFFER_SIZE); //mcu TX, RX, BUFFER_SIZE byte TX and RX buffers ADS8568_ADC adc(PB_15, PB_14, PB_13, PB_12, PC_15, PC_0, PC_1, PC_2, PC_3); I2C i2c(PB_7, PB_8); //SDA, SCL Timer timer; DigitalIn adc_busy(PA_8); //Busy interrupt sig# //Heater Control FastPWM drive_main(PC_9); FastPWM drive_lysis(PC_8); FastPWM guard_main(PC_7); FastPWM guard_lysis(PC_6); int heater_ID_main = 1; int heater_ID_lysis = 2; int i_port_main = 0; int i_port_lysis = 2; int v_port_main = 1; int v_port_lysis = 3; int heater_ID = 0; //Illumination LED Control //Indicator LEDs DigitalOut hb_led(PC_13); //Green DigitalOut led_0(PC_4); //Red DigitalOut led_1(PC_5); //Green //Camera and LED drive DigitalOut camTrigger(PB_2); //Trigger camera FastPWM ledDrive(PB_4); //PWM drive LED for fluorescence detection //User buttons DigitalIn user_0(PB_0); DigitalIn user_1(PB_1); BusOut converts(PC_0, PC_1, PC_2, PC_3); //Threads Thread heater_control(osPriorityHigh); Thread logging_thread(osPriorityAboveNormal); //Tickers Ticker heat_tick; Ticker pressure_tick; Ticker log_tick; //Flags EventFlags flags; //Flags: // 0 => update heater // 1 => log state bool triggered_flag; bool status = true; //Configuration data memspcr_ExperimentConfiguration exp_config = memspcr_ExperimentConfiguration_init_zero; int buffer_length; size_t message_length; uint8_t buffer[BUFFER_SIZE]; //Functions for reading and decoding the message__________________________________________________ void read_message() { if (pc.scanf("%d",&message_length) < 0){pc.printf("# Error reading message length");} size_t buffer_length = sizeof(buffer); if (message_length > buffer_length) { pc.printf("# Message length exceeds buffer. \n Input configuration file\n"); read_message(); return; } pc.printf("# Message is %d chars long, buffer length is %d\n",message_length,buffer_length); unsigned int c; for (int i = 0; i < message_length; i++) { pc.scanf("%02X",&c); buffer[i] = (char) c; } } void decode_message() { // Create a stream that reads from the buffer. pb_istream_t istream = pb_istream_from_buffer(buffer, message_length); //Now we are ready to decode the message. status = pb_decode(&istream, memspcr_ExperimentConfiguration_fields, &exp_config); // Check for errors... if (!status) { pc.printf("# Decoding failed: %s\n", PB_GET_ERROR(&istream)); } } bool decode_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) { vector <memspcr_ThermalStep> * dest = (vector <memspcr_ThermalStep> *)(*arg); memspcr_ThermalStep result = memspcr_ThermalStep_init_zero; status = pb_decode(stream, memspcr_ThermalStep_fields, & result); if (!status) { pc.printf("# Decode callback failed\n"); } dest->push_back(result); //CHECK: Does result get copied into the vector? return true; } //Ticking functions_________________________________________________________________ void temp_trigger() { //This function triggers a temperature update. //N.B. update cannot be called directly from a ticker as tickers and //reading the ADC both rely on interrupts. flags.set(0x1); } void log_trigger() { flags.set(0x2); } void pressure_control() { //Input pressure control function here //i.e. //read_pressure(); //if (pressure < lower_bound) { //pump_turn_on(); //} //else if (pressure > upper_bound) { //pump_turn_off(); //} led_1 = !led_1; } //Other functions__________________________________________________________________ void temp_control() { while(1){ flags.wait_any(0x1,osWaitForever,true); heater->read(); heater->update(); } } void log_state() { while(1){ flags.wait_any(0x2,osWaitForever,true); //Output time, R_ref, R, error, error_integrated pc.printf("%10d,%10d,%10.6f,%10.6f\n", heater_ID, timer.read_ms(), heater->Get_R(), heater->Get_R_ref()); } } void set_point_routine(std::vector<memspcr_ThermalStep> profile) { int curr_time; vector <memspcr_ThermalStep>::iterator it_prev, it = profile.begin(); if (it->elapsed_time_ms != 0) { pc.printf("# Error: the first point in the profile should be at time 0.\n"); return; } it++; for (it_prev = profile.begin(); it < profile.end(); it ++, it_prev++){ triggered_flag = false; r_gradient = (it->resistance - it_prev->resistance)/(it->elapsed_time_ms - it_prev->elapsed_time_ms); while ((curr_time = timer.read_ms()) <= it->elapsed_time_ms){ heater->Set_ref(it_prev->resistance + r_gradient * (curr_time - it_prev->elapsed_time_ms)); if (!triggered_flag && (it->camera_offset_ms != 0) && (curr_time > it_prev->elapsed_time_ms + it->camera_offset_ms)) { //Start camera exposure and turn on LED if camera_offset_ms is non-zero camTrigger = 0; wait_us(10); camTrigger = 1; led_0 = 1; ledDrive.pulsewidth_ticks(LED_PULSE_WIDTH); triggered_flag = true; } wait_us(200); } //Stop camera exposure and turn off LED at end of time segment camTrigger = 0; ledDrive.pulsewidth_ticks(0); led_0 = 0; } } int main() { pc.baud(115200); adc.init(); buffer_length = sizeof(buffer)/sizeof(uint8_t); pc.printf("# Input configuration file\n"); //set up LED PWM drive ledDrive.prescaler(1); ledDrive.period_ticks(LED_PULSE_PERIOD); ledDrive.pulsewidth_ticks(0); //set up nanopb std::vector<memspcr_ThermalStep> profile; exp_config.profile.funcs.decode = decode_callback; exp_config.profile.arg = &profile; //read and decode configuration read_message(); pc.printf("# Message read\n"); decode_message(); pc.printf("# Message decoded\n"); Heater * heater_main = new Heater(i_port_main, v_port_main, & drive_main, & guard_main, & adc, adc_busy, exp_config.thermal); Heater * heater_lysis = new Heater(i_port_lysis, v_port_lysis, & drive_lysis, & guard_lysis, & adc, adc_busy, exp_config.thermal); //Select heater. Put control times in us for ticker functions if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_MAIN) { heater = heater_main; heater_ID = heater_ID_main; } else if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_LYSIS) { heater = heater_lysis; heater_ID = heater_ID_lysis; } else { pc.printf("# Error - no heater has been selected\n"); return 1; } pc.printf("# Starting pressure control\n"); pressure_tick.attach(& pressure_control, 1); pc.printf("# Waiting for start signal to begin temperature control (type in an s or press button 0)\n"); heater->Set_ref(0.0); heater_control.start(& temp_control); heat_tick.attach_us(& temp_trigger,exp_config.thermal.control_loop_interval_ms * 1000); while (pc.getcNb()!='s' && !user_0); pc.printf("# Start signal received\n"); logging_thread.start(& log_state); log_tick.attach_us(& log_trigger,exp_config.logging_interval_ms * 1000); pc.printf("# Starting routine\n"); pc.printf("# heater, time(ms), r, rSet\n"); timer.start(); set_point_routine(profile); //Turn off heat_tick.detach(); log_tick.detach(); wait(1); heater->turn_off(); pc.printf("# Finished\n"); return 0; }