#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)); }