PS/2

Dependents:   Synth Lab3Translator PS2_Keyboard CLI ... more

Files at this revision

API Documentation at this revision

Comitter:
shintamainjp
Date:
Tue Aug 31 11:25:34 2010 +0000
Child:
1:823c2798e398
Commit message:

Changed in this revision

PS2.cpp Show annotated file Show diff for this revision Revisions of this file
PS2.h Show annotated file Show diff for this revision Revisions of this file
Semaphore.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2.cpp	Tue Aug 31 11:25:34 2010 +0000
@@ -0,0 +1,220 @@
+/**
+ * PS/2 interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#include "PS2.h"
+
+#define LOCK()   sem.take()
+#define UNLOCK()    sem.release()
+
+PS2::PS2(PinName clkin_pin, PinName datin_pin, PinName clkout_pin, PinName datout_pin)
+        :
+        clkin(clkin_pin), datin(datin_pin),
+        clkout(clkout_pin), datout(datout_pin),
+        writepoint(0), readpoint(0) {
+    init_work();
+    clkin.mode(PullUp);
+    datin.mode(PullUp);
+    clkin.fall(this, &PS2::func_fall);
+    
+    clkout.write(0);
+    datout.write(0);
+}
+
+PS2::~PS2() {
+}
+
+bool PS2::exists(void) {
+    LOCK();
+    bool b = (readpoint == writepoint) ? false : true;
+    UNLOCK();
+    return b;
+}
+
+int PS2::getData(uint8_t *buf, size_t bufsiz) {
+    LOCK();
+
+    /*
+     * Check a buffer empty.
+     */
+    if (readpoint == writepoint) {
+        UNLOCK();
+        return -1;
+    }
+
+    /*
+     * Check a storage buffer size.
+     */
+    if (bufsiz < DATABUFSIZ) {
+        UNLOCK();
+        return -2;
+    }
+
+    /*
+     * Copy the data.
+     */
+    const int nbytes = ringbuffer[readpoint].bytecnt;
+    for (int i = 0; i < nbytes; i++) {
+        buf[i] = ringbuffer[readpoint].buffer[i];
+    }
+
+    /*
+     * Increment read pointer.
+     */
+    readpoint++;
+    if (RINGBUFSIZ <= readpoint) {
+        readpoint = 0;
+    }
+
+    UNLOCK();
+    return nbytes;
+}
+
+void PS2::func_timeout(void) {
+
+    LOCK();
+
+    /*
+     * Check a buffer full.
+     */
+    const int n = ((readpoint - 1) < 0) ? (RINGBUFSIZ - 1) : (readpoint - 1);
+    if (n == writepoint) {
+        init_work();
+        // printf("Buffer full.\n");
+        UNLOCK();
+        return;
+    }
+
+    /*
+     * Check a data size.
+     */
+    if (work.bytecnt == 0) {
+        init_work();
+        // printf("Empty data detected.\n");
+        UNLOCK();
+        return;
+    }
+
+    /*
+     * Check a error.
+     */
+    if (work.errcnt > 0) {
+        init_work();
+        // printf("Error detected.\n");
+        UNLOCK();
+        return;
+    }
+
+    /*
+     * Copy the data.
+     */
+    ringbuffer[writepoint].bytecnt = work.bytecnt;
+    for (int i = 0; i < work.bytecnt; i++) {
+        ringbuffer[writepoint].buffer[i] = work.buffer[i];
+    }
+
+    /*
+     * Increment write pointer.
+     */
+    writepoint++;
+    if (RINGBUFSIZ <= writepoint) {
+        writepoint = 0;
+    }
+
+    /*
+     * Reset variables for work.
+     */
+    init_work();
+
+    UNLOCK();
+}
+
+void PS2::func_fall(void) {
+
+    LOCK();
+
+    /*
+     */
+    switch (work.bitcnt) {
+        case 0:
+            // start bit.
+            /*
+             */
+            if (datin.read() != 0) {
+                // printf("Illegal start bit condition.\n");
+                work.errcnt++;
+            }
+            /*
+             */
+            work.bitcnt++;
+            break;
+        case 9:
+            // parity bit.
+            /*
+             */
+        {
+            int oddpar = 0;
+            for (int i = 0; i < 8; i++) {
+                if ((work.buffer[work.bytecnt] & (1 << i)) != 0) {
+                    oddpar++;
+                }
+            }
+            if (datin.read() == 1) {
+                oddpar++;
+            }
+            if ((oddpar % 2) != 1) {
+                // printf("Data parity error.\n");
+                work.errcnt++;
+            }
+        }
+        /*
+         */
+        work.bitcnt++;
+        break;
+        case 10:
+            // stop bit.
+            /*
+             */
+            if (datin.read() != 1) {
+                // printf("Illegal stop bit condition.\n");
+                work.errcnt++;
+            }
+            /*
+             */
+            work.bytecnt++;
+            work.bitcnt = 0;
+            break;
+        default:
+            if ((1 <= work.bitcnt) && (work.bitcnt <= 8)) {
+                /*
+                 * data bit.
+                 */
+                if (datin.read() == 1) {
+                    work.buffer[work.bytecnt] |= (1 << (work.bitcnt - 1));
+                } else {
+                    work.buffer[work.bytecnt] &= ~(1 << (work.bitcnt - 1));
+                }
+                work.bitcnt++;
+            } else {
+                /*
+                 * Illegal internal state.
+                 */
+                // printf("Illegal internal state found.\n");
+                init_work();
+            }
+            break;
+    }
+
+    UNLOCK();
+    timeout.attach_us(this, &PS2::func_timeout, TIMEOUT_US);
+}
+
+void PS2::init_work(void) {
+    work.state = Idle;
+    work.bitcnt = 0;
+    work.bytecnt = 0;
+    work.errcnt = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2.h	Tue Aug 31 11:25:34 2010 +0000
@@ -0,0 +1,88 @@
+/**
+ * PS/2 interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#ifndef _PS2_H_
+#define _PS2_H_
+
+#include "mbed.h"
+#include "Semaphore.h"
+
+/**
+ * PS/2 interface control class.
+ */
+class PS2 {
+public:
+    /**
+     * Create.
+     *
+     * @param clkinpin Input pin for clock.
+     * @param datinpin Input pin for data.
+     */
+    PS2(PinName clkin_pin, PinName datin_pin, PinName clkout_pin = NC, PinName datout_pin = NC);
+
+    /**
+     * Destory.
+     */
+    ~PS2();
+
+    /**
+     * Check exists a data.
+     *
+     * @return true if a data exists.
+     */
+    bool exists(void);
+
+    /**
+     * Get a data into a buffer.
+     *
+     * @param buf A pointer to a buffer.
+     * @param bufsiz A size of the buffer.
+     *
+     * @return Number of a byte size.
+     */
+    int getData(uint8_t *buf, size_t bufsiz);
+
+private:
+    InterruptIn clkin;
+    DigitalIn datin;
+    DigitalOut clkout;
+    DigitalOut datout;
+    Timeout timeout;
+    Semaphore sem;
+    int writepoint;
+    int readpoint;
+    static const int TIMEOUT_US = 10 * 1000;
+    static const int RINGBUFSIZ = 16;
+    static const int DATABUFSIZ = 32;
+
+    typedef enum {
+        Idle,
+        Reading,
+        Writing
+    } State;
+
+    typedef struct {
+        State state;
+        int bitcnt;
+        int bytecnt;
+        int errcnt;
+        uint8_t buffer[DATABUFSIZ];
+    } work_t;
+    work_t work;
+
+    typedef struct {
+        int bytecnt;
+        uint8_t buffer[DATABUFSIZ];
+    } data_t;
+    data_t ringbuffer[RINGBUFSIZ];
+
+    void func_timeout(void);
+    void func_fall(void);
+    void init_work(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Semaphore.h	Tue Aug 31 11:25:34 2010 +0000
@@ -0,0 +1,32 @@
+#ifndef _SEMAPHORE_H_
+#define _SEMAPHORE_H_
+
+/*
+ * http://mbed.org/forum/mbed/topic/181/#comment-799
+ */
+
+class Semaphore {
+public:
+    Semaphore(): s(SemFree) {}
+
+    bool take(bool block = true) {
+        int oldval;
+        do {
+            oldval = __ldrex(&s);
+        } while ((block && oldval == SemTaken) || __strex(SemTaken, &s) != 0);
+        if (!block) {
+            __clrex();
+        }
+        return (oldval == SemFree);
+    }
+
+    void release() {
+        s = SemFree;
+    }
+
+private:
+    enum { SemFree, SemTaken };
+    int s;
+};
+
+#endif
\ No newline at end of file