c5bbd626979b490e7c92a5c008e1a33aba7140b0
[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         if (ioperm(lpt_base, 4, 1) != 0) {
88           fprintf(stderr,"Nejsou prava na port - musis byt root: %m\n");
89           exit(1);
90         }
91         
92         /* set realtime priority and lock us in memory */
93         struct sched_param scp;
94         memset(&scp, 0, sizeof(scp));
95         scp.sched_priority = sched_get_priority_max(SCHED_RR);
96         sched_setscheduler(0, SCHED_RR, &scp);
97         
98         mlockall(MCL_FUTURE);
99
100         /*
101          * assert NRFD?
102          * this way everything waits for us
103          * otherwise we act like we are not there
104          */
105         put_control(TRI | NDAC | NRFD );
106         
107         signal(SIGINT, sig_handler);
108 }
109
110 char lptgpib_read_byte(char *_flags){
111         DBG_low("READ: ");                /* previous state: TRI | NDAC | NRFD */
112         put_control(TRI | NDAC);          /* clear NRFD */
113         BUSYWAIT( !(get_control() & DAV) )   /* wait for DAV */
114         
115         DBG_low("dav, ")
116         char value = get_data();          /* read data */
117         char flags = get_control();
118         put_control(TRI | NRFD );         /* clear NDAC and set NRFD back */
119         BUSYWAIT( get_control() & DAV )/* wait for end of DAV */
120         
121         DBG_low("done ");
122         put_control(TRI | NDAC | NRFD );  /* back to default state */
123         
124         flags = (flags & ATN) | (value & EOI);
125         value = value & (~EOI);
126
127         DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", 
128                  value, 
129                  flags & EOI ? "EOI" : "", 
130                  flags & ATN ? "ATN" : "");
131 #if DEBUG > 2
132         if (flags & ATN)
133                 lptgpib_print_command(value);
134 #endif
135         if (_flags)
136                 *_flags = flags;
137         return value;
138 }
139
140 void lptgpib_write_byte(char value, char flags){
141         DBG_low("WRITE: ");
142         put_control( TRI | (flags & ATN)  );  /* clear NRFD and NDAC,
143                                                  possibly enable ATN */
144         int tmp;                              /* wait for all to be ready */
145         
146         BUSYWAIT(( tmp = get_control(), !(tmp & NDAC) || (tmp & NRFD) )) 
147         
148         DBG_low("rfd+ndac, ");
149         put_data(value & ~(flags & EOI) );    /* put data */
150         put_control( (flags & ATN) );         /* clear TRI */
151         put_control( DAV | (flags & ATN) );   /* set DAV*/
152         DBG_low("dav, ");
153         BUSYWAIT( get_control() & NDAC )      /* wait for all to accept */
154         DBG_low("dac ");
155         put_control(TRI | NDAC | NRFD );      /* back to default state */
156         
157         DBG_low( isprint(value) ? "'%c' %s %s\n" : "'\\x%02hx' %s %s\n", 
158                  value,
159                  flags & EOI ? "EOI" : "",
160                  flags & ATN ? "ATN" : "");
161 }
162
163 int lptgpib_read_data(char *dest, int size){
164         if ( !dest || ! (size>0) ) return 0;
165         int pos = 0;
166         while (1) {
167                 char flags;
168                 dest[pos++] = lptgpib_read_byte(&flags);
169                 if (flags & ATN){           /* command instead of data */
170                         DBG("READ: '%.*s' interrupted by ATN\n", pos, dest);
171                         return -pos;
172                 }
173                 if ( (pos >= size) || 
174                      (flags & EOI) || 
175                      (dest[pos-1] == EOS)){ /* overflow, EOI or EOS */
176                         DBG("READ: '%.*s'\n", pos, dest);
177                         return pos;
178                 }
179         }
180 }
181
182 void lptgpib_command(char value){
183         lptgpib_write_byte(value, ATN);
184 #if DEBUG > 2
185         lptgpib_print_command(value);
186 #endif
187 }
188
189 void lptgpib_write_data(char *src, int size){
190         if ( !src ) return;
191         int i;
192         for (i=0; i<size; i++)
193                 lptgpib_write_byte(src[i], (i+1 == size) ? EOI : 0);
194 /*              lptgpib_write_byte(src[i], 0);
195         lptgpib_write_byte(0x0a, EOI); */
196         DBG("WRITE: '%.*s'\n", size, src);
197 }
198
199 int lptgpib_read(int address, char *dest, int size){
200         if (address > 30 || address < 0 || !dest)
201                 return 0;
202         
203         lptgpib_command(UNL);
204         lptgpib_command(MLA+0);
205         lptgpib_command(MTA+address);
206         return  lptgpib_read_data(dest, size);  
207 }
208
209 void lptgpib_write(int address, char *src){
210         if (address > 30 || address < 0)
211                 return;
212         lptgpib_command(MTA+0);
213         lptgpib_command(UNL);
214         lptgpib_command(MLA+address);
215         lptgpib_write_data(src, strlen(src));
216 }