Committer:
marcbax
Date:
Mon Mar 28 07:15:14 2011 +0000
Revision:
0:fd45411cac49
v0.90

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcbax 0:fd45411cac49 1 //Firmware to drive Eton bee trainer breadboard
marcbax 0:fd45411cac49 2 char* fwversion = "0.90"; //For published versions use format "n.nn"
marcbax 0:fd45411cac49 3 //For development versions add "D" to end of string
marcbax 0:fd45411cac49 4 //This version published on 28/03/2011
marcbax 0:fd45411cac49 5
marcbax 0:fd45411cac49 6 //Include libraries
marcbax 0:fd45411cac49 7 #include "mbed.h"
marcbax 0:fd45411cac49 8 #include "Servo.h" //need this library to control servos
marcbax 0:fd45411cac49 9
marcbax 0:fd45411cac49 10 //Pin assignments and external functions
marcbax 0:fd45411cac49 11 DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4); //for debugging purposes only
marcbax 0:fd45411cac49 12 DigitalOut buzzer(p5); //pin high means buzzer on
marcbax 0:fd45411cac49 13 DigitalOut airswitcher(p7); //pin high shorts coax for air switcher valve
marcbax 0:fd45411cac49 14 Serial display(p9,p10); //serial display controller by ByVAC BV4618 controller
marcbax 0:fd45411cac49 15 AnalogOut irLED(p18); //only one analog out controls both IR LEDS in parallel
marcbax 0:fd45411cac49 16 AnalogIn ptor1(p19), ptor2(p20); //analog input for beeholder phototransistors
marcbax 0:fd45411cac49 17 Servo arm1(p21), elbow1(p22); //servos for station 1 robot arm
marcbax 0:fd45411cac49 18 Servo arm2(p23), elbow2(p24); //servos for station 2 robot arm
marcbax 0:fd45411cac49 19 I2C beeholder(p28,p27); //set up I2C communication to read beeholder serial no
marcbax 0:fd45411cac49 20 DigitalOut bhsel1(p29), bhsel2(p30); //select lines for station 1 and station 2 - pull low to select holder
marcbax 0:fd45411cac49 21 DigitalIn upsw(p13), risw(p14), dnsw(p15), lesw(p16), oksw(p17); //footswitch connected parallel to OK switch
marcbax 0:fd45411cac49 22 LocalFileSystem local("local"); //allow access to the mbed "thumbdrive" as a file system
marcbax 0:fd45411cac49 23 FILE *logfile = fopen("/local/etonlog.csv","w"); //creates new file etonlog.csv and set for writing. Overwrites existing file!
marcbax 0:fd45411cac49 24
marcbax 0:fd45411cac49 25 //Definition of global constants
marcbax 0:fd45411cac49 26 //station 1 (left) robot arm positions
marcbax 0:fd45411cac49 27 float arm1basepos = 0.4;
marcbax 0:fd45411cac49 28 float elbow1basepos = 0.07;
marcbax 0:fd45411cac49 29 float arm1dippos = 0.2;
marcbax 0:fd45411cac49 30 float elbow1dippos = 0.6;
marcbax 0:fd45411cac49 31 float arm1ticklepos = 0.65;
marcbax 0:fd45411cac49 32 float elbow1ticklepos = 0.07;
marcbax 0:fd45411cac49 33 float arm1feedpos = 0.7;
marcbax 0:fd45411cac49 34 float elbow1feedpos = 0.4;
marcbax 0:fd45411cac49 35
marcbax 0:fd45411cac49 36 //station 2 (right) robot arm positions
marcbax 0:fd45411cac49 37 float arm2basepos = 0.4;
marcbax 0:fd45411cac49 38 float elbow2basepos = 0.07;
marcbax 0:fd45411cac49 39 float arm2dippos = 0.2;
marcbax 0:fd45411cac49 40 float elbow2dippos = 0.07;
marcbax 0:fd45411cac49 41 float arm2ticklepos = 0.2;
marcbax 0:fd45411cac49 42 float elbow2ticklepos = 0.07;
marcbax 0:fd45411cac49 43 float arm2feedpos = 0.2;
marcbax 0:fd45411cac49 44 float elbow2feedpos = 0.07;
marcbax 0:fd45411cac49 45
marcbax 0:fd45411cac49 46 //robot arm hold and move times all times are in seconds
marcbax 0:fd45411cac49 47 float diptime = 1; //time that brush stays down dipped in sugar water
marcbax 0:fd45411cac49 48 float tickletimeout = 3; //maximum time to tickle if no PER is detected
marcbax 0:fd45411cac49 49 float feedtime = 3; //feeding time
marcbax 0:fd45411cac49 50
marcbax 0:fd45411cac49 51 //PER detection parameters
marcbax 0:fd45411cac49 52 float calsetval = 1.4; //voltage to which phototransistor output will be calibrated
marcbax 0:fd45411cac49 53 float PERsetval = 2.1; //phototransistor output needs to be above this voltage for PER
marcbax 0:fd45411cac49 54 float PERtime = 0.2; //phototransistor output needs to stay high this long in seconds
marcbax 0:fd45411cac49 55
marcbax 0:fd45411cac49 56 //I2C address
marcbax 0:fd45411cac49 57 int addr = 0xA2; //address is actually 0x51, but mbed expects left-shifted address
marcbax 0:fd45411cac49 58
marcbax 0:fd45411cac49 59 //Definition of global variables
marcbax 0:fd45411cac49 60
marcbax 0:fd45411cac49 61 struct holderrecord { //used to hold data on beeholder
marcbax 0:fd45411cac49 62 int serialno; //beeholder serial number 0-9999
marcbax 0:fd45411cac49 63 float calvalue; //IR-LED calibration value
marcbax 0:fd45411cac49 64 char cycleno; //number of cycles gone through in this session
marcbax 0:fd45411cac49 65 char reslastcycle; //result of last cycle, 1 for PER
marcbax 0:fd45411cac49 66 char ticklenextcycle; //whether tickling was done for last cycle
marcbax 0:fd45411cac49 67 time_t tstamp; //timestamp when last cycle was run
marcbax 0:fd45411cac49 68 };
marcbax 0:fd45411cac49 69
marcbax 0:fd45411cac49 70 holderrecord currentholder; //struct record for the current beeholder
marcbax 0:fd45411cac49 71 holderrecord sessionrecord[30]; //sessionrecord contains holderrecords for up to 30 beeholders
marcbax 0:fd45411cac49 72
marcbax 0:fd45411cac49 73 int numbeeholders; //number of beeholders used in current session
marcbax 0:fd45411cac49 74 int station; //which station is used in this session
marcbax 0:fd45411cac49 75
marcbax 0:fd45411cac49 76 //Substance strings
marcbax 0:fd45411cac49 77
marcbax 0:fd45411cac49 78 struct submenuitem {
marcbax 0:fd45411cac49 79 char* displaystring; //keep display string to 19 characters or less, otherwise display screws up
marcbax 0:fd45411cac49 80 char* logstring; //this is the string that gets printed in the logfile, and can be longer then 19 characters
marcbax 0:fd45411cac49 81 };
marcbax 0:fd45411cac49 82
marcbax 0:fd45411cac49 83 submenuitem submenu[11];
marcbax 0:fd45411cac49 84 int substanceindex; //this variable contains the index number (in the list) of the selected substance
marcbax 0:fd45411cac49 85
marcbax 0:fd45411cac49 86 //Function declarations
marcbax 0:fd45411cac49 87
marcbax 0:fd45411cac49 88 //Short beep
marcbax 0:fd45411cac49 89 void beeponce() {
marcbax 0:fd45411cac49 90 buzzer = 1;
marcbax 0:fd45411cac49 91 wait(0.1);
marcbax 0:fd45411cac49 92 buzzer = 0;
marcbax 0:fd45411cac49 93 }
marcbax 0:fd45411cac49 94
marcbax 0:fd45411cac49 95 //beep beep beep
marcbax 0:fd45411cac49 96 void multibeeps(int number, float interval) {
marcbax 0:fd45411cac49 97 for(int i=0;i<number;i++){
marcbax 0:fd45411cac49 98 beeponce();
marcbax 0:fd45411cac49 99 wait(interval);
marcbax 0:fd45411cac49 100 }
marcbax 0:fd45411cac49 101 }
marcbax 0:fd45411cac49 102
marcbax 0:fd45411cac49 103 //Clears and homes the display
marcbax 0:fd45411cac49 104 void cleardisplay() {
marcbax 0:fd45411cac49 105 display.printf("\e[2J\e[H");
marcbax 0:fd45411cac49 106 }
marcbax 0:fd45411cac49 107
marcbax 0:fd45411cac49 108 //Returns both robot arms to base position
marcbax 0:fd45411cac49 109 void armstobase() {
marcbax 0:fd45411cac49 110 elbow1 = elbow1basepos;
marcbax 0:fd45411cac49 111 elbow2 = elbow2basepos;
marcbax 0:fd45411cac49 112 wait(0.5); //need this delay to avoid snagging brush on IR LED
marcbax 0:fd45411cac49 113 arm1 = arm1basepos;
marcbax 0:fd45411cac49 114 arm2 = arm2basepos;
marcbax 0:fd45411cac49 115 }
marcbax 0:fd45411cac49 116
marcbax 0:fd45411cac49 117 //Fills the substance menu array with text
marcbax 0:fd45411cac49 118 void fillsubstancemenu() {
marcbax 0:fd45411cac49 119 submenu[0].displaystring = "No substance";
marcbax 0:fd45411cac49 120 submenu[0].logstring = "Lack of substance";
marcbax 0:fd45411cac49 121
marcbax 0:fd45411cac49 122 submenu[1].displaystring = "Coffee";
marcbax 0:fd45411cac49 123 submenu[1].logstring = "Espresso macchiato";
marcbax 0:fd45411cac49 124
marcbax 0:fd45411cac49 125 submenu[2].displaystring = "Earl Grey";
marcbax 0:fd45411cac49 126 submenu[2].logstring = "Nice cup of tea";
marcbax 0:fd45411cac49 127
marcbax 0:fd45411cac49 128 submenu[3].displaystring = "Apple Pie";
marcbax 0:fd45411cac49 129 submenu[3].logstring = "Mom's homemade apple pie - longer then 19 characters";
marcbax 0:fd45411cac49 130
marcbax 0:fd45411cac49 131 submenu[4].displaystring = "Substance 04";
marcbax 0:fd45411cac49 132 submenu[4].logstring = "Substance 4";
marcbax 0:fd45411cac49 133
marcbax 0:fd45411cac49 134 submenu[5].displaystring = "Substance 05";
marcbax 0:fd45411cac49 135 submenu[5].logstring = "Substance 5";
marcbax 0:fd45411cac49 136
marcbax 0:fd45411cac49 137 submenu[6].displaystring = "Substance 06";
marcbax 0:fd45411cac49 138 submenu[6].logstring = "Substance 6";
marcbax 0:fd45411cac49 139
marcbax 0:fd45411cac49 140 submenu[7].displaystring = "Substance 07";
marcbax 0:fd45411cac49 141 submenu[7].logstring = "Substance 7";
marcbax 0:fd45411cac49 142
marcbax 0:fd45411cac49 143 submenu[8].displaystring = "Substance 08";
marcbax 0:fd45411cac49 144 submenu[8].logstring = "Substance 8";
marcbax 0:fd45411cac49 145
marcbax 0:fd45411cac49 146 submenu[9].displaystring = "Substance 09";
marcbax 0:fd45411cac49 147 submenu[9].logstring = "Substance 9";
marcbax 0:fd45411cac49 148
marcbax 0:fd45411cac49 149 submenu[10].displaystring = "Red Roses";
marcbax 0:fd45411cac49 150 submenu[10].logstring = "I never promised you a rose garden";
marcbax 0:fd45411cac49 151 }
marcbax 0:fd45411cac49 152
marcbax 0:fd45411cac49 153 //Initialises sessionrecords
marcbax 0:fd45411cac49 154 void sessionrecordinit() {
marcbax 0:fd45411cac49 155 for (int i=0; i<30; i++) { //set base values for all possible beeholders
marcbax 0:fd45411cac49 156 sessionrecord[i].serialno = 0; //set serialno to 0 so we can detect a unresponsive holder
marcbax 0:fd45411cac49 157 sessionrecord[i].calvalue = 0;
marcbax 0:fd45411cac49 158 sessionrecord[i].cycleno = 0;
marcbax 0:fd45411cac49 159 sessionrecord[i].reslastcycle = 0;
marcbax 0:fd45411cac49 160 sessionrecord[i].ticklenextcycle = 1; //default is to tickle on each cycle
marcbax 0:fd45411cac49 161 }
marcbax 0:fd45411cac49 162 }
marcbax 0:fd45411cac49 163
marcbax 0:fd45411cac49 164 //Initialisation on power-on
marcbax 0:fd45411cac49 165 void initialise() {
marcbax 0:fd45411cac49 166
marcbax 0:fd45411cac49 167 //Set pins to a defined state
marcbax 0:fd45411cac49 168 led1 = led2 = led3 = led4 =0; //internal LEDs only used for debugging purposes
marcbax 0:fd45411cac49 169 buzzer = 0; //buzzer off
marcbax 0:fd45411cac49 170 airswitcher = 0; //relay contacts open, clean air position
marcbax 0:fd45411cac49 171 bhsel1 = bhsel2 = 1; //I2C select lines high to deselect both beeholders
marcbax 0:fd45411cac49 172 upsw.mode(PullUp); //set pull-up on all frontpanel switches
marcbax 0:fd45411cac49 173 risw.mode(PullUp);
marcbax 0:fd45411cac49 174 dnsw.mode(PullUp);
marcbax 0:fd45411cac49 175 lesw.mode(PullUp);
marcbax 0:fd45411cac49 176 oksw.mode(PullUp);
marcbax 0:fd45411cac49 177
marcbax 0:fd45411cac49 178 //Set robot arms to base positions
marcbax 0:fd45411cac49 179 armstobase();
marcbax 0:fd45411cac49 180
marcbax 0:fd45411cac49 181 //initialise the display
marcbax 0:fd45411cac49 182 display.baud(19200); //set display baud rate to 19200
marcbax 0:fd45411cac49 183 display.putc(0x0d); //send CR to display - this needs to be first character sent after power-up
marcbax 0:fd45411cac49 184 wait(0.5); //wait for display to adjust to serial baud rate
marcbax 0:fd45411cac49 185 display.printf("\e[4L\e[20c"); //set display to 4 lines of 20 characters
marcbax 0:fd45411cac49 186 cleardisplay(); //clear screen and home cursor
marcbax 0:fd45411cac49 187
marcbax 0:fd45411cac49 188 //display splash screen with time
marcbax 0:fd45411cac49 189 display.printf("Eton trainer v%s\r", fwversion); //show firmware release version
marcbax 0:fd45411cac49 190 time_t seconds = time(NULL); //creates timestamp
marcbax 0:fd45411cac49 191 char bufferd[20], buffert[20];
marcbax 0:fd45411cac49 192 strftime(bufferd, 20, "%d/%m/%Y", localtime(&seconds)); //formats date part of timestamp
marcbax 0:fd45411cac49 193 display.printf("Date: %s\r", bufferd); //displays date
marcbax 0:fd45411cac49 194 strftime(buffert, 20, "%X", localtime(&seconds)); //formats time part of timestamp
marcbax 0:fd45411cac49 195 display.printf("Time: %s\r", buffert); //displays time
marcbax 0:fd45411cac49 196 wait(3); //display splash screen
marcbax 0:fd45411cac49 197 cleardisplay(); //clear screen and home cursor
marcbax 0:fd45411cac49 198
marcbax 0:fd45411cac49 199 //initialise sessionrecord
marcbax 0:fd45411cac49 200 sessionrecordinit();
marcbax 0:fd45411cac49 201
marcbax 0:fd45411cac49 202 //initialise substance menu
marcbax 0:fd45411cac49 203 fillsubstancemenu();
marcbax 0:fd45411cac49 204
marcbax 0:fd45411cac49 205 //enter info in logfile.csv
marcbax 0:fd45411cac49 206 fprintf(logfile, "%s\r", bufferd); //writes date, time and firmware version
marcbax 0:fd45411cac49 207 fprintf(logfile, "%s\r", buffert);
marcbax 0:fd45411cac49 208 fprintf(logfile, "v%s\r", fwversion);
marcbax 0:fd45411cac49 209
marcbax 0:fd45411cac49 210 beeponce(); //three beeps to signal initialisation ready
marcbax 0:fd45411cac49 211 }
marcbax 0:fd45411cac49 212
marcbax 0:fd45411cac49 213 //Returns the index of the selected substance menu item
marcbax 0:fd45411cac49 214 int subchoice(submenuitem submenu[11]) {
marcbax 0:fd45411cac49 215 bool up, down, done;
marcbax 0:fd45411cac49 216 int i;
marcbax 0:fd45411cac49 217 up = down = done = 0;
marcbax 0:fd45411cac49 218 i = 0;
marcbax 0:fd45411cac49 219 cleardisplay();
marcbax 0:fd45411cac49 220 display.printf("Substance selection");
marcbax 0:fd45411cac49 221 wait(3);
marcbax 0:fd45411cac49 222 cleardisplay();
marcbax 0:fd45411cac49 223 while (!done) {
marcbax 0:fd45411cac49 224 display.printf("%s\r", submenu[i].displaystring);
marcbax 0:fd45411cac49 225 display.printf("\rUP/DOWN to scroll\rOK to select");
marcbax 0:fd45411cac49 226 while (!up && !down && !done) {
marcbax 0:fd45411cac49 227 up = !upsw;
marcbax 0:fd45411cac49 228 down = !dnsw;
marcbax 0:fd45411cac49 229 done = !oksw;
marcbax 0:fd45411cac49 230 }
marcbax 0:fd45411cac49 231 if (up) {
marcbax 0:fd45411cac49 232 i++;
marcbax 0:fd45411cac49 233 if (i==11) i = 0;
marcbax 0:fd45411cac49 234 }
marcbax 0:fd45411cac49 235 if (down) {
marcbax 0:fd45411cac49 236 if (i==0) i = 11;
marcbax 0:fd45411cac49 237 i--;
marcbax 0:fd45411cac49 238 }
marcbax 0:fd45411cac49 239 cleardisplay();
marcbax 0:fd45411cac49 240 }
marcbax 0:fd45411cac49 241 return i;
marcbax 0:fd45411cac49 242 }
marcbax 0:fd45411cac49 243
marcbax 0:fd45411cac49 244 //Converts the last 4 digits in the serial number string into a integer 0-9999
marcbax 0:fd45411cac49 245 int serialstring2int(char bser[8]) {
marcbax 0:fd45411cac49 246 int tempserial = 0;
marcbax 0:fd45411cac49 247 tempserial = tempserial + (bser[4]-0x30)*1000; //5th digit is thousands
marcbax 0:fd45411cac49 248 tempserial = tempserial + (bser[5]-0x30)*100; //6th digit is hundreds
marcbax 0:fd45411cac49 249 tempserial = tempserial + (bser[6]-0x30)*10; //7th digit is tens
marcbax 0:fd45411cac49 250 tempserial = tempserial + (bser[7]-0x30); //8th digit is units
marcbax 0:fd45411cac49 251 return tempserial;
marcbax 0:fd45411cac49 252 }
marcbax 0:fd45411cac49 253
marcbax 0:fd45411cac49 254 //beeholder resets on rising edge of select line
marcbax 0:fd45411cac49 255 void resetbeeholder() { //need this as mounting beeholder causes undefined start of beeholder firmware
marcbax 0:fd45411cac49 256 bhsel1 = bhsel2 = 0;
marcbax 0:fd45411cac49 257 wait(0.1);
marcbax 0:fd45411cac49 258 bhsel1 = bhsel2 = 1;
marcbax 0:fd45411cac49 259 wait(0.3);
marcbax 0:fd45411cac49 260 }
marcbax 0:fd45411cac49 261
marcbax 0:fd45411cac49 262 //Reads beeholder serial number from station 1 or 2
marcbax 0:fd45411cac49 263 int getserialno(int station) {
marcbax 0:fd45411cac49 264 char bser[8]; //define 8-byte serial number string to read
marcbax 0:fd45411cac49 265 resetbeeholder(); //does not work without this!!
marcbax 0:fd45411cac49 266 for (int i=0;i<8;i++) bser[i]=0x30;
marcbax 0:fd45411cac49 267 if (station==1) bhsel1=0; //pull select line station 1 low
marcbax 0:fd45411cac49 268 if (station==2) bhsel2=0; //pull select line station 2 low
marcbax 0:fd45411cac49 269 wait(0.2);
marcbax 0:fd45411cac49 270 beeholder.stop(); //I2C stop condition
marcbax 0:fd45411cac49 271 wait(0.2); //delay for beeholder to respond
marcbax 0:fd45411cac49 272 beeholder.write(addr,0x0,1); //initial write before read
marcbax 0:fd45411cac49 273 beeholder.read(addr,bser,8); //read 8 byte serial number
marcbax 0:fd45411cac49 274 bhsel1 = bhsel2= 1; //pull both select lines high
marcbax 0:fd45411cac49 275 int serialno = serialstring2int(bser); //translate serial number string to integer
marcbax 0:fd45411cac49 276 return serialno;
marcbax 0:fd45411cac49 277 }
marcbax 0:fd45411cac49 278
marcbax 0:fd45411cac49 279 //Returns 1 if a PER is detected on this beeholder within timeout seconds
marcbax 0:fd45411cac49 280 int detectPER(int station, float timeout) {
marcbax 0:fd45411cac49 281 Timer ttotal, tper;
marcbax 0:fd45411cac49 282 ttotal.start(); //start timers for time-out and PER-detect
marcbax 0:fd45411cac49 283 ttotal.reset();
marcbax 0:fd45411cac49 284 tper.start();
marcbax 0:fd45411cac49 285 tper.reset();
marcbax 0:fd45411cac49 286 if (station == 1) {
marcbax 0:fd45411cac49 287 while ((ttotal.read() < timeout) && (tper.read() < PERtime)) { //loop until timeout or PER detected
marcbax 0:fd45411cac49 288 wait_ms(10);
marcbax 0:fd45411cac49 289 if (ptor1 * 3.3 < PERsetval) tper.reset(); //if phototransistor voltage below treshold keep PER timer in reset
marcbax 0:fd45411cac49 290 //if above treshold let timer run until it reaches PERtime
marcbax 0:fd45411cac49 291 }
marcbax 0:fd45411cac49 292 }
marcbax 0:fd45411cac49 293 if (station == 2) {
marcbax 0:fd45411cac49 294 while ((ttotal.read() < timeout) && (tper.read() < PERtime)) {
marcbax 0:fd45411cac49 295 if (ptor2 * 3.3 < PERsetval) tper.reset();
marcbax 0:fd45411cac49 296 }
marcbax 0:fd45411cac49 297 }
marcbax 0:fd45411cac49 298 ttotal.stop();
marcbax 0:fd45411cac49 299 tper.stop();
marcbax 0:fd45411cac49 300 return (tper.read() >= PERtime); //if the loop exit condition was a PER, return a TRUE value
marcbax 0:fd45411cac49 301 }
marcbax 0:fd45411cac49 302
marcbax 0:fd45411cac49 303 //Checks if bee shows PER when stimulated with odour but without feeding
marcbax 0:fd45411cac49 304 int checktrained(int station) {
marcbax 0:fd45411cac49 305 airswitcher = 1;
marcbax 0:fd45411cac49 306 int responded = detectPER(station, 6); //PER needs to be detected within 6 seconds
marcbax 0:fd45411cac49 307 airswitcher = 0;
marcbax 0:fd45411cac49 308 return responded;
marcbax 0:fd45411cac49 309 }
marcbax 0:fd45411cac49 310
marcbax 0:fd45411cac49 311 //Function performs beeholder/IR-led calibration
marcbax 0:fd45411cac49 312 float calibrate(int station, int runs) {
marcbax 0:fd45411cac49 313 float tempcal;
marcbax 0:fd45411cac49 314 tempcal=0.5; //start calibration at 50% voltage
marcbax 0:fd45411cac49 315 irLED=tempcal;
marcbax 0:fd45411cac49 316 float calstep; //start calstep at 25% voltage
marcbax 0:fd45411cac49 317 calstep = tempcal/2;
marcbax 0:fd45411cac49 318 for (int i=0; i<10; i++) { //does a "10-bit binary search" for the correct voltage to get a good response
marcbax 0:fd45411cac49 319 irLED = tempcal;
marcbax 0:fd45411cac49 320 wait(0.1); //important to allow AD converter to settle
marcbax 0:fd45411cac49 321 if (ptor1 < calsetval/3.3) { //check phototransistor voltage against desired value
marcbax 0:fd45411cac49 322 tempcal = tempcal - calstep; //if phototransistor voltage is too low then reduce brightness
marcbax 0:fd45411cac49 323 }
marcbax 0:fd45411cac49 324 else {
marcbax 0:fd45411cac49 325 tempcal = tempcal + calstep; //if phototransistor voltage is too high then increase brightness
marcbax 0:fd45411cac49 326 }
marcbax 0:fd45411cac49 327 calstep = calstep/2; //on each loop of the for-cycle make smaller changes to IR LED voltage
marcbax 0:fd45411cac49 328 }
marcbax 0:fd45411cac49 329 float calib;
marcbax 0:fd45411cac49 330 calib = tempcal; //set preliminary calibration to the value just measured
marcbax 0:fd45411cac49 331 for (int j=1; j<runs; j++) { //run another j-1 runs, this corrects for antennae-movement as
marcbax 0:fd45411cac49 332 tempcal=0.5; //we use the lowest calibration value from j runs
marcbax 0:fd45411cac49 333 irLED=tempcal; //this is similar to what we do in the cassettes
marcbax 0:fd45411cac49 334 calstep = tempcal/2;
marcbax 0:fd45411cac49 335 for (int i=0;i<10;i++) {
marcbax 0:fd45411cac49 336 irLED = tempcal;
marcbax 0:fd45411cac49 337 wait(0.1);
marcbax 0:fd45411cac49 338 if (ptor1 < calsetval/3.3) {
marcbax 0:fd45411cac49 339 tempcal = tempcal - calstep;
marcbax 0:fd45411cac49 340 }
marcbax 0:fd45411cac49 341 else {
marcbax 0:fd45411cac49 342 tempcal = tempcal + calstep;
marcbax 0:fd45411cac49 343 }
marcbax 0:fd45411cac49 344 calstep = calstep/2;
marcbax 0:fd45411cac49 345 }
marcbax 0:fd45411cac49 346 if (tempcal < calib) calib = tempcal; //use the lowest of j calibration values
marcbax 0:fd45411cac49 347 }
marcbax 0:fd45411cac49 348 return calib;
marcbax 0:fd45411cac49 349 }
marcbax 0:fd45411cac49 350
marcbax 0:fd45411cac49 351 //switches the IR LED on at the right brightness level for the beeholder
marcbax 0:fd45411cac49 352 void IRledON(int i) {
marcbax 0:fd45411cac49 353 irLED = sessionrecord[i].calvalue;
marcbax 0:fd45411cac49 354 }
marcbax 0:fd45411cac49 355
marcbax 0:fd45411cac49 356 //moves arm1 to a position in a specified time, allowing speed control
marcbax 0:fd45411cac49 357 void arm1move (float endpos, float movetime) {
marcbax 0:fd45411cac49 358 float startpos = arm1.read();
marcbax 0:fd45411cac49 359 int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
marcbax 0:fd45411cac49 360 for (int i=0; i<numsteps; i++) {
marcbax 0:fd45411cac49 361 arm1 = startpos + i * (endpos - startpos)/numsteps;
marcbax 0:fd45411cac49 362 wait(movetime/numsteps);
marcbax 0:fd45411cac49 363 }
marcbax 0:fd45411cac49 364 arm1 = endpos;
marcbax 0:fd45411cac49 365 }
marcbax 0:fd45411cac49 366
marcbax 0:fd45411cac49 367 //moves arm2 to a position in a specified time, allowing speed control
marcbax 0:fd45411cac49 368 void arm2move (float endpos, float movetime) {
marcbax 0:fd45411cac49 369 float startpos = arm2.read();
marcbax 0:fd45411cac49 370 int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
marcbax 0:fd45411cac49 371 for (int i=0; i<numsteps; i++) {
marcbax 0:fd45411cac49 372 arm2 = startpos + i * (endpos - startpos)/numsteps;
marcbax 0:fd45411cac49 373 wait(movetime/numsteps);
marcbax 0:fd45411cac49 374 }
marcbax 0:fd45411cac49 375 arm2 = endpos;
marcbax 0:fd45411cac49 376 }
marcbax 0:fd45411cac49 377
marcbax 0:fd45411cac49 378 //moves elbow1 to a position in a specified time, allowing speed control
marcbax 0:fd45411cac49 379 void elbow1move (float endpos, float movetime) {
marcbax 0:fd45411cac49 380 float startpos = elbow1.read();
marcbax 0:fd45411cac49 381 int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
marcbax 0:fd45411cac49 382 for (int i=0; i<numsteps; i++) {
marcbax 0:fd45411cac49 383 elbow1 = startpos + i * (endpos - startpos)/numsteps;
marcbax 0:fd45411cac49 384 wait(movetime/numsteps);
marcbax 0:fd45411cac49 385 }
marcbax 0:fd45411cac49 386 elbow1 = endpos;
marcbax 0:fd45411cac49 387 }
marcbax 0:fd45411cac49 388
marcbax 0:fd45411cac49 389 //moves elbow2 to a position in a specified time, allowing speed control
marcbax 0:fd45411cac49 390 void elbow2move (float endpos, float movetime) {
marcbax 0:fd45411cac49 391 float startpos = elbow2.read();
marcbax 0:fd45411cac49 392 int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
marcbax 0:fd45411cac49 393 for (int i=0; i<numsteps; i++) {
marcbax 0:fd45411cac49 394 elbow2 = startpos + i * (endpos - startpos)/numsteps;
marcbax 0:fd45411cac49 395 wait(movetime/numsteps);
marcbax 0:fd45411cac49 396 }
marcbax 0:fd45411cac49 397 elbow2 = endpos;
marcbax 0:fd45411cac49 398 }
marcbax 0:fd45411cac49 399
marcbax 0:fd45411cac49 400 //Performs a conditioning cycle. if tickle==0, no tickling takes place. Return==1 if a PER has been detected
marcbax 0:fd45411cac49 401 int condcycle(int station, int tickle) {
marcbax 0:fd45411cac49 402 int perseen;
marcbax 0:fd45411cac49 403 perseen = 0;
marcbax 0:fd45411cac49 404 //for station 1
marcbax 0:fd45411cac49 405 if (station == 1) {
marcbax 0:fd45411cac49 406 //dip brush
marcbax 0:fd45411cac49 407 arm1move(arm1dippos, 0.5);
marcbax 0:fd45411cac49 408 elbow1move(elbow1dippos, 0.3);
marcbax 0:fd45411cac49 409 wait(diptime);
marcbax 0:fd45411cac49 410 elbow1move(elbow1basepos, 0.3);
marcbax 0:fd45411cac49 411 arm1move(arm1basepos, 0.5);
marcbax 0:fd45411cac49 412 //switch air to supply trace vapour
marcbax 0:fd45411cac49 413 airswitcher = 1; //air contains target vapour
marcbax 0:fd45411cac49 414 display.printf("Vapour ON");
marcbax 0:fd45411cac49 415 wait (0.5);
marcbax 0:fd45411cac49 416 //tickle
marcbax 0:fd45411cac49 417 if (tickle) { //if tickling, first tickle then wait for PER or timeout
marcbax 0:fd45411cac49 418 elbow1move(elbow1ticklepos, 0.2);
marcbax 0:fd45411cac49 419 arm1move(arm1ticklepos, 1.5); //slower move of arm towards bee
marcbax 0:fd45411cac49 420 perseen = detectPER(1, tickletimeout); //tickle until timeout or PER detected
marcbax 0:fd45411cac49 421 }
marcbax 0:fd45411cac49 422 //or not tickle
marcbax 0:fd45411cac49 423 else {
marcbax 0:fd45411cac49 424 perseen = detectPER(1, tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position
marcbax 0:fd45411cac49 425 arm1move(arm1ticklepos-0.05, 1); //move to position between LED and holder
marcbax 0:fd45411cac49 426 elbow1move(elbow1ticklepos, 0.3);
marcbax 0:fd45411cac49 427 }
marcbax 0:fd45411cac49 428 //feeding only if you have tickled or a PER has been detected
marcbax 0:fd45411cac49 429 if (tickle || perseen) { //only feed if a PER has been detector, or "tickle" is true
marcbax 0:fd45411cac49 430 elbow1move(elbow1feedpos, 0.3);
marcbax 0:fd45411cac49 431 arm1move(arm1feedpos, 0.3);
marcbax 0:fd45411cac49 432 wait(feedtime);
marcbax 0:fd45411cac49 433 arm1move(arm1ticklepos -0.05, 0.3);
marcbax 0:fd45411cac49 434 elbow1move(elbow1ticklepos, 0.3);
marcbax 0:fd45411cac49 435 }
marcbax 0:fd45411cac49 436 //move back to base position
marcbax 0:fd45411cac49 437 arm1 = arm1basepos; //use fast move here
marcbax 0:fd45411cac49 438 elbow1 = elbow1basepos; //use fast move here
marcbax 0:fd45411cac49 439 airswitcher = 0; //air valve to clean air
marcbax 0:fd45411cac49 440 display.printf("\e[DFF\r"); //rewrite "ON" to "OFF" on display
marcbax 0:fd45411cac49 441 }
marcbax 0:fd45411cac49 442 //for station 2
marcbax 0:fd45411cac49 443 if (station == 2) {
marcbax 0:fd45411cac49 444 //dip brush
marcbax 0:fd45411cac49 445 arm2move(arm2dippos, 0.5);
marcbax 0:fd45411cac49 446 elbow2move(elbow2dippos, 0.3);
marcbax 0:fd45411cac49 447 wait(diptime);
marcbax 0:fd45411cac49 448 elbow2move(elbow2basepos, 0.3);
marcbax 0:fd45411cac49 449 arm2move(arm2basepos, 0.5);
marcbax 0:fd45411cac49 450 //switch air to supply trace vapour
marcbax 0:fd45411cac49 451 //airswitcher = 1; //no air switching for station 2
marcbax 0:fd45411cac49 452 wait (0.5);
marcbax 0:fd45411cac49 453 //tickle
marcbax 0:fd45411cac49 454 if (tickle) { //if tickling, first tickle then wait for PER or timeout
marcbax 0:fd45411cac49 455 elbow2move(elbow2ticklepos, 0.2);
marcbax 0:fd45411cac49 456 arm2move(arm2ticklepos, 1.5); //slower move of arm towards bee
marcbax 0:fd45411cac49 457 perseen = detectPER(1, tickletimeout); //tickle until timeout or PER detected
marcbax 0:fd45411cac49 458 }
marcbax 0:fd45411cac49 459 //or not tickle
marcbax 0:fd45411cac49 460 else {
marcbax 0:fd45411cac49 461 perseen = detectPER(1, tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position
marcbax 0:fd45411cac49 462 arm2move(arm2ticklepos-0.05, 1); //move to position between LED and holder
marcbax 0:fd45411cac49 463 elbow2move(elbow2ticklepos, 0.3);
marcbax 0:fd45411cac49 464 }
marcbax 0:fd45411cac49 465 //feeding only if you have tickled or a PER has been detected
marcbax 0:fd45411cac49 466 if (tickle || perseen) { //only feed if a PER has been detector, or "tickle" is true
marcbax 0:fd45411cac49 467 elbow2move(elbow2feedpos, 0.3);
marcbax 0:fd45411cac49 468 arm2move(arm2feedpos, 0.3);
marcbax 0:fd45411cac49 469 wait(feedtime);
marcbax 0:fd45411cac49 470 arm2move(arm2ticklepos -0.05, 0.3);
marcbax 0:fd45411cac49 471 elbow2move(elbow2ticklepos, 0.3);
marcbax 0:fd45411cac49 472 }
marcbax 0:fd45411cac49 473 //move back to base position
marcbax 0:fd45411cac49 474 arm2 = arm2basepos;
marcbax 0:fd45411cac49 475 elbow2 = elbow2basepos;
marcbax 0:fd45411cac49 476 }
marcbax 0:fd45411cac49 477 return perseen;
marcbax 0:fd45411cac49 478 }
marcbax 0:fd45411cac49 479
marcbax 0:fd45411cac49 480 //User to input choice between station 1 and 2 for this session
marcbax 0:fd45411cac49 481 int stationchoice() {
marcbax 0:fd45411cac49 482 int station;
marcbax 0:fd45411cac49 483 station = 1;
marcbax 0:fd45411cac49 484 cleardisplay(); //clear screen and home cursor
marcbax 0:fd45411cac49 485 display.printf(" Station selection ");
marcbax 0:fd45411cac49 486 display.printf("Left=1 2=Right");
marcbax 0:fd45411cac49 487 while (lesw && risw) { //lesw and risw become false when pressed!
marcbax 0:fd45411cac49 488 wait(0.02);
marcbax 0:fd45411cac49 489 if (!lesw) station=1; //on LEFT select station 1
marcbax 0:fd45411cac49 490 if (!risw) station=2; //on RIGHT select station 2
marcbax 0:fd45411cac49 491 }
marcbax 0:fd45411cac49 492 display.printf("\rStation %1u selected", station);
marcbax 0:fd45411cac49 493 fprintf(logfile, "%3u, station selected\r", station);
marcbax 0:fd45411cac49 494 return station;
marcbax 0:fd45411cac49 495 }
marcbax 0:fd45411cac49 496
marcbax 0:fd45411cac49 497 //Registers and calibrates all beeholders used in this session
marcbax 0:fd45411cac49 498 int registerbeeholders() {
marcbax 0:fd45411cac49 499 int i;
marcbax 0:fd45411cac49 500 bool done;
marcbax 0:fd45411cac49 501 char buffert[30];
marcbax 0:fd45411cac49 502 i = done = 0;
marcbax 0:fd45411cac49 503 cleardisplay(); //clear screen and home cursor
marcbax 0:fd45411cac49 504 fprintf(logfile, "calibration record:\r");
marcbax 0:fd45411cac49 505 fprintf(logfile, "i, serialno, LED V, time\r");
marcbax 0:fd45411cac49 506 while (i<30 && !done) { //register and calibrate a maximum of 30 beeholders
marcbax 0:fd45411cac49 507 display.printf("calibrating %u\r",i+1);
marcbax 0:fd45411cac49 508 sessionrecord[i].serialno = getserialno(station); //read serial number
marcbax 0:fd45411cac49 509 if (sessionrecord[i].serialno != 0) { //check if serial number correctly read - if not it will be 0000
marcbax 0:fd45411cac49 510 sessionrecord[i].calvalue = calibrate(station, 5); //5 calibration cycles
marcbax 0:fd45411cac49 511 if ((sessionrecord[i].calvalue > 0.25) && (sessionrecord[i].calvalue < 0.97)) { //check that calvalue is in expected range
marcbax 0:fd45411cac49 512 sessionrecord[i].tstamp = time(NULL); //create timestamp NOW
marcbax 0:fd45411cac49 513 strftime(buffert, 20, "%X", localtime(&sessionrecord[i].tstamp)); //formats time part of timestamp
marcbax 0:fd45411cac49 514 cleardisplay();
marcbax 0:fd45411cac49 515 display.printf("SN %4u - cal %4.2fV\r", sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3);
marcbax 0:fd45411cac49 516 display.printf("OK for next\r");
marcbax 0:fd45411cac49 517 display.printf("DOWN for training");
marcbax 0:fd45411cac49 518 fprintf(logfile, "%4u,%6u,%6.2f, %s, calibrate\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
marcbax 0:fd45411cac49 519 i++;
marcbax 0:fd45411cac49 520 }
marcbax 0:fd45411cac49 521 else {
marcbax 0:fd45411cac49 522 cleardisplay();
marcbax 0:fd45411cac49 523 display.printf("SN %4u - cal %4.2fV\r", sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3);
marcbax 0:fd45411cac49 524 display.printf("Cal out of range!\r");
marcbax 0:fd45411cac49 525 multibeeps(2,0.5);
marcbax 0:fd45411cac49 526 display.printf("OK to recalibrate\r");
marcbax 0:fd45411cac49 527 fprintf(logfile, "%4u,%6u,%6.2f, %s, out of range\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
marcbax 0:fd45411cac49 528 }
marcbax 0:fd45411cac49 529 while (!done && oksw) { //loop until OK or DOWN are pressed
marcbax 0:fd45411cac49 530 wait(0.02);
marcbax 0:fd45411cac49 531 done = !dnsw; //DOWN exits registration cycle and moves to training
marcbax 0:fd45411cac49 532 }
marcbax 0:fd45411cac49 533 }
marcbax 0:fd45411cac49 534 else { //retry when serialno can't be read (is 0000)
marcbax 0:fd45411cac49 535 cleardisplay();
marcbax 0:fd45411cac49 536 multibeeps(3,0.3); //beep-beep-beep when beeholder not correctly read
marcbax 0:fd45411cac49 537 display.printf("invalid serial no\r");
marcbax 0:fd45411cac49 538 display.printf("reseat beeholder\r");
marcbax 0:fd45411cac49 539 display.printf("press OK");
marcbax 0:fd45411cac49 540 while (oksw) wait(0.02); //loop until OK is pressed to start calibration loop again
marcbax 0:fd45411cac49 541 }
marcbax 0:fd45411cac49 542 cleardisplay();
marcbax 0:fd45411cac49 543 }
marcbax 0:fd45411cac49 544 return i; //upon done condition, i== number of beeholders calibrated
marcbax 0:fd45411cac49 545 }
marcbax 0:fd45411cac49 546
marcbax 0:fd45411cac49 547 //gets holderrecord for the holder with a certain serial number
marcbax 0:fd45411cac49 548 int getholderindex(int serialno) {
marcbax 0:fd45411cac49 549 for (int i=0; i<numbeeholders; i++) { //reverse lookup of index for a certain serial number
marcbax 0:fd45411cac49 550 if (sessionrecord[i].serialno == serialno) return i;
marcbax 0:fd45411cac49 551 }
marcbax 0:fd45411cac49 552 return 29; //if the record is not found, returns i==29
marcbax 0:fd45411cac49 553 }
marcbax 0:fd45411cac49 554
marcbax 0:fd45411cac49 555 //all the elements making up a single training cycle with one beeholder
marcbax 0:fd45411cac49 556 void trainingcycle() {
marcbax 0:fd45411cac49 557 wait(0.2);
marcbax 0:fd45411cac49 558 time_t tstamp = time(NULL); //create timestamp NOW
marcbax 0:fd45411cac49 559 char buffert[30];
marcbax 0:fd45411cac49 560 strftime(buffert, 20, "%X", localtime(&tstamp)); //format timestamp to time string
marcbax 0:fd45411cac49 561 bool invalidserial;
marcbax 0:fd45411cac49 562 invalidserial = 1;
marcbax 0:fd45411cac49 563 int serialno;
marcbax 0:fd45411cac49 564 serialno = 0;
marcbax 0:fd45411cac49 565 while (invalidserial) { //loop until a serial number is read correctly
marcbax 0:fd45411cac49 566 cleardisplay();
marcbax 0:fd45411cac49 567 int serialno = getserialno(station); //read serial number
marcbax 0:fd45411cac49 568 invalidserial = (serialno == 0); //if the serialno is 0, then it's invalid
marcbax 0:fd45411cac49 569 if (invalidserial) {
marcbax 0:fd45411cac49 570 display.printf("Invalid serialno\rReseat holder\rUP to retry");
marcbax 0:fd45411cac49 571 while (upsw) wait(0.02); //loop until UP switch is pressed
marcbax 0:fd45411cac49 572 }
marcbax 0:fd45411cac49 573 }
marcbax 0:fd45411cac49 574 int i = getholderindex(serialno); //get index i for serial number
marcbax 0:fd45411cac49 575 IRledON(i); //switch IR LED on at correct brightness
marcbax 0:fd45411cac49 576 sessionrecord[i].cycleno++; //increment cycle number for this beeholder
marcbax 0:fd45411cac49 577 cleardisplay();
marcbax 0:fd45411cac49 578 display.printf("SN: %4u, cycle %u\r", serialno, sessionrecord[i].cycleno);
marcbax 0:fd45411cac49 579 sessionrecord[i].reslastcycle = condcycle(station, sessionrecord[i].ticklenextcycle); //do a conditioning cycle
marcbax 0:fd45411cac49 580 fprintf(logfile, "%s,",buffert);
marcbax 0:fd45411cac49 581 fprintf(logfile, " %4u,",serialno);
marcbax 0:fd45411cac49 582 fprintf(logfile, " %2u,", sessionrecord[i].cycleno);
marcbax 0:fd45411cac49 583 if (sessionrecord[i].reslastcycle) { //log PER or TimeOut
marcbax 0:fd45411cac49 584 fprintf(logfile, " PER,");
marcbax 0:fd45411cac49 585 }
marcbax 0:fd45411cac49 586 else {
marcbax 0:fd45411cac49 587 fprintf(logfile, " TO,");
marcbax 0:fd45411cac49 588 }
marcbax 0:fd45411cac49 589 fprintf(logfile, " training\r");
marcbax 0:fd45411cac49 590 if (sessionrecord[i].reslastcycle) {
marcbax 0:fd45411cac49 591 display.printf("PER detected\r");
marcbax 0:fd45411cac49 592 }
marcbax 0:fd45411cac49 593 else {
marcbax 0:fd45411cac49 594 display.printf("PER time-out\r");
marcbax 0:fd45411cac49 595 }
marcbax 0:fd45411cac49 596 display.printf("mount holder + OK\r");
marcbax 0:fd45411cac49 597 display.printf("DOWN to finish");
marcbax 0:fd45411cac49 598 }
marcbax 0:fd45411cac49 599
marcbax 0:fd45411cac49 600 //main program
marcbax 0:fd45411cac49 601 int main() {
marcbax 0:fd45411cac49 602 initialise(); //initialise a new session
marcbax 0:fd45411cac49 603
marcbax 0:fd45411cac49 604 //Choose which station this session will use
marcbax 0:fd45411cac49 605 station = stationchoice (); //menu to let user select station 1 or 2
marcbax 0:fd45411cac49 606 cleardisplay();
marcbax 0:fd45411cac49 607
marcbax 0:fd45411cac49 608 //Choose substance string
marcbax 0:fd45411cac49 609 substanceindex = subchoice(submenu); //menu to let use chose substance
marcbax 0:fd45411cac49 610 fprintf(logfile, "%s\r", submenu[substanceindex].logstring); //prints the substance log string to the logfile
marcbax 0:fd45411cac49 611
marcbax 0:fd45411cac49 612 //Register and calibrate beeholders used in this session
marcbax 0:fd45411cac49 613 display.printf("Now register holders\r");
marcbax 0:fd45411cac49 614 display.printf("seat first holder\rpress OK\r");
marcbax 0:fd45411cac49 615 while (oksw) wait(0.02); //loop so first beeholder can be mounted, then OK pressed
marcbax 0:fd45411cac49 616 numbeeholders = registerbeeholders();
marcbax 0:fd45411cac49 617 display.printf("%2u holders entered\r", numbeeholders);
marcbax 0:fd45411cac49 618 wait(3);
marcbax 0:fd45411cac49 619 cleardisplay();
marcbax 0:fd45411cac49 620
marcbax 0:fd45411cac49 621 //Conduct training
marcbax 0:fd45411cac49 622 display.printf("Start training cycle\r");
marcbax 0:fd45411cac49 623 display.printf("mount holder + OK\r");
marcbax 0:fd45411cac49 624 display.printf("DOWN to finish");
marcbax 0:fd45411cac49 625 fprintf(logfile, "Training started\r");
marcbax 0:fd45411cac49 626 fprintf(logfile, "time, serial, cycleno, result\r");
marcbax 0:fd45411cac49 627 wait(1);
marcbax 0:fd45411cac49 628 InterruptIn oksw(p17); //redefine OK and footswitch as interrupts
marcbax 0:fd45411cac49 629 oksw.mode(PullUp);
marcbax 0:fd45411cac49 630 bool finishsession;
marcbax 0:fd45411cac49 631 finishsession = 0;
marcbax 0:fd45411cac49 632 oksw.fall(&trainingcycle); //call subroutine "trainingcycle" on OK/footswitch interrupt
marcbax 0:fd45411cac49 633 while (!finishsession) { //loop while servicing interrupts
marcbax 0:fd45411cac49 634 wait(0.02);
marcbax 0:fd45411cac49 635 finishsession = !dnsw; //until DOWN button is pressed, which exits to program close
marcbax 0:fd45411cac49 636 }
marcbax 0:fd45411cac49 637
marcbax 0:fd45411cac49 638 //Close logfile
marcbax 0:fd45411cac49 639 fprintf(logfile, "session closed");
marcbax 0:fd45411cac49 640 fclose(logfile); //close logfile for reading
marcbax 0:fd45411cac49 641 cleardisplay();
marcbax 0:fd45411cac49 642 display.printf("Session finished\r\rdownload etonlog.csvand rename");
marcbax 0:fd45411cac49 643 }