Marc Bax
/
EtonBreadboard_090
main.cpp@0:fd45411cac49, 2011-03-28 (annotated)
- Committer:
- marcbax
- Date:
- Mon Mar 28 07:15:14 2011 +0000
- Revision:
- 0:fd45411cac49
v0.90
Who changed what in which revision?
User | Revision | Line number | New 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 | } |