terminal: +chvili pockat, asi zbytecne, jen aby to bylo videt na portu
[lptgpib.git] / lptgpib.c
1 #include "lptgpib.h"
2
3 #include <sys/io.h>
4 #include <stdio.h>
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <signal.h>
9 #include <string.h>
10 #include <sched.h>
11 #include <sys/mman.h>
12 #include <time.h>
13
14 #define DEBUG 3 /* 4 - all, 3 - data, */
15
16 #if DEBUG > 3
17         #define DBG_low(...) { fprintf(stderr,__VA_ARGS__); fflush(stderr); }
18 #else
19         #define DBG_low(...)
20 #endif
21
22 #if DEBUG > 2
23         #define DBG(...) { fprintf(stderr,__VA_ARGS__); fflush(stderr); }
24 #else
25         #define DBG(...)
26 #endif
27
28 int lpt_base;
29 /* 
30  * GPIB uses negative logic, 
31  * LPT control lines (except 0x04) are inverted in hw,
32  */
33 #define get_data() (~inb(lpt_base))
34 #define put_data(x) outb(~(x), lpt_base)
35 #define get_control() (inb(lpt_base+2) ^ 0x04)
36 #define put_control(x) outb((x) ^ 0x04, lpt_base+2)
37 #define TRI 0x20 /* tristate data lines */
38 #define IRQ 0x10 /* enable irq */
39
40 /* these depend on wiring */
41 #define EOI 0x80 /* LPT 8th data bit */
42 #define DAV  0x01 /* LPT pin 1  */
43 #define NRFD 0x02 /* LPT pin 14 */
44 #define NDAC 0x04 /* LPT pin 16 */
45 #define ATN  0x08 /* LPT pin 17 */
46
47 struct timespec sleeptime = {0, 10000}; /* 10 us*/
48 #define BUSYWAIT(cond) while(cond) nanosleep(&sleeptime, NULL);
49
50 struct {int val; char *desc; int len;} cmds[] = {
51         {GTL, "Go to local"},
52         {SDC, "Selected device clear"},
53         {PPC, "Parallel poll configure"},
54         {GET, "Group execute trigger"},
55         {TCT, "Take control"},
56         {LLO, "Local lockout"},
57         {DCL, "Device clear"},
58         {PPU, "Parallel poll unconfigure"},
59         {SPE, "Serial poll enable"},
60         {SPD, "Serial poll disable"},
61         {MLA, "My primary listen address", 30},
62         {UNL, "Unlisten"},
63         {MTA, "My primary talk address", 30},
64         {UNT, "Untalk"},
65         {MSA, "My secondary address", 30},
66         {PPE, "Parallel poll enable"},
67         {PPD, "Parallel poll disable"},
68         {0, "Unknown command"},
69 };
70
71 void lptgpib_print_command(unsigned char val){
72         int i = 0;
73         while (cmds[i].val && !(cmds[i].val <= val && 
74                                 val <= cmds[i].val+cmds[i].len) ) i++;
75         char *desc = cmds[i].desc;
76         fprintf(stderr,"CMD: %02hx (%s)\n", val, desc);
77 }
78
79 void sig_handler(int sig){ 
80         DBG("Caught ^C\n");
81         put_control(TRI);
82         exit(0);
83 }
84
85 void lptgpib_init(int base){
86         lpt_base = base;
87         ioperm(lpt_base, 4, 1);
88         
89         /* set realtime priority and lock us in memory */
90         struct sched_param scp;
91         memset(&scp, 0, sizeof(scp));
92         scp.sched_priority = sched_get_priority_max(SCHED_RR);
93         sched_setscheduler(0, SCHED_RR, &scp);
94         
95         mlockall(MCL_FUTURE);
96
97         /*
98          * assert NRFD?
99          * this way everything waits for us
100          * otherwise we act like we are not there
101          */
102         put_control(TRI | NDAC | NRFD );
103         
104         signal(SIGINT, sig_handler);
105 }
106
107 char lptgpib_read_byte(char *_flags){
108         DBG_low("READ: ");                /* previous state: TRI | NDAC | NRFD */
109         put_control(TRI | NDAC);          /* clear NRFD */
110         BUSYWAIT( !(get_control() & DAV) )   /* wait for DAV */
111         
112         DBG_low("dav, ")
113         char value = get_data();          /* read data */
114         char flags = get_control();
115         put_control(TRI | NRFD );         /* clear NDAC and set NRFD back */
116         BUSYWAIT( get_control() & DAV )/* wait for end of DAV */
117         
118         DBG_low("done ");
119         put_control(TRI | NDAC | NRFD );  /* back to default state */
120         
121         flags = (flags & ATN) | (value & EOI);
122         value = value & (~EOI);
123
124         DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", 
125                  value, 
126                  flags & EOI ? "EOI" : "", 
127                  flags & ATN ? "ATN" : "");
128 #if DEBUG > 2
129         if (flags & ATN)
130                 lptgpib_print_command(value);
131 #endif
132         if (_flags)
133                 *_flags = flags;
134         return value;
135 }
136
137 void lptgpib_write_byte(char value, char flags){
138         DBG_low("WRITE: ");
139         put_control( TRI | (flags & ATN)  );  /* clear NRFD and NDAC,
140                                                  possibly enable ATN */
141         int tmp;                              /* wait for all to be ready */
142         
143         BUSYWAIT(( tmp = get_control(), !(tmp & NDAC) || (tmp & NRFD) )) 
144         
145         DBG_low("rfd+ndac, ");
146         put_data(value & ~(flags & EOI) );    /* put data */
147         put_control( (flags & ATN) );         /* clear TRI */
148         put_control( DAV | (flags & ATN) );   /* set DAV*/
149         DBG_low("dav, ");
150         BUSYWAIT( get_control() & NDAC )      /* wait for all to accept */
151         DBG_low("dac ");
152         put_control(TRI | NDAC | NRFD );      /* back to default state */
153         
154         DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", 
155                  value,
156                  flags & EOI ? "EOI" : "",
157                  flags & ATN ? "ATN" : "");
158 }
159
160 int lptgpib_read_data(char *dest, int size){
161         if ( !dest || ! (size>0) ) return 0;
162         int pos = 0;
163         while (1) {
164                 char flags;
165                 dest[pos++] = lptgpib_read_byte(&flags);
166                 if (flags & ATN){           /* command instead of data */
167                         DBG("READ: '%.*s' interrupted by ATN\n", pos, dest);
168                         return -pos;
169                 }
170                 if ( (pos >= size) || 
171                      (flags & EOI) || 
172                      (dest[pos-1] == EOS)){ /* overflow, EOI or EOS */
173                         DBG("READ: '%.*s'\n", pos, dest);
174                         return pos;
175                 }
176         }
177 }
178
179 void lptgpib_command(char value){
180         lptgpib_write_byte(value, ATN);
181 #if DEBUG > 2
182         lptgpib_print_command(value);
183 #endif
184 }
185
186 void lptgpib_write_data(char *src, int size){
187         if ( !src ) return;
188         int i;
189         for (i=0; i<size; i++)
190                 lptgpib_write_byte(src[i], (i+1 == size) ? EOI : 0);
191 /*              lptgpib_write_byte(src[i], 0);
192         lptgpib_write_byte(0x0a, EOI); */
193         DBG("WRITE: '%.*s'\n", size, src);
194 }
195
196 int lptgpib_read(int address, char *dest, int size){
197         if (address > 30 || address < 0 || !dest)
198                 return 0;
199         
200         lptgpib_command(UNL);
201         lptgpib_command(MLA+0);
202         lptgpib_command(MTA+address);
203         return  lptgpib_read_data(dest, size);  
204 }
205
206 void lptgpib_write(int address, char *src){
207         if (address > 30 || address < 0)
208                 return;
209         lptgpib_command(MTA+0);
210         lptgpib_command(UNL);
211         lptgpib_command(MLA+address);
212         lptgpib_write_data(src, strlen(src));
213 }