Trackball based on the NXP LPC11U24 and the ADNS-9500

Dependencies:   ADNS9500 USBDevice mbed 25LCxxx_SPI

main.cpp

Committer:
xxann5
Date:
2013-03-14
Revision:
9:ee05aa95f5c9
Parent:
8:5674f5ab61cd

File content as of revision 9:ee05aa95f5c9:

/* 
 *  loststone is free sofware: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License 3 as published by
 *  the Free Software Foundation.
 *
 *  loststone is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with loststone. If not, see <http://www.gnu.org/licenses/gpl.txt>.
 *
 *  Copyright (c) 2012-2013 Chris Majoros(chris@majoros.us), GNU3
 */

#include "main.h"


int main(void)
{
    
    printf("And away we go.\n\r");
    activity = 1;
    run_mode.mode(PullUp);
    Ser25LCxxx *eeprom;
    
    #ifdef MBED
    SPI eeprom_spi( p11, p12, p13); // mosi, miso, sclk 
    #elif
    SPI eeprom_spi( P0_21, P0_22, P1_20); // mosi, miso, sclk 
    #endif
    
    eeprom_spi.format(8,3);
    eeprom_spi.frequency(1000000);
    
    #ifdef MBED
    eeprom = new Ser25LCxxx( &eeprom_spi, p15, 0x10000, 0x20 ); 
    #elif
    eeprom = new Ser25LCxxx( &eeprom_spi, P1_27, 0x10000, 0x20 ); 
    #endif

    //retreave default and system settings from the EEPROM and override the default values.
    printf("Loading settings\n\r");
    for( int i = 0; i < sizeof(s)/sizeof(uint16_t); i++ ){
        printf("Setting %d: %X\r\n", i, s[i]);
        //set_setting( eeprom, i, s[i], SETTINGS_BASE ); 
        //s[i] = get_setting( eeprom, i, SETTINGS_BASE );
        printf("Setting %d: %X\r\n", i, s[i]);
    }
    
    //eeprom->write( s[ADNS_FW_OFFSET], ADNS9500_FIRMWARE_LEN, adns9500FWArray );
    
    if( run_mode ){
        printf("Tracking mode\n\r");
        track( eeprom );
    }
    else{
        printf("Programming mode\n\r");
        program( eeprom );
    }
}

void track( Ser25LCxxx *eeprom ){
    activity = 0;
    /* 
    * mosi miso sclk ncs FREQ, motion
    */
    mouse = new USBMouse( REL_MOUSE, s[VID], s[PID], s[RELEASE]) ;

    /* 
     * mosi == p5 / P0_9
     * miso == p6 / P0_8
     * sclk == p7 / P0_10
     * ncs  == p8 / P1_16
     * spi_frequency = MAX_SPI_FREQUENCY
     * motion == p14 / P0_22
     */

    printf("Creating sensor object\n\r");
    #ifdef MBED
    adns9500::ADNS9500 sensor(p5, p6, p7, p8, adns9500::MAX_SPI_FREQUENCY);
    #elif
    adns9500::ADNS9500 sensor(P0_9, P0_8, P0_10, P1_16, adns9500::MAX_SPI_FREQUENCY); 
    #endif
    
    static fn press_funcs[] = {
        btn_l_press,
        btn_m_press,
        btn_r_press,
        btn_f_press,
        btn_b_press,
        btn_z_press,
        btn_hr_press};
        
    static fn release_funcs[] = {
        btn_l_release,
        btn_m_release,
        btn_r_release,
        btn_f_release,
        btn_b_release,
        btn_z_release,
        btn_hr_release};
        
    printf("Inisializing buttons\n\r");

// Mouse buttons 
    btn_a.mode(PullNone);
    btn_a.fall(press_funcs[s[BTN_A]]);
    btn_a.rise(release_funcs[s[BTN_A]]);
    
    btn_b.mode(PullNone);
    btn_b.fall(press_funcs[s[BTN_B]]);
    btn_b.rise(release_funcs[s[BTN_B]]);

    btn_c.mode(PullNone);
    btn_c.fall(press_funcs[s[BTN_C]]);
    btn_c.rise(release_funcs[s[BTN_C]]);
    
    btn_d.mode(PullNone);
    btn_d.fall(press_funcs[s[BTN_D]]);
    btn_d.rise(release_funcs[s[BTN_D]]);
    
    btn_e.mode(PullNone);
    btn_e.fall(press_funcs[s[BTN_E]]);
    btn_e.rise(release_funcs[s[BTN_E]]);
    
    btn_f.mode(PullNone);
    btn_f.fall(press_funcs[s[BTN_F]]);
    btn_f.rise(release_funcs[s[BTN_F]]);

    btn_g.mode(PullNone);
    btn_g.fall(press_funcs[s[BTN_G]]);
    btn_g.rise(release_funcs[s[BTN_G]]);

// Profile buttons
    prfl_a.mode(PullUp);
    prfl_a.fall(&prfl_a_set);
    prfl_a.rise(&prfl_stub);
    
    prfl_b.mode(PullUp);
    prfl_b.fall(&prfl_b_set);
    prfl_b.rise(&prfl_stub);
    
    prfl_c.mode(PullUp);
    prfl_c.fall(&prfl_c_set);
    prfl_c.rise(&prfl_stub);
    
    prfl_d.mode(PullUp);
    prfl_d.fall(&prfl_d_set);
    prfl_d.rise(&prfl_stub);
    
    prfl_e.mode(PullUp);
    prfl_e.fall(&prfl_e_set);
    prfl_e.rise(&prfl_stub);
    
    debug.mode(PullUp);
    debug.fall(&debug_out);
    debug.rise(&debug_out);
    
    int16_t dx, dy;
    float mx, my;

    sensor.reset();

    uint8_t *adns_fw;

    //eeprom->write(ADNS_FW_OFFSET, ADNS_FW_LEN, adns9500FWArray);
    //adns_fw = eeprom->read( ADNS_FW_OFFSET, ADNS_FW_LEN );
//eeprom->write( s[ADNS_FW_OFFSET], ADNS9500_FIRMWARE_LEN, adns9500FWArray );

    activity = 1;
    printf("Loading sensor firmware\r\n");
    uint16_t crc = sensor.sromDownload( adns9500FWArray, ADNS9500_FIRMWARE_LEN ); //FIXME

    if( ADNS6010_FIRMWARE_CRC != crc ){ //ADNS6010_FIRMWARE_CRC
        printf("Firmware CRC does not match [%X] [%X]\n\r",
               ADNS6010_FIRMWARE_CRC,
               crc);             
        while (true){
            activity = 0;
            wait(0.2);
            activity = 1;
            wait(0.2);
        }
    }
    else{
        activity = 0;
        printf("Firmware CRC matches [%X] [%X]\n\r",
           ADNS6010_FIRMWARE_CRC,
           crc);
    }

    // The firmware was set correctly. Freeing the 3K! of ram.
    //delete adns_fw;

    printf("Enableing lazer\n\r");
    sensor.enableLaser();
    sensor.setResolution( s[CPI_X], s[CPI_Y] );

    printf("Starting Loop\n\r");
    activity = 1;
    //rest_counter = 0;
    while (true){
        //rest_counter++;
        /*
         * Moved the setResolution calls out of the interupt callbacks as they
         * havequite a few waits in them. I am hopping this is the reasion why
         * the hr and z buttons on occation stick or don't work the first time
         * you press them.
         */
        if( set_res_hr ){
            printf("Setting High hez\n\r");
            set_res_hr = false;
            sensor.setResolution( s[CPI_HR_X], s[CPI_HR_Y] );
        }
        
        if( set_res_z ){
            printf("Setting Z rez\n\r");
            set_res_z = false;
            sensor.setResolution( s[CPI_Z], s[CPI_H] );
        }
        
        if( set_res_default ){
            printf("Setting default rez\n\r");
            set_res_default = false;
            sensor.setResolution( s[CPI_X], s[CPI_Y] );
        }
              
        if( !motion_in){

            motion_triggered = false;

            sensor.getMotionDelta(dx, dy);
            if( dx == 0 and dy == 0 ){
                // FIXME: why is the ADNS9500 dropping the motion pin and then
                // giving me no motion? Do I have somthing wired up wrong?
                continue;
            }
            /*
             * The sensor is not aware of its orientation so we need to muck
             * with the values a it.
             */
            if( z_axis_active ){
                printf("scroll,%X,%X,\n\r", -dx, dy);
                mouse->scroll( dy, - dx );
            }
            else{
                
                mx = (float(abs(dx))/float(s[CPI_X_MULITIPLYER]) + 1.0);
                my = (float(abs(dy))/float(s[CPI_Y_MULITIPLYER]) + 1.0);
                
                printf("motion,%X,%X %.4f,%.4f %X,%X\n\r", -dx, dy, mx, my, int(- (dx * mx)), int(dy * my) );

                mouse->move( - (dx * mx), (dy * my) ); 
                //printf("rest_coutner,%d\n\r", rest_counter);
                //rest_counter = 0;
            }
        }
        

        // Load the current profile.
        // This rights the first 10 16bit values of the s array from the selected profile.
        //
        // Base is calculated...
        //     selected profile * profile length * 2 + profile base
        //
        //     (3 * 7 * 2) + 64  (multiplying by two because they are 16bit values.
        // TODO: should i move this to a function?
        if( profile_load ){
        //    for( int i = 0; i < PROFILE_LEN; i++ ){
        //        //s[i] = get_setting( eeprom, i, (s[PROFILE_CURRENT] * PROFILE_LEN) + PROFILE_BASE );
        //    }
        //    sensor.setResolution( s[CPI_X], s[CPI_Y] );
            profile_load = false;
        }
    }
}

void program( Ser25LCxxx *eeprom ){

    
    //USBHID *hid = new USBHID( 64, 64, 0x192f, 0x0, 0x0);
    USBHID *hid = new USBHID();
    //This report will contain data to be sent
    HID_REPORT send_rep;
    HID_REPORT recv_rep;
    
    send_rep.length = 64;
    uint16_t base;
    uint16_t len;
    //Fill the report
    for (int i = 0; i < send_rep.length; i++) {
        send_rep.data[i] = rand() & 0xff;
    }
            
    //Send the report
    //hid->send(&send_rep);

    uint8_t *tmp;

    printf("Entering loop\n\r");
    while (1) {
        if( hid->readNB(&recv_rep)) {
            printf("Receaved some data.\n\r");
            switch ((recv_rep.data[0])){
                case SET:
                    //set_setting( eeprom, recv_rep.data[1], UINT16(recv_rep.data[2],recv_rep.data[3]));
                    break;
                case GET:
                    //tmp = get_setting( eeprom, recv_rep.data[1] );
                        
                    //send_rep.data[0] = (int)tmp;
                    //send_rep.data[1] = (int)(tmp >> 8);
                        
                    //hid->send(&send_rep);
                    
                    break;
                case CLEAR:
                    //clear_setting( eeprom, recv_rep.data[1] );
                    break;
                case INIT:
                    eeprom->clearMem();
                    break;
                case LOAD_DATA:
                    printf("LOADING DATA\n\r");
                    base = UINT16( recv_rep.data[1], recv_rep.data[2] );
                    len  = recv_rep.data[3];
                    printf("BASE: %X LEN: %X\n\r", base, len);
                    load_data( eeprom, base, len, &recv_rep.data[4] );
                    wait(0.1);
                    tmp = get_data( eeprom, base, len );
                    printf("BASE: %X LEN: %X\n\r", base, len);
                    for( uint16_t i=0; i < (len); i++){
                        printf("%X\n\r", tmp[i]);
                        send_rep.data[i] = tmp[i]; //FIXME
                    }
                    hid->send(&send_rep);
                    delete( tmp);
                    break;
                case GET_DATA:
                    //base = UINT16( recv_rep.data[1], recv_rep.data[2] );
                    //len  = UINT16( recv_rep.data[3], recv_rep.data[4] );
                    //tmp = get_data( Ser25LCxxx *eeprom, uint16_t base, uint16_t len ){
                default:
                    // FIXME: error handling.
                    break;
            }
        }
    }
}

void btn_l_press(){
    printf("button,left,press\n\r");
    mouse->press(MOUSE_LEFT);
}
void btn_l_release(){
    printf("button,left,release\n\r");
    mouse->release(MOUSE_LEFT);
}

void btn_m_press(){
    //mouse->press(MOUSE_MIDDLE);
}
void btn_m_release(){
    //mouse->release(MOUSE_MIDDLE);
}

void btn_r_press(){
    printf("button,right,press\n\r");
    mouse->press(MOUSE_RIGHT);
}

void btn_r_release(){
    printf("button,right,release\n\r");
    mouse->release(MOUSE_RIGHT);
}

void btn_f_press(){
    printf("button,forword,press\n\r");
    mouse->press(MOUSE_FORWORD);
}
void btn_f_release(){
    printf("button,forword,release\n\r");
    mouse->release(MOUSE_FORWORD);
}

void btn_b_press(){
    printf("button,back,press\n\r");
    mouse->press(MOUSE_BACK);
}

void btn_b_release(){
    printf("button,back,release\n\r");
    mouse->release(MOUSE_BACK);
}

void btn_hr_press(){
    printf("button,high_res,press\n\r");
    set_res_hr = true;
    set_res_default = false;
    high_rez_active = true;
}
void btn_hr_release(){
    printf("button,high_res,release\n\r");
    set_res_hr = false;
    set_res_default = true;
    high_rez_active = false;
}

void btn_z_press(){
    printf("button,z,press\n\r");
    set_res_z = true;
    set_res_default = false;
    z_axis_active = true;
}
void btn_z_release(){
    printf("button,z,release\n\r");
    set_res_z = false;
    set_res_default = true;
    z_axis_active = false;
}

void prfl_a_set(){
    s[PROFILE_CURRENT] = 0;
    profile_load = true;
}

void prfl_b_set(){
    s[PROFILE_CURRENT] = 1;
    profile_load = true;
}

void prfl_c_set(){
    s[PROFILE_CURRENT] = 2;
    profile_load = true;
}

void prfl_d_set(){
    s[PROFILE_CURRENT] = 3;
    profile_load = true;
}

void prfl_e_set(){
    s[PROFILE_CURRENT] = 4;
    profile_load = true;
}

void prfl_stub(){
}

void debug_out(){
printf("motion_triggerd %d\n\r" , motion_triggered);
printf("z_axis_active %d\n\r", z_axis_active);
printf("high_rez_active %d\n\r", high_rez_active);
printf("profile_load %d\n\r", profile_load); // Always inishally load the profile even if it might be the same.
printf("set_res_hr %d\n\r", set_res_hr);
printf("set_res_z %d\n\r" , set_res_z);
printf("set_res_default %d\n\r", set_res_default);
}

/*
 * The settings are kept in the first 'N' addresses of the of the EEPROM.
 * They are 16bits long. The default settings are in a uint16_t array. So
 * to set/get a setting you use the array value and multiple it by two.
 * This way I can easily get all setting at the start of the program by
 * simply looping through the array.
 */


int set_setting( Ser25LCxxx *eeprom, uint16_t attrib, uint16_t val, uint16_t base_address ){

    uint8_t hl[2];
    
    // TODO: Its working but is it working the way i think its working
    hl[0] = (int)val;
    hl[1] = (int)(val >> 8);
    
    printf("Set Setting %d: L[%X] H[%X]\n\r", attrib, hl[0], hl[1] );

    if ( eeprom->write( attrib * 2, 0x2, hl )){
        return true;
    }
    return false;
}

uint16_t get_setting( Ser25LCxxx *eeprom, uint16_t attrib, uint16_t base_address ){
    
    uint16_t val;
    uint8_t *hl;
    
    hl = eeprom->read( (attrib * 2) + base_address, 0x2 );
    printf("Get Setting %d: L[%X] H[%X]\n\r", attrib, hl[0], hl[1] );
    val = UINT16( hl[1], hl[0] );
    if( val != 0xFFFF ){
        return val;
    }

    return s[attrib];
}

void clear_setting( Ser25LCxxx *eeprom, uint16_t attrib, uint16_t base_address ){
    uint8_t val[2];
    val[0] = val[1] = 0xFF;
    eeprom->write( (attrib * 2) + base_address , 0x2, val );
}


/*
 * Getting and setting the firmware is a bit easer as it is all 8bit.
 */
void load_data( Ser25LCxxx *eeprom, uint16_t base, uint16_t len, const uint8_t* data ){
    eeprom->write( base , len, data );
}

uint8_t* get_data( Ser25LCxxx *eeprom, uint16_t base, uint16_t len ){
    return (uint8_t*)eeprom->read( base, len );
}