Alvaro Cassinelli / Mbed 2 deprecated skinGames_forktest

Dependencies:   mbed

Fork of scoreLight_Advanced 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  InterruptIn switchTwo(SWITCH_TWO); 
00020  AnalogIn ainPot(POT_ANALOG_INPUT);  
00021  //DigitalIn RotaryEncoderPinA(ROTARY_ENCODER_PINA); // not needed: this is done in the CRotaryEncoder library (as input or interrupt)
00022  //DigitalIn RotaryEncoderPinB(ROTARY_ENCODER_PINB);
00023  
00024  DigitalIn twoStateSwitch(TWO_STATE_SWITCH);
00025 
00026 void HardwareIO::init(void) {
00027 
00028     // Set laser powers down:
00029     setRedPower(0);// TTL red laser (not used - actually not present)
00030     setGreenPower(0);
00031     setBluePower(0);
00032     
00033     //Serial Communication setup:
00034     pc.baud(115200);//
00035     //pc.printf("Serial Connection established \r\n");
00036    //  pc.baud(921600);//115200);//
00037     
00038     // Setup for lock-in amplifier and pwm references:
00039     setLaserLockinPower(1);// actually this is the Red laser in the hardware
00040     lockin.init();
00041     
00042     // Setup for DAC control to move the mirrors:
00043     // Set spi for 8 bit data, high steady state clock,
00044     // second edge capture, with a 10MHz clock rate:
00045      csDAC = 1; 
00046     spiDAC.format(16,0);
00047     spiDAC.frequency(16000000);
00048    
00049    // default initial mirror position: 
00050     writeOutX(CENTER_AD_MIRROR_X);
00051     writeOutY(CENTER_AD_MIRROR_Y);
00052     
00053     // Rotary encoder 1 (to set the FIXED THRESHOLD VALUE): 
00054     rotaryEncoder1.SetMinMax(0,255);
00055     rotaryEncoder1.Set(0); // initial value
00056     
00057      // Rotary encoder 2 (to set the additional correction angle):   
00058     rotaryEncoder2.SetMinMax(-10,10);
00059     rotaryEncoder2.Set(0); // initial value
00060     
00061     // Load LUT table:
00062     setLUT();
00063     
00064     // Set interrupts on RAISING edge for button-switch functions:
00065     // 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. 
00066     // By default, the InterruptIn is setup with an internal pull-down resistor, but for security and clarity I will do it explicitly here:
00067     switchOne.mode(PullUp); // pull down seems not very good
00068     switchTwo.mode(PullUp);
00069     switchOne.fall(this, &HardwareIO::switchOneInterrupt);  // attach the address of the flip function to the falling edge
00070     switchTwo.fall(this, &HardwareIO::switchTwoInterrupt);  // attach the address of the flip function to the falling edge
00071     switchOneState=true; 
00072     switchTwoState=false;
00073     switchOneChange=false;
00074     switchTwoChange=false;
00075   
00076   // ATTENTION: initial state of the switch should correspond to the inital state of the threshold mode in the constructor of the laser trajectory objects (not nice):
00077     setSwitchOneState(true); //equal to switchOneState=true, plus set led value. False means fixed threshold, true AUTO THRESHOLD (will be the default mode)
00078     // NOTE: actually this interrupt switches are not used anymore to change threhold... 
00079      
00080     // Initial state of the two state switch (and don't forget to set the internal pullup resistors!):
00081     twoStateSwitch.mode(PullUp);// Use internal pullup for pushbutton
00082     twoStateSwitchState=twoStateSwitch.read(); // attention: twoStateSwitch is actually a method (this is equal to twoStateSwitch.read());
00083     twoStateSwitchChange=true; // this will force reading the initial threshold mode the first time the program runs
00084     
00085     // Read and update pot value:
00086    // updatePotValue(); // the value will be ajusted in the range 0-255
00087 }
00088 
00089 void HardwareIO::setSwitchOneState(bool newstate) {
00090     switchOneState=newstate; 
00091     //ledSwitchOne=(switchOneState? 1 :0); 
00092 }
00093 
00094 // these ISR could do more (like debouncing). 
00095 // For the time being, I will debounce electrically with a small capacitor. 
00096 void HardwareIO::switchOneInterrupt() {
00097     switchOneState=!switchOneState;
00098     switchOneChange=true;
00099 }
00100 
00101 void HardwareIO::switchTwoInterrupt() {
00102     switchTwoState=!switchTwoState;
00103     switchTwoChange=true;
00104 }
00105 
00106 bool HardwareIO::switchOneCheck(bool& new_state) {
00107     new_state=switchOneState;
00108     if (switchOneChange) {
00109         switchOneChange=false;
00110         return(true);
00111     } else     
00112     return(false);
00113 }
00114 
00115 bool HardwareIO::switchTwoCheck(bool& new_state) {
00116     new_state=switchTwoState;
00117     if (switchTwoChange) {
00118         switchTwoChange=false;
00119         return(true);
00120     } else return(false);
00121 }
00122 
00123 // NOT interrupt-based switch:
00124 bool HardwareIO::twoStateSwitchCheck(bool& new_state) {
00125     new_state=twoStateSwitch; // note: twoStateSwitch is a method!
00126     if (twoStateSwitchState==new_state) {
00127         // this means that the switch did not change state:
00128         return(false);
00129     } else {
00130         twoStateSwitchState=new_state;
00131         return(true);
00132     }
00133 }
00134     
00135 
00136 // THIS IS NOT WORKING!!!!!!
00137 unsigned char HardwareIO::updatePotValue() { // this will update the pot value, and return it too.
00138    //The value will be ajusted in the range 0-255
00139     //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.
00140 
00141  //   potValue=(unsigned char )(ainPot*255);
00142    // Attention: go back to burst mode:
00143  //   lockin.setADC_forLockin(1);
00144  //   wait(1);
00145 
00146  //USING the adc library: 
00147     // unset fast adc for lockin, and set normal adc for conversion from analog input pin:
00148     lockin.setADC_forLockin(0);
00149    // wait(1);
00150 
00151     //Measure pin POT_ANALOG_INPUT
00152     adc.select(POT_ANALOG_INPUT);
00153     //Start ADC conversion
00154     adc.start();
00155     //Wait for it to complete
00156     while(!adc.done(POT_ANALOG_INPUT));
00157     potValue=adc.read(POT_ANALOG_INPUT);
00158 
00159     //Unset pin POT_ANALOG_INPUT
00160     adc.setup(POT_ANALOG_INPUT,0);
00161 
00162     lockin.setADC_forLockin(1);
00163     wait(0.5);
00164     
00165     return(potValue);
00166 }
00167 
00168 //write on the first DAC, output A (mirror X)
00169 void HardwareIO::writeOutX(unsigned short value){
00170  if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS;
00171  if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS;
00172  
00173  value |= 0x7000;
00174  value &= 0x7FFF;
00175  
00176  csDAC = 0; // this means the chip is enabled (negated logic), so CLK and SDI (data) can be transfered
00177  spiDAC.write(value);
00178  csDAC = 1; // rising the pin actually writes the data in the corresponding DAC register...
00179 }
00180 
00181 //write on the first DAC, output B (mirror Y)
00182 void HardwareIO::writeOutY(unsigned short value){
00183  if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS;
00184  if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS;
00185  
00186  value |= 0xF000;
00187  value &= 0xFFFF;
00188  
00189  csDAC = 0;
00190  spiDAC.write(value);
00191  csDAC = 1;
00192 }
00193 
00194 void HardwareIO::setLaserLockinPower(int powerValue){
00195     if(powerValue > 0){
00196        lockin.setLaserPower(true);
00197     }
00198     else{
00199        lockin.setLaserPower(false);
00200     }
00201 }
00202 // THE TTL controlled lasers:
00203 // Note: the red one is not used here
00204 void HardwareIO::setRedPower(int powerValue){
00205     if(powerValue > 0){
00206         Laser_Red = 1;
00207     }
00208     else{
00209         Laser_Red = 0;
00210     }
00211 }
00212 void HardwareIO::setGreenPower(int powerValue){
00213     if(powerValue > 0){
00214         Laser_Green = 1;
00215     }
00216     else{
00217         Laser_Green = 0;
00218     }
00219 }
00220 void HardwareIO::setBluePower(int powerValue){
00221     if(powerValue > 0){
00222         Laser_Blue = 1;
00223     }
00224     else{
00225         Laser_Blue = 0;
00226     }
00227 }
00228 
00229 void HardwareIO::setRGBPower(unsigned char color) {
00230     lockin.setLaserPower((color&0x04)>0? true : false); // NOTE: here the "red" is the lockin laser, not the TTL one (not used yet)
00231     Laser_Green=(color&0x02)>>1;
00232     Laser_Blue =color&0x01;
00233 }
00234 
00235 void HardwareIO::showLimitsMirrors(int seconds) {
00236       unsigned short pointsPerLine=150;
00237       int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00238       int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00239    
00240       Laser_Green=1;
00241    
00242      //for (int repeat=0; repeat<times; repeat++) {
00243      
00244      Timer t;
00245      t.start();
00246      while(t.read_ms()<seconds*1000) {
00247        
00248       writeOutX(MIN_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS);
00249    
00250       for(int j=0; j<pointsPerLine; j++){   
00251        wait_us(200);//delay between each points
00252        writeOutY(j*shiftY + MIN_AD_MIRRORS);
00253        }
00254       
00255       writeOutX(MIN_AD_MIRRORS);writeOutY(MAX_AD_MIRRORS);
00256       for(int j=0; j<pointsPerLine; j++) {
00257          wait_us(200);//delay between each points
00258          writeOutX(j*shiftX + MIN_AD_MIRRORS);
00259          }
00260       
00261       writeOutX(MAX_AD_MIRRORS);writeOutY(MAX_AD_MIRRORS);
00262       for(int j=0; j<pointsPerLine; j++) {
00263          wait_us(200);//delay between each points
00264          writeOutY(-j*shiftX + MAX_AD_MIRRORS);
00265          }
00266       
00267        writeOutX(MAX_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS);
00268       for(int j=0; j<pointsPerLine; j++) {
00269          wait_us(200);//delay between each points
00270          writeOutX(-j*shiftX + MAX_AD_MIRRORS);
00271          }
00272       
00273       }
00274       t.stop();
00275       Laser_Green=0;
00276 }
00277 
00278 void HardwareIO::scan_serial(unsigned short pointsPerLine){
00279       //scan the total surface with a custom resolution
00280       //send the lockin value for each point as a byte on the serial port to the PC
00281       //use "scanSLP_save" to see the data on processing
00282       // First, set the red laser on, and other off:
00283       setRGBPower(0x4);
00284       wait_us(1000); // just to give time to the lockin to set
00285        
00286       int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00287       int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine;
00288       
00289       for(int j=0; j<pointsPerLine; j++){
00290         writeOutX(MIN_AD_MIRRORS);
00291         writeOutY(j*shiftY + MIN_AD_MIRRORS);
00292         
00293         wait_us(300);//begining of line delay
00294         for(int i=0; i<pointsPerLine; i++){
00295           writeOutX(i*shiftX + MIN_AD_MIRRORS);
00296 
00297           wait_us(200);//delay between each points
00298           
00299           // SEND A VALUE BETWEEN 0 and 255:
00300           pc.putc(int(255.0*lockin.getMedianValue()/4095));//printf("%dL",int(valueLockin*255));//pc.putc(int(lockin*255));//
00301         }
00302       }
00303 }
00304 
00305 //load Look-up Table from LUT.TXT file
00306 //or create the file with scanLUT() if not existing.
00307 void HardwareIO::setLUT(){
00308 
00309     FILE *fp = fopen(LUT_FILENAME, "r");  // Open file on the local file system for writing
00310     if(fp){
00311         //load the file into the lut table; keep the SAME resolution!
00312         fread(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp);
00313         fclose(fp);
00314     }
00315     else{
00316         //fclose(fp);
00317         //if the file "LUT.TXT" doesn't exist, create one with scanLUT()
00318         lockin.setLaserPower(true);
00319         scanLUT();
00320     }
00321     
00322 }
00323 
00324 //scan the total surface with a fixed 2^x resolution
00325 //create the Look-Up Table used to "flatten" the scan according to the position
00326 //
00327 //To Do: maybe detect high frequency to be sure the area is clean and empty?
00328 void HardwareIO::scanLUT(){
00329 
00330     //reset lut table
00331     for(int j=0; j<LUT_RESOLUTION; j++){
00332       for(int i=0; i<LUT_RESOLUTION; i++){
00333         lut[i][j] =0;
00334       }
00335     }
00336     
00337     int delayScanning = 300; //in us
00338     
00339     //define the distance between each points (from 0 to 4096) and the offset (here 0)
00340     float shiftX = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1);
00341     float shiftY = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1);
00342     float offsetX = MIN_AD_MIRRORS;
00343     float offsetY = MIN_AD_MIRRORS;
00344     
00345     //move the mirrors to the first position
00346     writeOutX(MAX_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS);
00347     wait_us(500);
00348       
00349     float x, y;
00350     
00351     //scan the surface NB_SCANS times 
00352     //the total value in lut[i][j] shouldn't exceed uint16 !!! 
00353     for(int loop=0; loop<NB_SCANS; loop++){
00354       for(int j=0; j<LUT_RESOLUTION; j++){
00355         y = shiftY*j + offsetY ;
00356         writeOutY(int(y));
00357         //scan from right to left
00358         for(int i=LUT_RESOLUTION-1; i>=0; i--){
00359           x = shiftX*i + offsetX;
00360           writeOutX(int(x));
00361           wait_us(delayScanning);
00362           lut[i][j] += lockin_read();
00363         }
00364         //re-scan from left to right
00365         for(int i=0; i<LUT_RESOLUTION; i++){
00366           x = shiftX*i + offsetX;
00367           writeOutX(int(x));
00368           wait_us(delayScanning);
00369           lut[i][j] += lockin_read();
00370         }
00371       }
00372     }
00373     
00374     
00375     //save tab in file
00376     FILE *fp;
00377 #ifdef LUT_FILENAME
00378     fp = fopen(LUT_FILENAME, "w");  // Open file on the local file system for writing
00379     fwrite(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp);
00380     fclose(fp); //close the file (the mBed will appear connected again)
00381 #endif
00382     
00383 #ifdef LUT_H_FILENAME    
00384     //save tab in Human readable file (not used by the program, this is just for checking)
00385     // NOTE: we divide the content of the lut table by NB_SCANS, for easy reading (values should be between 0-4095)
00386     fp = fopen(LUT_H_FILENAME, "w");  // Open file on the local file system for writing
00387     fprintf(fp, "scan resolution: %d x %d\r\n",LUT_RESOLUTION, LUT_RESOLUTION);
00388     for(int j=0; j<LUT_RESOLUTION; j++){
00389       for(int i=0; i<LUT_RESOLUTION; i++){
00390             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) );
00391       }
00392     }
00393     fclose(fp); //close the file (the mBed will appear connected again)
00394 #endif
00395     
00396 }
00397 
00398 
00399 //Return the lockin value "corrected with the Look-UpTable" - this means a RATIO between two reflectivities (and normally, this is <1). 
00400 float HardwareIO::lockInCorrectedValue(unsigned short x, unsigned short y){
00401 //*******Correction using DIRECT approximation
00402 #ifdef LUT_DIRECT
00403     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)
00404 #endif 
00405 
00406 //*******Correction using BILINEAR approximation
00407 #ifdef LUT_BILINEAR
00408     unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17
00409     unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17
00410     float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 
00411     float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm)
00412     
00413     //Wheighted mean approximation of the Look-Up Table at the position (x,y):
00414     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] );
00415     
00416     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)   
00417 #endif
00418 
00419 //*******Correction using LINEAR approximation
00420 #ifdef LUT_LINEAR
00421     unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17
00422     unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17
00423     float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 
00424     float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm)
00425     float linearLUT, dzx, dzy;
00426     
00427     if(dx>dy){ //if the position is on the "top-right" triangle
00428         dzx = (lut[X+1][Y] - lut[X][Y]) * dx;
00429         dzy = (lut[X+1][Y+1] - lut[X+1][Y]) * dy;
00430     }
00431     else{ //if the position is on the "bottom-left" triangle
00432         dzy = (lut[X][Y+1] - lut[X][Y]) * dy;
00433         dzx = (lut[X+1][Y+1] - lut[X][Y+1]) * dx;
00434     }
00435     
00436     //linear approximation of the Look-Up Table at the position (x,y):
00437     linearLUT = lut[X][Y] + dzx + dzy;
00438     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)
00439     
00440 #endif
00441 
00442 //*******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)
00443 #ifdef NO_LUT
00444     return 1.0* lockin_read()/4096;
00445 #endif 
00446 
00447 }