init
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 1 May 2013 18:19:23 +0000 (20:19 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 1 May 2013 18:19:23 +0000 (20:19 +0200)
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
controler.c [new file with mode: 0644]
device.c [new file with mode: 0644]
lptgpib.c [new file with mode: 0644]
lptgpib.h [new file with mode: 0644]
sniff.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 <vesely@gjh.sk>
+
+Changelog:
+1.01 added realtime priority
+1.0  first release
diff --git a/controler.c b/controler.c
new file mode 100644 (file)
index 0000000..98d0932
--- /dev/null
@@ -0,0 +1,21 @@
+#include "lptgpib.h"
+#include <unistd.h> /* 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 (file)
index 0000000..d1051a8
--- /dev/null
+++ b/device.c
@@ -0,0 +1,19 @@
+#include "lptgpib.h"
+#include <string.h> /* 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 (file)
index 0000000..2a9f244
--- /dev/null
+++ b/lptgpib.c
@@ -0,0 +1,213 @@
+#include "lptgpib.h"
+
+#include <sys/io.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#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<size; i++)
+                lptgpib_write_byte(src[i], (i+1 == size) ? EOI : 0);
+/*             lptgpib_write_byte(src[i], 0);
+        lptgpib_write_byte(0x0a, EOI); */
+       DBG("WRITE: '%.*s'\n", size, src);
+}
+
+int lptgpib_read(int address, char *dest, int size){
+       if (address > 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 (file)
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 (file)
index 0000000..2fc2d69
--- /dev/null
+++ b/sniff.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#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);
+       }
+}