touch screen handler for the microchip AR1020

ar1020.cpp

Committer:
hlipka
Date:
2011-02-24
Revision:
4:510ea5b28a05
Parent:
3:b7eb3b3fe79f
Child:
5:a5eba88e8c3e

File content as of revision 4:510ea5b28a05:

/*
* mbed AR1020 library
* Copyright (c) 2010 Hendrik Lipka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "ar1020.h"
#include "wait_api.h"

AR1020::AR1020(PinName mosi, PinName miso, PinName clk, PinName enable, PinName siq, PinName power) {
    _mosi=new DigitalOut(mosi);
    _miso=new DigitalIn(miso);
    _clk=new DigitalOut(clk);
    _clk->write(0);

    _enable=new DigitalOut(enable);
    _enable->write(1);
    _irq=new InterruptIn(siq);
    _siq=new DigitalIn(siq);
    _x=-1;
    _y=-1;
    _pen=0;
    _oldPen=false;
    _led=new DigitalOut(LED1);
    _power=new DigitalOut(power);
    _power->write(0);
}

AR1020::~AR1020() {
    delete _enable;
    delete _irq;
}

void AR1020::init() {
    bool ok=false;
    while (!ok)
    {
        _power->write(0);
        wait_ms(200);
        _power->write(1);
        wait_ms(100);
        int r=cmd(0x13,NULL,0);
        printf("disable touch=%i\n",r);
        if (0!=r)
            continue;
    
        int regStart=cmd(0x22,NULL,0);
        printf("reg offset=%i\n",regStart);
    
        if (regStart<0)
            continue;
    
        char cid2[4]={0x00,0x0d+regStart,0x01,0x01};
        r=cmd(0x21,cid2,4);
        printf("set mode=1 => %i\n",r);
        if (0!=r)
            continue;
    
        r=cmd(0x12,NULL,0);
        printf("enable touch=%i\n",r);
        if (0!=r)
            continue;
        ok=true;
    }
    _irq->rise(this, &AR1020::read);
}

int AR1020::x() {
    return _x;
}

int AR1020::y() {
    return _y;
}

int AR1020::pen() {
    return _pen;
}


void AR1020::read() {
    while (1==_siq->read()) {
        _led->write(1);
        _enable->write(0);
        wait_us(60);

        int pen=readByte();
        wait_us(60);

        int xlo=readByte();
        wait_us(60);

        int xhi=readByte();
        wait_us(60);

        int ylo=readByte();
        wait_us(60);

        int yhi=readByte();
        _enable->write(1);

//        printf("0x%x|0x%x|0x%x|0x%x|0x%x\n", pen,xlo,xhi,ylo,yhi);
        if (0x4d==pen || 0==pen || 255==pen) {
            // ignore invalid stuff, do nothing...
        } else if (0x81!=pen&0x81) { // pen set?
            _pen=0;
            int x=xlo+(xhi<<7);
            int y=ylo+(yhi<<7);
            if (0!=x&&0!=y) {
                _x=x;
                _y=y;
            }
        } else {
            _pen=1;
            int x=xlo+(xhi<<7);
            int y=ylo+(yhi<<7);
            if (0!=x&&0!=y) {
                _x=x;
                _y=y;
            }
        }
        _event.x=_x;
        _event.y=_y;
        _event.pen=_pen;
        if (_pen==1 && _oldPen==false) { // pen down
            _callbackPD.call((uint32_t)&_event);
        } else if (_pen==1 && _oldPen==true) { // pen moved
            _callbackPM.call((uint32_t)&_event);
        } else if (_pen==0 && _oldPen==true) { // pen up
            _callbackPU.call((uint32_t)&_event);
        } else {
            // happens on the first touch (the first report is send with pen=0).
        }
        _oldPen=(_pen==1);
        _led->write(0);
        if (1==_siq->read())
            wait_ms(5);
    }
}

int AR1020::cmd(char cmd,char* data, int len, bool doEnable) {
    if (doEnable) {
        _enable->write(1);
        wait_us(1000);
        _enable->write(0);
    }

    wait_us(10);

    writeByte(0x55);
    wait_us(100);

    writeByte(len+1);
    wait_us(100);

    writeByte(cmd);
    wait_us(100);

    for (int i=0;i<len;i++) {
        writeByte(data[i]);
        wait_us(100);
    }
    Timer t;
    t.start();
    while (true) {
        wait_us(100);
        if (1==_siq->read())
            break;
        if (t.read_ms()>1)
            break;
    }
    char rhead=readByte();
    wait_us(100);
    if (rhead!=0x55) {
        if (doEnable)
            _enable->write(1);
        printf("rh=0x%x\n",rhead);
        return -1000;
    }
    char rlen=readByte();
    wait_us(100);
    if (rlen==2) {
        char r=readByte();
        wait_us(100);
        char rc=readByte();
        wait_us(100);
        if (doEnable)
            _enable->write(1);
        if (rc!=cmd)
            return -2000;
        return -r;
    } else if (rlen==3) {
        char r=readByte();
        wait_us(100);
        char rc=readByte();
        wait_us(100);
        if (rc!=cmd) {
            if (doEnable)
                _enable->write(1);
            return -3000;
        }
        char rd=readByte();
        wait_us(100);
        if (doEnable)
            _enable->write(1);
        if (r==0)
            return rd;
        return -r;
    } else {
        if (doEnable)
            _enable->write(1);
        return -4000;
    }
}
void AR1020::calibrate() {
    _irq->rise(NULL);

    DigitalOut led1(LED1);
    DigitalOut led2(LED2);
    DigitalOut led3(LED3);
    DigitalOut led4(LED4);
    led1=0;
    led2=0;
    led3=1;
    led4=1;

    int r=cmd(0x13,NULL,0);
    printf("disable touch=%i\n",r);
    wait_ms(100);
    if (r<0)
        return;
    led4=0;

    int regStart=cmd(0x22,NULL,0);
    printf("reg offset=%i\n",regStart);

    char cid[3]={0x00,0x0d+regStart,0x01};
    int mode=cmd(0x20,cid,3);
    printf("mode=%i\n",mode);

    if (regStart<0)
        return;
    printf("start calibrate\n");
    led3=0;
    char cid2[4]={0x00,0x0e+regStart,0x01,0x19};
    r=cmd(0x21,cid2,4);
    printf("set inset=%i\n",r);
    if (r<0)
        return;

    _enable->write(1);
    wait_us(100);
    _enable->write(0);
    wait_us(10);
    char cid3[1]={0x04};
    cmd(0x14,cid3,1,false);

    wait_ms(1);

    int resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("start OK, press upper left");
    led1=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press upper right");
    led2=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press lower right");
    led3=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press lower left");
    led4=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);

    _enable->write(1);

    r=cmd(0x23,NULL,0);
    printf("save registers=%i\n",r);

    r=cmd(0x12,NULL,0);
    printf("enable touch=%i\n",r);

    _irq->rise(this, &AR1020::read);

}

int AR1020::readCalibResponse() {
    while (true) {
        int r=readByte();
        if (r!=0x55) {
//            printf("1=0x%x\n",r);
            wait_ms(100);
            continue;
        }

        r=readByte();
        wait_us(100);
        if (r!=0x02) {
            printf("2=0x%x\n",r);
            continue;
        }

        r=readByte();
        wait_us(100);
        if (r!=0x00) {
            printf("3=0x%x\n",r);
            continue;
        }
        int rc=readByte();
        wait_us(100);
        if (rc!=0x14) {
            printf("4=0x%x\n",r);
            continue;
        }

        return r;
    }
}

int AR1020::readByte() {
    _clk->write(0);
    wait_us(10);
    int r=0;
    for (int i=0;i<8;i++) {
        r=r<<1;
        _clk->write(1);
        wait_us(10);
        _clk->write(0);
        wait_us(10);
        int bit=_miso->read();
        r+=bit;
    }
//    printf("<-%i\n",r);
    return r;
}

void AR1020::writeByte(char byte) {
    _clk->write(0);
    wait_us(10);
//    printf("->0x%x\n",byte);
    for (int i=0;i<8;i++) {
        int bit=byte>127;
//        printf("%i",bit);
        _clk->write(1);
        wait_us(10);
        _mosi->write(bit);
        wait_us(10);
        _clk->write(0);
        wait_us(10);
        byte=(char)(byte<<1);

    }
//    printf("\n");
}