initial commit

Tue, 26 Aug 2008 12:45:33 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 26 Aug 2008 12:45:33 +0100
changeset 0
745037d69d81
child 1
3e775df109e6

initial commit

Makefile file | annotate | diff | revisions
include/liblpfk.h file | annotate | diff | revisions
src/liblpfk.c file | annotate | diff | revisions
test/lpfktest.c file | annotate | diff | revisions
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Tue Aug 26 12:45:33 2008 +0100
     1.3 @@ -0,0 +1,19 @@
     1.4 +CFLAGS=-fPIC -g -I./include
     1.5 +SONAME=liblpfk.so.1
     1.6 +
     1.7 +.PHONY:	all clean
     1.8 +
     1.9 +all:	liblpfk.so lpfktest
    1.10 +	ldconfig -n .
    1.11 +
    1.12 +clean:
    1.13 +	-rm -f lpfktest
    1.14 +	-rm -f liblpfk.so*
    1.15 +	-rm -f src/*.o
    1.16 +	-rm -f test/*.o
    1.17 +
    1.18 +liblpfk.so:	src/liblpfk.o
    1.19 +	$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $<
    1.20 +
    1.21 +lpfktest:	test/lpfktest.o
    1.22 +	$(CC) -o $@ $< -L. -llpfk
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/include/liblpfk.h	Tue Aug 26 12:45:33 2008 +0100
     2.3 @@ -0,0 +1,135 @@
     2.4 +/****************************************************************************
     2.5 + * Project:		liblpfk
     2.6 + * Purpose:		Driver library for the IBM 6094-020 Lighted Program Function
     2.7 + * 				Keyboard.
     2.8 + * Version:		1.0
     2.9 + * Author:		Philip Pemberton <philpem@philpem.me.uk>
    2.10 + *
    2.11 + * The latest version of this library is available from
    2.12 + * <http://www.philpem.me.uk/code/liblpfk/>.
    2.13 + *
    2.14 + * Copyright (c) 2008, Philip Pemberton
    2.15 + * All rights reserved.
    2.16 + *
    2.17 + * Redistribution and use in source and binary forms, with or without
    2.18 + * modification, are permitted provided that the following conditions
    2.19 + * are met:
    2.20 + *
    2.21 + *  * Redistributions of source code must retain the above copyright
    2.22 + *    notice, this list of conditions and the following disclaimer.
    2.23 + *  * Redistributions in binary form must reproduce the above copyright
    2.24 + *    notice, this list of conditions and the following disclaimer in
    2.25 + *    the documentation and/or other materials provided with the
    2.26 + *    distribution.
    2.27 + *  * Neither the name of the project nor the names of its
    2.28 + *    contributors may be used to endorse or promote products derived
    2.29 + *    from this software without specific prior written permission.
    2.30 + *
    2.31 + *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    2.32 + *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    2.33 + *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    2.34 + *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    2.35 + *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    2.36 + *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    2.37 + *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    2.38 + *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    2.39 + *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    2.40 + *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    2.41 + *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2.42 + ****************************************************************************/
    2.43 +
    2.44 +/**
    2.45 + * @file	liblpfk.h
    2.46 + * @brief	liblpfk library header
    2.47 + */
    2.48 +
    2.49 +#ifndef _liblpfk_h_included
    2.50 +#define _liblpfk_h_included
    2.51 +
    2.52 +#include <termios.h>
    2.53 +
    2.54 +/**
    2.55 + * @brief	LPFK context
    2.56 + *
    2.57 + * Do not change any variables inside this struct, they are for liblpfk's
    2.58 + * internal use only.
    2.59 + */
    2.60 +typedef struct {
    2.61 +	int				fd;			///< serial port file descriptor
    2.62 +	struct termios	oldtio;		///< old termios setup
    2.63 +	int				enabled;	///< LPFK enabled
    2.64 +	unsigned long	led_mask;	///< lit LEDs mask
    2.65 +} LPFK_CTX;
    2.66 +
    2.67 +/**
    2.68 + * @brief	liblpfk error codes
    2.69 + */
    2.70 +enum {
    2.71 +	LPFK_E_OK = 0,				///< No error, success.
    2.72 +	LPFK_E_PORT_OPEN,			///< Could not open comm port.
    2.73 +	LPFK_E_NOT_PRESENT,			///< LPFK not present on specified port.
    2.74 +	LPFK_E_COMMS,				///< Communication error.
    2.75 +	LPFK_E_PARAM				///< Invalid function parameter.
    2.76 +};
    2.77 +
    2.78 +/**
    2.79 + * @brief	Open a serial port and attempt to connecct to an LPFK on that
    2.80 + * 			port.
    2.81 + * @param	port	Serial port path (e.g. /dev/ttyS0).
    2.82 + * @param	ctx		Pointer to an LPFK_CTX struct where LPFK context will be
    2.83 + * 					stored.
    2.84 + * @return	LPFK_E_OK on success, LPFK_E_PORT_OPEN if port could not be
    2.85 + * 			opened, LPFK_E_NOT_PRESENT if no LPFK present on specified port.
    2.86 + */
    2.87 +int lpfk_open(const char *port, LPFK_CTX *ctx);
    2.88 +
    2.89 +/**
    2.90 + * @brief	Close the LPFK.
    2.91 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
    2.92 + * @return	LPFK_E_OK
    2.93 + */
    2.94 +int lpfk_close(LPFK_CTX *ctx);
    2.95 +
    2.96 +/**
    2.97 + * @brief	Enable or disable LPFK input
    2.98 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
    2.99 + * @param	val		true to enable the LPFK's keys, false to disable.
   2.100 + * @return	LPFK_E_OK on success, LPFK_E_COMMS on comms error.
   2.101 + */
   2.102 +int lpfk_enable(LPFK_CTX *ctx, int val);
   2.103 +
   2.104 +/**
   2.105 + * @brief	Set or clear an LED on the LPFK.
   2.106 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   2.107 + * @param	num		LED/key number, from 0 to 31.
   2.108 + * @param	state	State, true for on, false for off.
   2.109 + * @return	LPFK_E_OK on success, LPFK_E_PARAM on bad parameter, LPFK_E_COMMS
   2.110 + * 			on comms error.
   2.111 + */
   2.112 +int lpfk_set_led(LPFK_CTX *ctx, const int num, const int state);
   2.113 +
   2.114 +/**
   2.115 + * @brief	Set or clear all the LEDs on the LPFK.
   2.116 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   2.117 + * @param	state	State, true for on, false for off.
   2.118 + * @return	LPFK_E_OK on success, LPFK_E_PARAM on bad parameter, LPFK_E_COMMS
   2.119 + * 			on comms error.
   2.120 + */
   2.121 +int lpfk_set_leds(LPFK_CTX *ctx, const int state);
   2.122 +
   2.123 +/**
   2.124 + * @brief	Get the status of an LED on the LPFK.
   2.125 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   2.126 + * @param	num		LED/key number, from 0 to 31.
   2.127 + * @return	true if LED is on, false otherwise.
   2.128 + */
   2.129 +int lpfk_get_led(LPFK_CTX *ctx, const int num);
   2.130 +
   2.131 +/**
   2.132 + * @brief	Read a key from the LPFK
   2.133 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   2.134 + * @return	-1 if no keys in buffer, 0-31 for key 1-32 down.
   2.135 + */
   2.136 +int lpfk_read(LPFK_CTX *ctx);
   2.137 +
   2.138 +#endif // _liblpfk_h_included
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/liblpfk.c	Tue Aug 26 12:45:33 2008 +0100
     3.3 @@ -0,0 +1,399 @@
     3.4 +/****************************************************************************
     3.5 + * Project:		liblpfk
     3.6 + * Purpose:		Driver library for the IBM 6094-020 Lighted Program Function
     3.7 + * 				Keyboard.
     3.8 + * Version:		1.0
     3.9 + * Author:		Philip Pemberton <philpem@philpem.me.uk>
    3.10 + *
    3.11 + * The latest version of this library is available from
    3.12 + * <http://www.philpem.me.uk/code/liblpfk/>.
    3.13 + *
    3.14 + * Copyright (c) 2008, Philip Pemberton
    3.15 + * All rights reserved.
    3.16 + *
    3.17 + * Redistribution and use in source and binary forms, with or without
    3.18 + * modification, are permitted provided that the following conditions
    3.19 + * are met:
    3.20 + *
    3.21 + *  * Redistributions of source code must retain the above copyright
    3.22 + *    notice, this list of conditions and the following disclaimer.
    3.23 + *  * Redistributions in binary form must reproduce the above copyright
    3.24 + *    notice, this list of conditions and the following disclaimer in
    3.25 + *    the documentation and/or other materials provided with the
    3.26 + *    distribution.
    3.27 + *  * Neither the name of the project nor the names of its
    3.28 + *    contributors may be used to endorse or promote products derived
    3.29 + *    from this software without specific prior written permission.
    3.30 + *
    3.31 + *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    3.32 + *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    3.33 + *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    3.34 + *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    3.35 + *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    3.36 + *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    3.37 + *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    3.38 + *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    3.39 + *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    3.40 + *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    3.41 + *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    3.42 + ****************************************************************************/
    3.43 +
    3.44 +/**
    3.45 + * @file	liblpfk.c
    3.46 + * @brief	liblpfk library, main source
    3.47 + */
    3.48 +
    3.49 +#include <sys/types.h>
    3.50 +#include <sys/stat.h>
    3.51 +#include <fcntl.h>
    3.52 +#include <unistd.h>
    3.53 +#include <termios.h>
    3.54 +#include <sys/ioctl.h>
    3.55 +#include <time.h>
    3.56 +#include <string.h>
    3.57 +#include <stdbool.h>
    3.58 +#include <stdio.h>
    3.59 +
    3.60 +#include "liblpfk.h"
    3.61 +
    3.62 +int lpfk_open(const char *port, LPFK_CTX *ctx)
    3.63 +{
    3.64 +	struct termios newtio;
    3.65 +	int status;
    3.66 +	int fd;
    3.67 +	int i;
    3.68 +
    3.69 +	// open the serial port
    3.70 +	fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
    3.71 +	if (fd < 0) return LPFK_E_PORT_OPEN;
    3.72 +
    3.73 +	// save current port settings
    3.74 +	tcgetattr(fd, &ctx->oldtio);
    3.75 +
    3.76 +	// set up new parameters
    3.77 +	memset(&newtio, 0, sizeof(newtio));
    3.78 +	// 9600 baud, 8 bits, parity enabled, odd parity
    3.79 +	newtio.c_cflag = B9600 | CS8 | PARENB | PARODD | CLOCAL | CREAD;
    3.80 +	newtio.c_iflag = 0;
    3.81 +	newtio.c_oflag = 0;
    3.82 +
    3.83 +	// set input mode -- non canonical, no echo
    3.84 +	newtio.c_lflag = 0;
    3.85 +
    3.86 +	// inter-character timer unused
    3.87 +	newtio.c_cc[VTIME] = 0;
    3.88 +	// read does not block waiting for characters if there are none in the buffer
    3.89 +	newtio.c_cc[VMIN]  = 0;
    3.90 +
    3.91 +	// flush input buffer
    3.92 +	tcflush(fd, TCIFLUSH);
    3.93 +
    3.94 +	// set new port config
    3.95 +	tcsetattr(fd, TCSANOW, &newtio);
    3.96 +
    3.97 +	// set RTS true to pull the LPFK out of reset
    3.98 +	ioctl(fd, TIOCMGET, &status);
    3.99 +	status |= TIOCM_RTS;
   3.100 +	ioctl(fd, TIOCMSET, &status);
   3.101 +
   3.102 +	// wait a few seconds for the LPFK to become ready
   3.103 +	sleep(2);
   3.104 +
   3.105 +	// 0x06: READ CONFIGURATION. LPFK sends 0x03 in response.
   3.106 +	// Try five times to wake it up.
   3.107 +	status = false;
   3.108 +	for (i=0; i<5; i++) {
   3.109 +		unsigned char buf;
   3.110 +		time_t tm;
   3.111 +
   3.112 +		// Send 0x06: READ CONFIGURATION, loop on failure
   3.113 +		if (write(fd, "\x06", 1) < 1) {
   3.114 +			continue;
   3.115 +		}
   3.116 +
   3.117 +		// save current time (in seconds)
   3.118 +		tm = time(NULL);
   3.119 +
   3.120 +		// loop until 2 seconds have passed, or LPFK responds
   3.121 +		status = false;
   3.122 +		do {
   3.123 +			// read data, loop if not successful
   3.124 +			if (read(fd, &buf, 1) < 1) {
   3.125 +				continue;
   3.126 +			}
   3.127 +
   3.128 +			// we got some data, what is it?
   3.129 +			if (buf == 0x03) {
   3.130 +				// 0x03 -- correct response. we're done.
   3.131 +				status = true;
   3.132 +			}
   3.133 +		} while (((time(NULL) - tm) < 2) && (!status));
   3.134 +
   3.135 +		// exit loop if we got the LPFK to talk
   3.136 +		if (status) {
   3.137 +			break;
   3.138 +		}
   3.139 +	}
   3.140 +
   3.141 +	// Did the LPFK respond?
   3.142 +	if (!status) {
   3.143 +		// LPFK isn't talking. Restore serial port state and exit.
   3.144 +		tcsetattr(fd, TCSANOW, &ctx->oldtio);
   3.145 +		close(fd);
   3.146 +		
   3.147 +		return LPFK_E_NOT_PRESENT;
   3.148 +	} else {
   3.149 +		// Initialise LPFK context
   3.150 +		ctx->led_mask = 0;
   3.151 +		ctx->fd = fd;
   3.152 +
   3.153 +		// Enable the LPFK
   3.154 +		write(fd, "\x08", 1);
   3.155 +		ctx->enabled = true;
   3.156 +
   3.157 +		// Return OK status
   3.158 +		return LPFK_E_OK;
   3.159 +	}
   3.160 +}
   3.161 +
   3.162 +int lpfk_close(LPFK_CTX *ctx)
   3.163 +{
   3.164 +	int status;
   3.165 +
   3.166 +	// 0x09: DISABLE. Stop the LPFK responding to keystrokes.
   3.167 +	write(ctx->fd, "\x09", 1);
   3.168 +
   3.169 +	// turn all the LEDs off
   3.170 +	lpfk_set_leds(ctx, false);
   3.171 +
   3.172 +	// set RTS false to put the LPFK into reset
   3.173 +	ioctl(ctx->fd, TIOCMGET, &status);
   3.174 +	status &= ~TIOCM_RTS;
   3.175 +	ioctl(ctx->fd, TIOCMSET, &status);
   3.176 +
   3.177 +	// Restore the port state and close the serial port.
   3.178 +	tcsetattr(ctx->fd, TCSANOW, &ctx->oldtio);
   3.179 +	close(ctx->fd);
   3.180 +
   3.181 +	// Done!
   3.182 +	return LPFK_E_OK;
   3.183 +}
   3.184 +
   3.185 +int lpfk_enable(LPFK_CTX *ctx, int val)
   3.186 +{
   3.187 +	if (val) {
   3.188 +		// val == true, enable the LPFK
   3.189 +		if (write(ctx->fd, "\x08", 1) != 1) {
   3.190 +			ctx->enabled = true;
   3.191 +			return LPFK_E_COMMS;
   3.192 +		}
   3.193 +	} else {
   3.194 +		// val == false, disable the LPFK
   3.195 +		if (write(ctx->fd, "\x09", 1) != 1) {
   3.196 +			return LPFK_E_COMMS;
   3.197 +		}
   3.198 +	}
   3.199 +
   3.200 +	// update the context, return success
   3.201 +	ctx->enabled = val;
   3.202 +	return LPFK_E_OK;
   3.203 +}
   3.204 +
   3.205 +/**
   3.206 + * @brief	Set or clear an LED on the LPFK.
   3.207 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   3.208 + * @param	num		LED/key number, from 0 to 31.
   3.209 + * @param	state	State, true for on, false for off.
   3.210 + * @return	LPFK_E_OK on success, LPFK_E_PARAM on bad parameter, LPFK_E_COMMS
   3.211 + * 			on comms error.
   3.212 + */
   3.213 +int lpfk_set_led(LPFK_CTX *ctx, const int num, const int state)
   3.214 +{
   3.215 +	int i;
   3.216 +	time_t tm;
   3.217 +	unsigned long mask, leds;
   3.218 +	unsigned char buf[5];
   3.219 +	unsigned char status;
   3.220 +
   3.221 +	// check parameters
   3.222 +	if ((num < 0) || (num > 31)) {
   3.223 +		return LPFK_E_PARAM;
   3.224 +	}
   3.225 +
   3.226 +	// parameters OK, now build the LED mask
   3.227 +	mask = (0x80 >> (num % 8)) << ((num / 8) * 8);
   3.228 +
   3.229 +	leds = ctx->led_mask;
   3.230 +
   3.231 +	// mask the specified bit
   3.232 +	if (state) {
   3.233 +		leds |= mask;
   3.234 +	} else {
   3.235 +		leds &= ~mask;
   3.236 +	}
   3.237 +
   3.238 +	// send new LED mask to the LPFK
   3.239 +	buf[0] = 0x94;
   3.240 +	buf[1] = leds & 0xff;
   3.241 +	buf[2] = leds >> 8;
   3.242 +	buf[3] = leds >> 16;
   3.243 +	buf[4] = leds >> 24;
   3.244 +
   3.245 +	// make 5 attempts to set the LEDs
   3.246 +	for (i=0; i<5; i++) {
   3.247 +		if (write(ctx->fd, &buf, 5) < 5) {
   3.248 +			continue;
   3.249 +		}
   3.250 +
   3.251 +		// check for response -- 0x81 = OK, 0x80 = retransmit
   3.252 +		// save current time (in seconds)
   3.253 +		tm = time(NULL);
   3.254 +
   3.255 +		// loop until 2 seconds have passed, or LPFK responds
   3.256 +		status = 0x00;
   3.257 +		do {
   3.258 +			// read data, loop if not successful
   3.259 +			if (read(ctx->fd, &status, 1) < 1) {
   3.260 +				continue;
   3.261 +			}
   3.262 +
   3.263 +			// we got some data, what is it?
   3.264 +			if (status == 0x81) {
   3.265 +				// 0x81 -- received successfully
   3.266 +				break;
   3.267 +			}
   3.268 +		} while ((time(NULL) - tm) < 2);
   3.269 +
   3.270 +		// status OK?
   3.271 +		if (status == 0x81) {
   3.272 +			// 0x81: OK
   3.273 +			break;
   3.274 +		} else if (status == 0x80) {
   3.275 +			// 0x80: Retransmit request
   3.276 +			continue;
   3.277 +		}
   3.278 +	}
   3.279 +
   3.280 +	// update the context
   3.281 +	ctx->led_mask = leds;
   3.282 +
   3.283 +	return LPFK_E_OK;
   3.284 +}
   3.285 +
   3.286 +/**
   3.287 + * @brief	Set or clear all the LEDs on the LPFK.
   3.288 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   3.289 + * @param	state	State, true for on, false for off.
   3.290 + * @return	LPFK_E_OK on success, LPFK_E_PARAM on bad parameter, LPFK_E_COMMS
   3.291 + * 			on comms error.
   3.292 + */
   3.293 +int lpfk_set_leds(LPFK_CTX *ctx, const int state)
   3.294 +{
   3.295 +	int i;
   3.296 +	time_t tm;
   3.297 +	unsigned long leds;
   3.298 +	unsigned char buf[5];
   3.299 +	unsigned char status;
   3.300 +
   3.301 +	if (state) {
   3.302 +		// all LEDs on
   3.303 +		leds = 0xFFFFFFFF;
   3.304 +	} else {
   3.305 +		// all LEDs off
   3.306 +		leds = 0x00000000;
   3.307 +	}
   3.308 +
   3.309 +	// send new LED mask to the LPFK
   3.310 +	buf[0] = 0x94;
   3.311 +	buf[1] = leds & 0xff;
   3.312 +	buf[2] = leds >> 8;
   3.313 +	buf[3] = leds >> 16;
   3.314 +	buf[4] = leds >> 24;
   3.315 +
   3.316 +	// make 5 attempts to set the LEDs
   3.317 +	for (i=0; i<5; i++) {
   3.318 +		if (write(ctx->fd, &buf, 5) < 5) {
   3.319 +			continue;
   3.320 +		}
   3.321 +
   3.322 +		// check for response -- 0x81 = OK, 0x80 = retransmit
   3.323 +		// save current time (in seconds)
   3.324 +		tm = time(NULL);
   3.325 +
   3.326 +		// loop until 2 seconds have passed, or LPFK responds
   3.327 +		status = 0x00;
   3.328 +		do {
   3.329 +			// read data, loop if not successful
   3.330 +			if (read(ctx->fd, &status, 1) < 1) {
   3.331 +				continue;
   3.332 +			}
   3.333 +
   3.334 +			// we got some data, what is it?
   3.335 +			if (status == 0x81) {
   3.336 +				// 0x81 -- received successfully
   3.337 +				break;
   3.338 +			}
   3.339 +		} while ((time(NULL) - tm) < 2);
   3.340 +
   3.341 +		// status OK?
   3.342 +		if (status == 0x81) {
   3.343 +			// 0x81: OK
   3.344 +			break;
   3.345 +		} else if (status == 0x80) {
   3.346 +			// 0x80: Retransmit request
   3.347 +			continue;
   3.348 +		}
   3.349 +	}
   3.350 +
   3.351 +	// update the context
   3.352 +	ctx->led_mask = leds;
   3.353 +
   3.354 +	return LPFK_E_OK;
   3.355 +}
   3.356 +
   3.357 +/**
   3.358 + * @brief	Get the status of an LED on the LPFK.
   3.359 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   3.360 + * @param	num		LED/key number, from 0 to 31.
   3.361 + * @return	true if LED is on, false otherwise.
   3.362 + */
   3.363 +int lpfk_get_led(LPFK_CTX *ctx, const int num)
   3.364 +{
   3.365 +	unsigned long mask;
   3.366 +
   3.367 +	// check parameters
   3.368 +	if ((num < 0) || (num > 31)) {
   3.369 +		return false;
   3.370 +	}
   3.371 +
   3.372 +	// parameters OK, now build the LED mask
   3.373 +	mask = (0x80 >> (num % 8)) << ((num / 8) * 8);
   3.374 +	if (ctx->led_mask & mask) {
   3.375 +		return true;
   3.376 +	} else {
   3.377 +		return false;
   3.378 +	}
   3.379 +}
   3.380 +
   3.381 +/**
   3.382 + * @brief	Read a key from the LPFK
   3.383 + * @param	ctx		Pointer to an LPFK_CTX struct initialised by lpfk_open().
   3.384 + * @return	-1 if no keys in buffer, 0-31 for key 1-32 down.
   3.385 + */
   3.386 +int lpfk_read(LPFK_CTX *ctx)
   3.387 +{
   3.388 +	int nbytes;
   3.389 +	unsigned char key;
   3.390 +
   3.391 +	// try and read a byte (keycode) from the LPFK
   3.392 +	nbytes = read(ctx->fd, &key, 1);
   3.393 +
   3.394 +	if ((nbytes < 1) || (key > 31)) {
   3.395 +		// no keys buffered, or keycode invalid.
   3.396 +		return -1;
   3.397 +	} else {
   3.398 +		// key buffered, pass it along.
   3.399 +		return key;
   3.400 +	}
   3.401 +}
   3.402 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/lpfktest.c	Tue Aug 26 12:45:33 2008 +0100
     4.3 @@ -0,0 +1,63 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdbool.h>
     4.6 +#include <time.h>
     4.7 +#include "liblpfk.h"
     4.8 +
     4.9 +int main(int argc, char **argv) 
    4.10 +{
    4.11 +	LPFK_CTX	ctx;
    4.12 +	int			i;
    4.13 +	time_t		tm;
    4.14 +
    4.15 +	if (argc < 2) {
    4.16 +		printf("Syntax: %s commport\n", argv[0]);
    4.17 +		return -1;
    4.18 +	}
    4.19 +
    4.20 +	if ((i = lpfk_open(argv[1], &ctx)) != LPFK_E_OK) {
    4.21 +		switch(i) {
    4.22 +			case LPFK_E_PORT_OPEN:
    4.23 +				printf("Error opening comm port.\n");
    4.24 +				break;
    4.25 +			case LPFK_E_NOT_PRESENT:
    4.26 +				printf("LPFK not connected to specified port.\n");
    4.27 +				break;
    4.28 +			case LPFK_E_COMMS:
    4.29 +				printf("LPFK communications error.\n");
    4.30 +				break;
    4.31 +		}
    4.32 +		return -2;
    4.33 +	}
    4.34 +
    4.35 +//	printf("disable: %d\n", lpfk_enable(&ctx, false));
    4.36 +//	printf("enable : %d\n", lpfk_enable(&ctx, true));
    4.37 +
    4.38 +	printf("Scanning LEDs, 1-32...\n");
    4.39 +
    4.40 +	for (i=0; i<32; i++) {
    4.41 +		if (i>0) {
    4.42 +			lpfk_set_led(&ctx, i-1, false);
    4.43 +		}
    4.44 +		lpfk_set_led(&ctx, i, true);
    4.45 +		usleep(100000);
    4.46 +	}
    4.47 +
    4.48 +	// Turn LEDs off
    4.49 +	lpfk_set_leds(&ctx, false);
    4.50 +
    4.51 +	printf("Now press the keys on the LPFK...\n");
    4.52 +
    4.53 +	// scan keys for 5 seconds
    4.54 +	tm = time(NULL);
    4.55 +	do {
    4.56 +		// read keys
    4.57 +		if ((i = lpfk_read(&ctx)) >= 0) {
    4.58 +			// key buffered, toggle the LED
    4.59 +			printf("Key down: #%d\n", i);
    4.60 +			lpfk_set_led(&ctx, i, !lpfk_get_led(&ctx, i));
    4.61 +		}
    4.62 +	} while ((time(NULL) - tm) < 30);
    4.63 +
    4.64 +	lpfk_close(&ctx);
    4.65 +}
    4.66 +