PS/2
Dependents: Synth Lab3Translator PS2_Keyboard CLI ... more
Revision 0:7ee6afa15d51, committed 2010-08-31
- Comitter:
- shintamainjp
- Date:
- Tue Aug 31 11:25:34 2010 +0000
- Child:
- 1:823c2798e398
- Commit message:
Changed in this revision
--- /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