/* * Motor power jump test via parallel port bit-banging * Works in the Leenux. * * Simon Kirby, 2012-10-01 */ //#define DEBUG #include #include #include #include #include #include #include /* * The only lines believed to be implemented in all parallel ports are: * D0-D6 outputs (long long ago I heard of some non-PC machine with * D7 hardwired to GND - don't remember what it was) * BUSY input * * STROBE output might be pulsed by hardware and not be writable * ACK input might only trigger an interrupt and not be readable * */ #include #include #include #include #include #include "parport.h" #include "ppdev.h" #include "funcs.h" static int ppdev_fd; #ifndef MIN_SLEEP_USEC #define MIN_SLEEP_USEC 20000 #endif /* 136 / 4 = 34 */ #define LINKER_QBIT_DELAY_US (34) #define SERIAL_TIMEOUT 2 #define RETRIES 3 static inline unsigned long readtsc() { unsigned int low, high; asm volatile("rdtsc" : "=a" (low), "=d" (high)); return low | ((unsigned long)(high) << 32); } unsigned long delay_start = 0; static void delay_us(unsigned long t) { delay_start+= t * 2800; // if (delay_start > readtsc() + 50 * 2800) /* 50 microseconds */ // sched_yield(); while (readtsc() < delay_start) ; } #if 0 static void delay_us(unsigned long t) { struct timeval t1, t2; if (t == 0) return; /* very short delay for slow machines */ gettimeofday(&t1, NULL); if (t > MIN_SLEEP_USEC) usleep(t - MIN_SLEEP_USEC); /* loop for the remaining time */ t2.tv_sec = t / 1000000UL; t2.tv_usec = t % 1000000UL; timeradd(&t1, &t2, &t1); do { gettimeofday(&t2, NULL); } while (timercmp(&t2, &t1, <)); } #endif #if 0 static void par_ctrl(int ctrl) { ioctl(ppdev_fd, PPWCONTROL, &ctrl); } static int par_read_status() { int status; ioctl(ppdev_fd, PPRSTATUS, &status); return status; } #endif static void pin_set(int x) { x = !!x; ioctl(ppdev_fd, PPWDATA, &x); } static void pin_ddr(int dir) { dir = dir ? 0 : PARPORT_CONTROL_DIRECTION; ioctl(ppdev_fd, PPDATADIR, &dir); } int pin_read() { int data; ioctl(ppdev_fd, PPRDATA, &data); return data & 1; } static void parallel_Init() { /* data=1, reset=0, sck=0 */ // par_ctrl(PARPORT_CONTROL_STROBE); pin_ddr(0); pin_set(1); } static void parallel_constructor() { const char *ppdev_name = "/dev/parport0"; ppdev_fd = open(ppdev_name, O_RDWR, 0); if (ppdev_fd == -1) { perror(ppdev_name); fprintf(stderr,"Failed to open ppdev.\n"); exit(1); } if (ioctl(ppdev_fd, PPCLAIM, 0) != 0) { perror("ioctl PPCLAIM"); close(ppdev_fd); ppdev_fd = -1; fprintf(stderr,"Failed to claim ppdev."); exit(1); } parallel_Init(); } static void parallel_destructor() { pin_ddr(0); ioctl(ppdev_fd, PPRELEASE, 0); close(ppdev_fd); } #define TICKS_PER_SECOND 2800000000 int main(int argc,char *argv[]) { unsigned long d; int i; parallel_constructor(); pin_ddr(0); /* Start tristate */ pin_set(0); pin_ddr(1); delay_start = readtsc(); for (i = 0;i < 2000;i++) { pin_set(1); delay_us(900); pin_set(0); delay_us(100); } for (;;) { for (i = 0;i < 1000;i++) { pin_set(1); d = 1084; delay_us(d); pin_set(0); delay_us(2000-d); } pin_set(1); d = 1900; delay_us(d); pin_set(0); delay_us(2000-d); delay_us(50000); for (i = 0;i < 30;i++) { pin_set(1); delay_us(d); pin_set(0); delay_us(2000-d); } } sleep(1); exit(0); parallel_destructor(); }