Below is the file 'i2c.c' from this revision. You can also download the file.
#include <windows.h> #include <stdio.h> #include "ioport.h" /* * This is a hacked up piece of bit-banging code to query a Wii Motion Plus * over I2C on the parallel port. It's not polished code by a long way. * You have been warned. */ /* This is the first parallel port on most PCs. */ #define PAR 0x378 #define SCL_MASK 0x40 #define SDA_MASK 0x80 #define SDA_IN_MASK 0x40 #if 0 #define DELAY Sleep(1) #else int _delay; #define DELAY for (_delay = 0; _delay < DELAY_COUNT; _delay++) {} #endif /* * Carefully Calibrated[tm] delay loop. * This works on my PC, it may not work on yours. * You have been warned. */ #define DELAY_COUNT 10000 #define NCAL 100 int roll0, pitch0, yaw0; int paroutvalue = SCL_MASK | SDA_MASK; void initparallel(void) { paroutvalue = SCL_MASK | SDA_MASK; outportb(PAR+2, 0x20); outportb(PAR+0, paroutvalue); DELAY; } void setscl(int value) { /* We have an inverter in the way */ value = !value; paroutvalue &= ~SCL_MASK; paroutvalue |= (value ? SCL_MASK : 0); outportb(PAR+0, paroutvalue); DELAY; } void setsda(int value) { /* We have an inverter in the way */ value = !value; paroutvalue &= ~SDA_MASK; paroutvalue |= (value ? SDA_MASK : 0); outportb(PAR+0, paroutvalue); DELAY; } int getsda(void) { int value; value = inportb(PAR+1) & SDA_IN_MASK; /* We have an inverter in the way */ value = !value; return (value != 0); } void send_start(void) { setsda(1); setscl(1); setsda(0); } void send_stop(void) { setsda(0); setscl(1); setsda(1); } int send_byte(int value) { int i; int ack; for (i = 0; i < 8; i++) { setscl(0); setsda(value & 0x80); setscl(1); value = value << 1; } setscl(0); setsda(1); setscl(1); ack = !getsda(); setscl(0); if (!ack) { send_stop(); printf("ACK not received\n"); return FALSE; } return TRUE; } int get_byte(int last) { int i; int value = 0; setsda(1); for (i = 0; i < 8; i++) { setscl(0); setscl(1); value = value << 1; value |= (getsda()?1:0); } setscl(0); if (!last) setsda(0); setscl(1); setscl(0); setsda(1); return value; } void setupi2c(void) { send_start(); send_byte((0x53 << 1) + 0); /* Address 0x53, write */ send_byte(0xfe); send_byte(0x04); send_stop(); } void get_readings(int *b) { send_start(); send_byte((0x52 << 1) + 0); /* Address 0x52, write */ send_byte(0); send_stop(); send_start(); send_byte((0x52 << 1) + 1); /* Address 0x52, read */ b[0] = get_byte(0); b[1] = get_byte(0); b[2] = get_byte(0); b[3] = get_byte(0); b[4] = get_byte(0); b[5] = get_byte(1); send_stop(); } void query_device(int *roll, int *pitch, int *yaw) { int b[6]; get_readings(b); *yaw = ((b[3]>>2)<<8) + b[0] - yaw0; *pitch = ((b[4]>>2)<<8) + b[1] - pitch0; *roll = ((b[5]>>2)<<8) + b[2] - roll0; } void calibrate(void) { int b[6]; int i; yaw0 = 0; pitch0 = 0; roll0 = 0; printf("Calibrating... "); for (i = 0; i < NCAL; i++) { printf("%2d", i); get_readings(b); yaw0 += ((b[3]>>2)<<8) + b[0]; pitch0 += ((b[4]>>2)<<8) + b[1]; roll0 += ((b[5]>>2)<<8) + b[2]; printf("\b\b"); } yaw0 = yaw0 / NCAL; pitch0 = pitch0 / NCAL; roll0 = roll0 / NCAL; printf("done\n"); printf("Calibrated values: %d, %d, %d\n", roll0, pitch0, yaw0); }