#define _BSD_SOURCE #include #include #include #include #include #include #include /* Some of the concepts here taken from src/sys/i386/i386/elan-mmcr.c */ #define DURATION(a, b) ((b.tv_sec - a.tv_sec) * 1000000) + (b.tv_usec - a.tv_usec) #define ON 1 #define OFF 0 static uint16_t *mmcr; /* Turn pins high or low */ void led(u_int pin, int state) { int offset = 0; u_int val = 0xc34; if (pin > 16) offset = 2; /* Turn the pin number into a bit */ pin = 1 << (pin & 0xf); if (state == 0) val ^= 0xc; /* Why do we bother dividing by 2? Not sure :( */ mmcr[(val + offset) / 2] = pin; } /* usleep(3) and select(2) are unreliable. Let's spin wait instead */ void waittime(long duration) { struct timeval start; struct timeval now; gettimeofday(&start, NULL); for (gettimeofday(&now, NULL); DURATION(start, now) < duration; gettimeofday(&now, NULL)) ; } int main() { int fd; int state = ON; fd = open("/dev/elan-mmcr", O_RDWR); if (fd < 0) err(1, "/dev/elan-mmcr"); mmcr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); int count = 0; int interval = 10000; // 10ms interval, in theory... int duty_cycle = 0; // duty cycle is how long the 'on' state should be. // Same units as interval (microseconds) int dir = 1; for (count = 0; ; count++) { duty_cycle += 100 * dir; /* duty cycle stepping of 100usecs */ if (duty_cycle >= interval) { duty_cycle = interval; dir = -1; } if (duty_cycle <= 0) { duty_cycle = 0; dir = 1; } state = ON; led(5, state); // led 5 == gpio5 == PIO1? led(9, state); // led 9 == error led waittime(interval - (interval - duty_cycle)); state = OFF; led(5, state); led(9, state); waittime(interval - duty_cycle); } return 0; }