An example of using polling PS/2 using the modified mbed PS/2 library

Dependencies:   Servo mbed

mylib/PS2/PS2MS.cpp

Committer:
d3alek
Date:
2014-03-12
Revision:
11:f5dcf8811a4e
Parent:
10:37e7c46837dc

File content as of revision 11:f5dcf8811a4e:

/**
 * PS/2 mouse interface control class (Version 0.0.1)
 *
 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
 * http://shinta.main.jp/
 */

#include "PS2MS.h"

#define DEBUG false

/**
 * Create.
 *
 * @param clk_pin Clock pin.
 * @param dat_pin Data pin.
 */
PS2MS::PS2MS(PinName clk_pin, PinName dat_pin)
    : clk(clk_pin), dat(dat_pin), clkOut(clk_pin), mSending(false), mInFuncFall(false)
{
    init_work();
    dat.input();
    clk.fall(this, &PS2MS::func_fall);
    timeout = 1;
}

/**
 * Destory.
 */
PS2MS::~PS2MS()
{
    wdt.detach();
}

int PS2MS::getc()
{
    tot.reset();
    tot.start();
    while (work.cStart == work.cEnd) {
        wait_ms(1);
        if ((timeout > 0) && (tot.read_ms() > timeout)) {
            return EOF;
        }
    }
    tot.stop();

    char c = work.buffer[work.cStart++];
    work.cStart =  work.cStart % RINGBUFSIZ;

    return c;
}



int PS2MS::sendCommand(char c)
{
    while (mInFuncFall) {
        continue;
    }
    mSending = true;
    if (DEBUG) printf("S ");
    dat.output();
    clkOut.output();
    clkOut.write(0);
    wait_us(200);

    dat.write(0);
    wait_us(10);
    clkOut.write(1);
    clkOut.input();

    int parcnt = 0;
    for (int i = 0; i < 10; i++) {
        if (!waitClockDownEdge()) {
            mSending = false;
            wait_us(50);
            if (DEBUG) printf("R ");
            return -1;
        }
        if ((0 <= i) && (i <= 7)) {
            /*
             * Data bit.
             */
            if ((c & (1 << i)) == 0) {
                dat.write(0);
            } else {
                dat.write(1);
                parcnt++;
            }
        }
        if (i == 8) {
            /*
             * Parity bit.
             */
            if ((parcnt % 2) == 0) {
                dat.write(1);
            } else {
                dat.write(0);
            }
        }
        if (i == 9) {
            /*
             * Stop bit.
             */
            dat.write(1);
        }
    }

    dat.input();
    /*
     * Check a ACK.
     */
    if (!waitClockDownEdge()) {
        mSending = false;
        wait_us(50);
        if (DEBUG) printf("R ");
        return -2;
    }
    if (dat.read() != 0) {
        mSending = false;
        wait_us(50);
        if (DEBUG) printf("R ");
        return -3;
    }

    if (!waitClockUpLevel()) {
        mSending = false;
        wait_us(50);
        if (DEBUG) printf("R ");
        return -4;
    }
    mSending = false;
    if (DEBUG) printf("E ");
    wait_us(50);

    return 0;
}

/**
 * Wait a clock up level.
 *
 * @return true if wait done.
 */
bool PS2MS::waitClockUpLevel(void)
{
    int cnt;
    /*
     * Wait until clock is low.
     */
    cnt = 0;
    clkOut.input();
    while (clkOut.read() == 0) {
        cnt++;
        if (MAX_RETRY < cnt) {
            return false;
        }
        wait_us(1);
    }
    return true;
}

/**
 * Wait a clock down edge.
 *
 * @return true if wait done.
 */

bool PS2MS::waitClockDownEdge(void)
{
    //tot.reset();
    //tot.start();
    //while (work.cStart == work.cEnd) {
    //    if (tot.read_ms() > CLOCK_DOWN_EDGE_WAIT_MS) {
    //        tot.stop();
    //        return false;
    //    }
    //}
    //tot.stop();

    // char c = work.buffer[work.cStart++];
    //work.cStart =  work.cStart % RINGBUFSIZ;

    //return c;
    int cnt;
    /*
     * Wait until clock is low.
     */
    cnt = 0;
    clkOut.input();
    while (clkOut.read() == 0) {
        cnt++;
        if (MAX_RETRY < cnt) {
            return false;
        }
        wait_us(1);
    }
    /*
     * Wait until clock is high.
     */
    cnt = 0;
    while (clkOut.read() == 1) {
        cnt++;
        if (MAX_RETRY < cnt) {
            return false;
        }
        wait_us(1);
    }
    return true;
}

/**
 * Set timeout.
 *
 * @param ms Timeout ms.
 */
void PS2MS::setTimeout(int ms)
{
    timeout = ms;
}

void PS2MS::func_timeout(void)
{
    work.bitcnt = 0;
}

void PS2MS::func_fall(void)
{
    if (mSending) {
        return;
    }
    mInFuncFall = true;
    int oddpar = 0;

    /*
     */
    switch (work.bitcnt) {
        case 0:
            /*
             * Start bit.
             */
            int res = dat.read();
            if (res != 0) {
                //printf("Illegal start bit condition. %d\n\r" + res);
            }
            work.bitcnt++;
            break;
        case 9:
            /*
             * Parity bit.
             */
            for (int i = 0; i < 8; i++) {
                if ((work.buffer[work.cEnd] & (1 << i)) != 0) {
                    oddpar++;
                }
            }
            if (dat.read() == 1) {
                oddpar++;
            }
            if ((oddpar % 2) != 1) {
                //printf("Data parity error.\n");
            }
            work.bitcnt++;
            break;
        case 10:
            /*
             * Stop bit.
             */
            if (dat.read() != 1) {
                //printf("Illegal stop bit condition.\n");
            }
            if (work.cStart != ((work.cEnd + 1) % RINGBUFSIZ)) {
                work.cEnd++;
                work.cEnd = work.cEnd % RINGBUFSIZ;
                work.bitcnt = 0;
            } else {
                init_work();
                printf("Buffer overrun.\n");
            }
            break;
        default:
            if ((1 <= work.bitcnt) && (work.bitcnt <= 8)) {
                /*
                 * data bit.
                 */
                if (dat.read() == 1) {
                    work.buffer[work.cEnd] |= (1 << (work.bitcnt - 1));
                } else {
                    work.buffer[work.cEnd] &= ~(1 << (work.bitcnt - 1));
                }
                work.bitcnt++;
            } else {
                /*
                 * Illegal internal state.
                 */
                //printf("Illegal internal state found.\n");
                init_work();
            }
            break;
    }
    wdt.detach();
    wdt.attach_us(this, &PS2MS::func_timeout, 250);
    mInFuncFall = false;
}

void PS2MS::init_work(void)
{
    work.bitcnt = 0;
    work.cStart = 0;
    work.cEnd = 0;
}