From e5d37585de9699dbcf203ba49b5ff8a8e5c89ff8 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 1 May 2013 20:19:23 +0200 Subject: [PATCH] init --- Makefile | 7 ++ README | 16 +++++ controler.c | 21 ++++++ device.c | 19 ++++++ lptgpib.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lptgpib.h | 42 ++++++++++++ sniff.c | 17 +++++ 7 files changed, 335 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 controler.c create mode 100644 device.c create mode 100644 lptgpib.c create mode 100644 lptgpib.h create mode 100644 sniff.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a5efd3d --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS=-O2 -Wall +PROGS=controler device sniff +all: $(PROGS) +$(PROGS): lptgpib.o +clean: + rm -f $(PROGS) *.o diff --git a/README b/README new file mode 100644 index 0000000..f1e89f2 --- /dev/null +++ b/README @@ -0,0 +1,16 @@ +What: +"Library" for controlling gpib devices over standard lpt port. + +Usage: +See examples device.c, controller.c and sniff.c +Link with lptgpib.o, definitions in lptgpib.h + +Wiring: +TODO + +Who: +Jozef Vesely + +Changelog: +1.01 added realtime priority +1.0 first release diff --git a/controler.c b/controler.c new file mode 100644 index 0000000..98d0932 --- /dev/null +++ b/controler.c @@ -0,0 +1,21 @@ +#include "lptgpib.h" +#include /* sleep */ + +#define ADDRESS 7 +int main(int argc, char **argv){ + lptgpib_init(0x378); + + for (;;) { + char buf[256]; + + lptgpib_command(DCL); + lptgpib_write(ADDRESS, "R0G1X\x0a"); + lptgpib_read(ADDRESS, buf, sizeof(buf)); + sleep(1); + + lptgpib_command(DCL); + lptgpib_write(ADDRESS, "F0X\x0a"); + lptgpib_read(ADDRESS, buf, sizeof(buf)); + sleep(1); + } +} diff --git a/device.c b/device.c new file mode 100644 index 0000000..d1051a8 --- /dev/null +++ b/device.c @@ -0,0 +1,19 @@ +#include "lptgpib.h" +#include /* strlen */ + +#define ADDRESS 6 +int main(int argc, char **argv){ + lptgpib_init(0x378); + + char buf[1024] = "Welcome to echo device!\n" + "I will remember and reply with string written to me."; + int len = strlen(buf); + while (1) { + char val, flags; + val = lptgpib_read_byte(&flags); + if ((flags & ATN) && (val == MTA + ADDRESS)) + lptgpib_write_data(buf, len); + if ((flags & ATN) && (val == MLA + ADDRESS)) + len = lptgpib_read_data(buf, sizeof(buf)); + } +} diff --git a/lptgpib.c b/lptgpib.c new file mode 100644 index 0000000..2a9f244 --- /dev/null +++ b/lptgpib.c @@ -0,0 +1,213 @@ +#include "lptgpib.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 3 /* 4 - all, 3 - data, */ + +#if DEBUG > 3 + #define DBG_low(...) { fprintf(stderr,__VA_ARGS__); fflush(stderr); } +#else + #define DBG_low(...) +#endif + +#if DEBUG > 2 + #define DBG(...) { fprintf(stderr,__VA_ARGS__); fflush(stderr); } +#else + #define DBG(...) +#endif + +int lpt_base; +/* + * GPIB uses negative logic, + * LPT control lines (except 0x04) are inverted in hw, + */ +#define get_data() (~inb(lpt_base)) +#define put_data(x) outb(~(x), lpt_base) +#define get_control() (inb(lpt_base+2) ^ 0x04) +#define put_control(x) outb((x) ^ 0x04, lpt_base+2) +#define TRI 0x20 /* tristate data lines */ +#define IRQ 0x10 /* enable irq */ + +/* these depend on wiring */ +#define EOI 0x80 /* LPT 8th data bit */ +#define DAV 0x01 /* LPT pin 1 */ +#define NRFD 0x02 /* LPT pin 14 */ +#define NDAC 0x04 /* LPT pin 16 */ +#define ATN 0x08 /* LPT pin 17 */ + +struct timespec sleeptime = {0, 10000}; /* 10 us*/ +#define BUSYWAIT(cond) while(cond) nanosleep(&sleeptime, NULL); + +struct {int val; char *desc; int len;} cmds[] = { + {GTL, "Go to local"}, + {SDC, "Selected device clear"}, + {PPC, "Parallel poll configure"}, + {GET, "Group execute trigger"}, + {TCT, "Take control"}, + {LLO, "Local lockout"}, + {DCL, "Device clear"}, + {PPU, "Parallel poll unconfigure"}, + {SPE, "Serial poll enable"}, + {SPD, "Serial poll disable"}, + {MLA, "My primary listen address", 30}, + {UNL, "Unlisten"}, + {MTA, "My primary talk address", 30}, + {UNT, "Untalk"}, + {MSA, "My secondary address", 30}, + {PPE, "Parallel poll enable"}, + {PPD, "Parallel poll disable"}, + {0, "Unknown command"}, +}; + +void lptgpib_print_command(unsigned char val){ + int i = 0; + while (cmds[i].val && !(cmds[i].val <= val && + val <= cmds[i].val+cmds[i].len) ) i++; + char *desc = cmds[i].desc; + fprintf(stderr,"CMD: %02hx (%s)\n", val, desc); +} + +void sig_handler(int sig){ + DBG("Caught ^C\n"); + put_control(TRI); + exit(0); +} + +void lptgpib_init(int base){ + lpt_base = base; + ioperm(lpt_base, 4, 1); + + /* set realtime priority and lock us in memory */ + struct sched_param scp; + memset(&scp, 0, sizeof(scp)); + scp.sched_priority = sched_get_priority_max(SCHED_RR); + sched_setscheduler(0, SCHED_RR, &scp); + + mlockall(MCL_FUTURE); + + /* + * assert NRFD? + * this way everything waits for us + * otherwise we act like we are not there + */ + put_control(TRI | NDAC | NRFD ); + + signal(SIGINT, sig_handler); +} + +char lptgpib_read_byte(char *_flags){ + DBG_low("READ: "); /* previous state: TRI | NDAC | NRFD */ + put_control(TRI | NDAC); /* clear NRFD */ + BUSYWAIT( !(get_control() & DAV) ) /* wait for DAV */ + + DBG_low("dav, ") + char value = get_data(); /* read data */ + char flags = get_control(); + put_control(TRI | NRFD ); /* clear NDAC and set NRFD back */ + BUSYWAIT( get_control() & DAV )/* wait for end of DAV */ + + DBG_low("done "); + put_control(TRI | NDAC | NRFD ); /* back to default state */ + + flags = (flags & ATN) | (value & EOI); + value = value & (~EOI); + + DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", + value, + flags & EOI ? "EOI" : "", + flags & ATN ? "ATN" : ""); +#if DEBUG > 2 + if (flags & ATN) + lptgpib_print_command(value); +#endif + if (_flags) + *_flags = flags; + return value; +} + +void lptgpib_write_byte(char value, char flags){ + DBG_low("WRITE: "); + put_control( TRI | (flags & ATN) ); /* clear NRFD and NDAC, + possibly enable ATN */ + int tmp; /* wait for all to be ready */ + + BUSYWAIT(( tmp = get_control(), !(tmp & NDAC) || (tmp & NRFD) )) + + DBG_low("rfd+ndac, "); + put_data(value & ~(flags & EOI) ); /* put data */ + put_control( (flags & ATN) ); /* clear TRI */ + put_control( DAV | (flags & ATN) ); /* set DAV*/ + DBG_low("dav, "); + BUSYWAIT( get_control() & NDAC ) /* wait for all to accept */ + DBG_low("dac "); + put_control(TRI | NDAC | NRFD ); /* back to default state */ + + DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", + value, + flags & EOI ? "EOI" : "", + flags & ATN ? "ATN" : ""); +} + +int lptgpib_read_data(char *dest, int size){ + if ( !dest || ! (size>0) ) return 0; + int pos = 0; + while (1) { + char flags; + dest[pos++] = lptgpib_read_byte(&flags); + if (flags & ATN){ /* command instead of data */ + DBG("READ: '%.*s' interrupted by ATN\n", pos, dest); + return -pos; + } + if ( (pos >= size) || + (flags & EOI) || + (dest[pos-1] == EOS)){ /* overflow, EOI or EOS */ + DBG("READ: '%.*s'\n", pos, dest); + return pos; + } + } +} + +void lptgpib_command(char value){ + lptgpib_write_byte(value, ATN); +#if DEBUG > 2 + lptgpib_print_command(value); +#endif +} + +void lptgpib_write_data(char *src, int size){ + if ( !src ) return; + int i; + for (i=0; i 30 || address < 0 || !dest) + return 0; + + lptgpib_command(UNL); + lptgpib_command(MLA+0); + lptgpib_command(MTA+address); + return lptgpib_read_data(dest, size); +} + +void lptgpib_write(int address, char *src){ + if (address > 30 || address < 0) + return; + lptgpib_command(MTA+0); + lptgpib_command(UNL); + lptgpib_command(MLA+address); + lptgpib_write_data(src, strlen(src)); +} diff --git a/lptgpib.h b/lptgpib.h new file mode 100644 index 0000000..8ad751d --- /dev/null +++ b/lptgpib.h @@ -0,0 +1,42 @@ +#ifndef GPIB_H +#define GPIB_H + +/* GPIB commands*/ +#define GTL 0x01 +#define SDC 0x04 +#define PPC 0x05 +#define GET 0x08 +#define TCT 0x09 +#define LLO 0x11 +#define DCL 0x14 +#define PPU 0x15 +#define SPE 0x18 +#define SPD 0x19 +#define MLA 0x20 // 0x20 - 0x3e +#define UNL 0x3f +#define MTA 0x40 // 0x40 - 0x5e +#define UNT 0x5f +#define MSA 0x60 // 0x60 - 0x7e +#define PPE 0x60 +#define PPD 0x70 +/* GPIB end of string */ +#define EOS 0x0a +/* these depend on wiring !! */ +#define EOI 0x80 /* LPT 8th data bit */ +#define ATN 0x08 /* LPT pin 17 */ + + +void lptgpib_print_command(unsigned char val); +void lptgpib_init(int base); + +char lptgpib_read_byte(char *_flags); +void lptgpib_write_byte(char value, char flags); + +int lptgpib_read_data(char *dest, int size); +void lptgpib_write_data(char *src, int size); + +void lptgpib_command(char value); + +int lptgpib_read(int address, char *dest, int size); +void lptgpib_write(int address, char *src); +#endif diff --git a/sniff.c b/sniff.c new file mode 100644 index 0000000..2fc2d69 --- /dev/null +++ b/sniff.c @@ -0,0 +1,17 @@ +#include +#include "lptgpib.h" + +int main(int argc, char **argv){ + lptgpib_init(0x378); + + char buf[1024]; + while (1) { + char val, flags; + val = lptgpib_read_byte(&flags); + if ( (flags & ATN) && + ((val > MTA && val <= MTA + 30) || + (val > MLA && val <= MLA + 30)) ) + lptgpib_read_data(buf, sizeof(buf)); + printf("%s\n", buf); + } +} -- 1.8.3.1