Alvaro Cassinelli / Mbed 2 deprecated laserUI

Dependencies:   mbed

Fork of skinGames_forktest by Alvaro Cassinelli

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hardwareIO.cpp Source File

hardwareIO.cpp

00001 #include "hardwareIO.h"
00002 
00003 HardwareIO IO; // preintantiation of cross-file global object IO
00004 
00005 // --------------------------------------  (0) SETUP ALL IO (call this in the setup() function in main program)
00006 
00007 Serial pc(USBTX, USBRX); // tx, rx
00008 LocalFileSystem local("local");               // Create the local filesystem under the name "local"
00009 
00010 SPI spiDAC(MOSI_PIN, MISO_PIN, SCK_PIN); // mosi, miso, sclk
00011 DigitalOut csDAC(CS_DAC_MIRRORS);
00012 
00013 DigitalOut Laser_Red(LASER_RED_PIN); // NOTE: this is NOT the lock in sensing laser (actually, not used yet)
00014 DigitalOut Laser_Green(LASER_GREEN_PIN);
00015 DigitalOut Laser_Blue(LASER_BLUE_PIN);
00016 
00017 // Some manual controls over the hardware function:
00018 InterruptIn switchOne(SWITCH_ONE);
00019 DigitalOut ledSwitchOne(LED_SWITCH_ONE);
00020 InterruptIn switchTwo(SWITCH_TWO);
00021 AnalogIn ainPot(POT_ANALOG_INPUT);   // I cannot use this directly because the adc is being used by the locking. We have to re-setup it (see updatePotValue())
00022 
00023 // Testing leds (for debugging):
00024 DigitalOut myLed1(LED1); // note: LED1/2/3/4 are defined in mbed.h, and correspond to mbed pins 32, 34, 35 and 37
00025 DigitalOut myLed2(LED2);
00026 DigitalOut myLed3(LED3);
00027 DigitalOut myLed4(LED4);
00028 
00029 void HardwareIO::init(void)
00030 {
00031     setLaserLockinPower(1); // this may be always ON (the IR laser). But we may want to switch it off sometimes...
00032     Laser_Red = 0; // note: this is not the lockin-laser! (in the future, the lock in laser will be infrared...)
00033     Laser_Green = 0;
00034     Laser_Blue = 0;
00035 
00036     // Test leds:
00037     myLed1=0;
00038     myLed2=0;
00039     myLed3=0;
00040     myLed4=0;
00041 
00042     //Serial Communication setup:
00043     pc.baud(SERIAL_SPEED);
00044 
00045     // Setup for lock-in amplifier and pwm references:
00046     setLaserLockinPower(1);// actually this is the Red laser in the hardware
00047     lockin.init();
00048 
00049     // Setup for DAC control to move the mirrors:
00050     // Set spi for 8 bit data, high steady state clock,
00051     // second edge capture, with a 10MHz clock rate:
00052     csDAC = 1;
00053     spiDAC.format(16,0);
00054     spiDAC.frequency(16000000);
00055 
00056     // default initial mirror position:
00057     writeOutX(CENTER_AD_MIRROR_X);
00058     writeOutY(CENTER_AD_MIRROR_Y);
00059 
00060     // Load LUT table:
00061     setLUT();
00062 
00063     // Set interrupts on RAISING edge for button-switch functions:
00064     // Note: The pin input will be logic '0' for any voltage on the pin below 0.8v, and '1' for any voltage above 2.0v.
00065     // By default, the InterruptIn is setup with an internal pull-down resistor, but for security and clarity I will do it explicitly here:
00066     switchOne.mode(PullUp); // pull down seems not very good
00067     switchTwo.mode(PullUp);
00068     switchOne.fall(this, &HardwareIO::switchOneInterrupt);  // attach the address of the flip function to the falling edge
00069     switchTwo.fall(this, &HardwareIO::switchTwoInterrupt);  // attach the address of the flip function to the falling edge
00070     switchOneState=true;
00071     switchTwoState=false;
00072     switchOneChange=false;
00073     switchTwoChange=false;
00074 
00075     setSwitchOneState(true); //equal to switchOneState=true, plus set led value. False means fixed threshold, true AUTO THRESHOLD (will be the default mode)
00076 
00077     // Read and update pot value:
00078     // updatePotValue(); // the value will be ajusted in the range 0-255
00079 }
00080 
00081 void HardwareIO::setSwitchOneState(bool newstate)
00082 {
00083     switchOneState=newstate;
00084     ledSwitchOne=(switchOneState? 1 :0);
00085 }
00086 
00087 // these ISR could do more (like debouncing).
00088 // For the time being, I will debounce electrically with a small capacitor.
00089 void HardwareIO::switchOneInterrupt()
00090 {
00091     switchOneState=!switchOneState;
00092     ledSwitchOne=(switchOneState? 1 :0); // this switch has a built-in led
00093     switchOneChange=true;
00094 }
00095 void HardwareIO::switchTwoInterrupt()
00096 {
00097     switchTwoState=!switchTwoState;
00098     switchTwoChange=true;
00099 }
00100 
00101 bool HardwareIO::switchOneCheck(bool& state)
00102 {
00103     if (switchOneChange) {
00104         switchOneChange=false;
00105         state=switchOneState;
00106         return(true);
00107     } else
00108         return(false);
00109 }
00110 
00111 bool HardwareIO::switchTwoCheck(bool& state)
00112 {
00113     if (switchTwoChange) {
00114         switchTwoChange=false;
00115         state=switchTwoState;
00116         return(true);
00117     } else return(false);
00118 }
00119 
00120 unsigned char HardwareIO::updatePotValue()   // this will update the pot value, and return it too.
00121 {
00122     //The value will be ajusted in the range 0-255
00123     //The 0.0v to 3.3v range of the AnalogIn is represented in software as a normalised floating point number from 0.0 to 1.0.
00124     potValue=(unsigned char )(ainPot*255);
00125 
00126 /* USING the adc library: 
00127     // unset fast adc for lockin, and set normal adc for conversion from analog input pin:
00128     lockin.setADC_forLockin(0);
00129     adc.setup(POT_ANALOG_INPUT,1);
00130 
00131     wait(1);
00132 
00133     //Measure pin POT_ANALOG_INPUT
00134     adc.select(POT_ANALOG_INPUT);
00135     //Start ADC conversion
00136     adc.start();
00137     //Wait for it to complete
00138     while(!adc.done(POT_ANALOG_INPUT));
00139     potValue=adc.read(POT_ANALOG_INPUT);
00140 
00141     //Unset pin POT_ANALOG_INPUT
00142     adc.setup(POT_ANALOG_INPUT,0);
00143 
00144     lockin.setADC_forLockin(1);
00145     // wait(1);
00146 */
00147 
00148  // Attention! reading using the AnalogIn library seems to break my burst reading mode. So, we need to re-set it: 
00149     lockin.setADC_forLockin(1);
00150     
00151     return(potValue);
00152 }
00153 
00154 //write on the first DAC, output A (mirror X)
00155 void HardwareIO::writeOutX(unsigned short value)
00156 {
00157     if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS;
00158     if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS;
00159 
00160     value |= 0x7000;
00161     value &= 0x7FFF;
00162 
00163     csDAC = 0;
00164     spiDAC.write(value);
00165     csDAC = 1;
00166 }
00167 
00168 //write on the first DAC, output B (mirror Y)
00169 void HardwareIO::writeOutY(unsigned short value)
00170 {
00171     if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS;
00172     if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS;
00173 
00174     value |= 0xF000;
00175     value &= 0xFFFF;
00176 
00177     csDAC = 0;
00178     spiDAC.write(value);
00179     csDAC = 1;
00180 }
00181 
00182 void HardwareIO::setLaserLockinPower(int powerValue)
00183 {
00184     if(powerValue > 0) {
00185         lockin.setLaserPower(true);
00186     } else {
00187         lockin.setLaserPower(false);
00188     }
00189 }
00190 
00191 void HardwareIO::setRedPower(int powerValue)
00192 {
00193     if(powerValue > 0) {
00194         Laser_Red = 1;
00195     } else {
00196         Laser_Red = 0;
00197     }
00198 }
00199 void HardwareIO::setGreenPower(int powerValue)
00200 {
00201     if(powerValue > 0) {
00202         Laser_Green = 1;
00203     } else {
00204         Laser_Green = 0;
00205     }
00206 }
00207 void HardwareIO::setBluePower(int powerValue)
00208 {
00209     if(powerValue > 0) {
00210         Laser_Blue = 1;
00211     } else {
00212         Laser_Blue = 0;
00213     }
00214 }
00215 
00216 
00217 void HardwareIO::setRGBPower(unsigned char color)  // NOTE: this do NOT affect the power of the lockin laser...
00218 {
00219     // lockin.setLaserPower((color&0x04)>0? true : false);
00220     Laser_Red=(color&0x04)>>2;
00221     Laser_Green=(color&0x02)>>1;
00222     Laser_Blue =color&0x01;
00223 }
00224 
00225 // Attention: we should stop the displaying engine lsd before calling this (if we want, otherwise it will continue showing the
00226 // displayed objects/scene, but it will be weird) - this is done in the WRAPPERS methods.
00227 void HardwareIO::showLimitsMirrors(unsigned short pointsPerLine, unsigned short durationSecs)
00228 {
00229     //unsigned short pointsPerLine=150;
00230     int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00231     int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00232 
00233     setRGBPower(0x07);// all displaying lasers ON
00234 
00235     //for (int repeat=0; repeat<times; repeat++) {
00236 
00237     Timer t;
00238     t.start();
00239     while(t.read_ms()<durationSecs*1000) {
00240 
00241         writeOutX(MIN_AD_MIRRORS);
00242         writeOutY(MIN_AD_MIRRORS);
00243 
00244         for(int j=0; j<pointsPerLine; j++) {
00245             wait_us(200);//delay between each points
00246             writeOutY(j*shiftY + MIN_AD_MIRRORS);
00247         }
00248 
00249         writeOutX(MIN_AD_MIRRORS);
00250         writeOutY(MAX_AD_MIRRORS);
00251         for(int j=0; j<pointsPerLine; j++) {
00252             wait_us(200);//delay between each points
00253             writeOutX(j*shiftX + MIN_AD_MIRRORS);
00254         }
00255 
00256         writeOutX(MAX_AD_MIRRORS);
00257         writeOutY(MAX_AD_MIRRORS);
00258         for(int j=0; j<pointsPerLine; j++) {
00259             wait_us(200);//delay between each points
00260             writeOutY(-j*shiftX + MAX_AD_MIRRORS);
00261         }
00262 
00263         writeOutX(MAX_AD_MIRRORS);
00264         writeOutY(MIN_AD_MIRRORS);
00265         for(int j=0; j<pointsPerLine; j++) {
00266             wait_us(200);//delay between each points
00267             writeOutX(-j*shiftX + MAX_AD_MIRRORS);
00268         }
00269 
00270     }
00271     t.stop();
00272     Laser_Green=0;
00273 }
00274 
00275 void HardwareIO::scan_serial(unsigned short pointsPerLine)
00276 {
00277     //scan the total surface with a custom resolution
00278     //send the lockin value for each point as a byte on the serial port to the PC
00279     //use "scanSLP_save" to see the data on processing
00280 
00281     int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00282     int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00283 
00284     for(int j=0; j<pointsPerLine; j++) {
00285         writeOutX(MIN_AD_MIRRORS);
00286         writeOutY(j*shiftY + MIN_AD_MIRRORS);
00287 
00288         wait_us(300);//begining of line delay
00289         for(int i=0; i<pointsPerLine; i++) {
00290             writeOutX(i*shiftX + MIN_AD_MIRRORS);
00291 
00292             wait_us(200);//delay between each points
00293 
00294             // SEND A VALUE BETWEEN 0 and 255:
00295             pc.putc(int(255.0*lockin.getMedianValue()/4095));//printf("%dL",int(valueLockin*255));//pc.putc(int(lockin*255));//
00296         }
00297     }
00298 }
00299 
00300 //load Look-up Table from LUT.TXT file
00301 //or create the file with scanLUT() if not existing.
00302 void HardwareIO::setLUT()
00303 {
00304 
00305     FILE *fp = fopen(LUT_FILENAME, "r");  // Open file on the local file system for writing
00306     if(fp) {
00307         //load the file into the lut table; keep the SAME resolution!
00308         fread(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp);
00309         fclose(fp);
00310     } else {
00311         //fclose(fp);
00312         //if the file "LUT.TXT" doesn't exist, create one with scanLUT()
00313         lockin.setLaserPower(true);
00314         scanLUT();
00315     }
00316 
00317 }
00318 
00319 //scan the total surface with a fixed 2^x resolution
00320 //create the Look-Up Table used to "flatten" the scan according to the position
00321 //
00322 //To Do: maybe detect high frequency to be sure the area is clean and empty?
00323 void HardwareIO::scanLUT()
00324 {
00325 
00326     //reset lut table
00327     for(int j=0; j<LUT_RESOLUTION; j++) {
00328         for(int i=0; i<LUT_RESOLUTION; i++) {
00329             lut[i][j] =0;
00330         }
00331     }
00332 
00333     int delayScanning = 300; //in us
00334 
00335     //define the distance between each points (from 0 to 4096) and the offset (here 0)
00336     float shiftX = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1);
00337     float shiftY = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1);
00338     float offsetX = MIN_AD_MIRRORS;
00339     float offsetY = MIN_AD_MIRRORS;
00340 
00341     //move the mirrors to the first position
00342     writeOutX(MAX_AD_MIRRORS);
00343     writeOutY(MIN_AD_MIRRORS);
00344     wait_us(500);
00345 
00346     float x, y;
00347 
00348     //scan the surface NB_SCANS times
00349     //the total value in lut[i][j] shouldn't exceed uint16 !!!
00350     for(int loop=0; loop<NB_SCANS; loop++) {
00351         for(int j=0; j<LUT_RESOLUTION; j++) {
00352             y = shiftY*j + offsetY ;
00353             writeOutY(int(y));
00354             //scan from right to left
00355             for(int i=LUT_RESOLUTION-1; i>=0; i--) {
00356                 x = shiftX*i + offsetX;
00357                 writeOutX(int(x));
00358                 wait_us(delayScanning);
00359                 lut[i][j] += lockin_read();
00360             }
00361             //re-scan from left to right
00362             for(int i=0; i<LUT_RESOLUTION; i++) {
00363                 x = shiftX*i + offsetX;
00364                 writeOutX(int(x));
00365                 wait_us(delayScanning);
00366                 lut[i][j] += lockin_read();
00367             }
00368         }
00369     }
00370 
00371 
00372     //save tab in file
00373     FILE *fp;
00374 #ifdef LUT_FILENAME
00375     fp = fopen(LUT_FILENAME, "w");  // Open file on the local file system for writing
00376     fwrite(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp);
00377     fclose(fp); //close the file (the mBed will appear connected again)
00378 #endif
00379 
00380 #ifdef LUT_H_FILENAME
00381     //save tab in Human readable file (not used by the program, this is just for checking)
00382     // NOTE: we divide the content of the lut table by NB_SCANS, for easy reading (values should be between 0-4095)
00383     fp = fopen(LUT_H_FILENAME, "w");  // Open file on the local file system for writing
00384     fprintf(fp, "scan resolution: %d x %d\r\n",LUT_RESOLUTION, LUT_RESOLUTION);
00385     for(int j=0; j<LUT_RESOLUTION; j++) {
00386         for(int i=0; i<LUT_RESOLUTION; i++) {
00387             fprintf(fp, "X=%d,\tY=%d,\tI=%d\t \r\n", int(shiftX*i + offsetX), int(shiftY*j + offsetY), int(1.0*lut[i][j]/NB_SCANS) );
00388         }
00389     }
00390     fclose(fp); //close the file (the mBed will appear connected again)
00391 #endif
00392 
00393 }
00394 
00395 
00396 //Return the lockin value "corrected with the Look-UpTable" - this means a RATIO between two reflectivities (and normally, this is <1).
00397 float HardwareIO::lockInCorrectedValue(unsigned short x, unsigned short y)
00398 {
00399 //*******Correction using DIRECT approximation
00400 #ifdef LUT_DIRECT
00401     return 2.0* NB_SCANS * lockin_read() / (lut[x >> LUT_BITS_SHIFT][y >> LUT_BITS_SHIFT]); // 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left)
00402 #endif
00403 
00404 //*******Correction using BILINEAR approximation
00405 #ifdef LUT_BILINEAR
00406     unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17
00407     unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17
00408     float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm)
00409     float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm)
00410 
00411     //Wheighted mean approximation of the Look-Up Table at the position (x,y):
00412     float wmLUT = (1-dy)*( (1-dx)*lut[X][Y] + dx*lut[X+1][Y] ) + dy*( (1-dx)*lut[X][Y+1] + dx*lut[X+1][Y+1] );
00413 
00414     return 2.0* NB_SCANS * lockin_read() / wmLUT;// 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left)
00415 #endif
00416 
00417 //*******Correction using LINEAR approximation
00418 #ifdef LUT_LINEAR
00419     unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17
00420     unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17
00421     float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm)
00422     float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm)
00423     float linearLUT, dzx, dzy;
00424 
00425     if(dx>dy) { //if the position is on the "top-right" triangle
00426         dzx = (lut[X+1][Y] - lut[X][Y]) * dx;
00427         dzy = (lut[X+1][Y+1] - lut[X+1][Y]) * dy;
00428     } else { //if the position is on the "bottom-left" triangle
00429         dzy = (lut[X][Y+1] - lut[X][Y]) * dy;
00430         dzx = (lut[X+1][Y+1] - lut[X][Y+1]) * dx;
00431     }
00432 
00433     //linear approximation of the Look-Up Table at the position (x,y):
00434     linearLUT = lut[X][Y] + dzx + dzy;
00435     return 2.0* NB_SCANS * lockin_read() / linearLUT; // 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left)
00436 
00437 #endif
00438 
00439 //*******No corrections, just return the value divided by 4096 (this means we are assuming that the surface is everywhere perfectly reflective - we supposedly get the max value always)
00440 #ifdef NO_LUT
00441     return 1.0* lockin_read()/4096;
00442 #endif
00443 
00444 }
00445