From 63d755835adff11984a70718010ca5bf8a4bc5ea Mon Sep 17 00:00:00 2001 From: Anders Blomdell <anders.blomdell@control.lth.se> Date: Thu, 11 Oct 2018 18:42:12 +0200 Subject: [PATCH] Add pcio processes, enhance avr target handling with multiple targets for one project --- .gitignore | 1 + Makefile | 20 ++- pcio/avr/Makefile | 19 +++ pcio/avr/pcio.c | 217 +++++++++++++++++++++++++++++ pcio/avr/pcio_w_usb.c | 218 ++++++++++++++++++++++++++++++ pcio/linux/Makefile | 21 +++ pcio/linux/pciotest.c | 285 +++++++++++++++++++++++++++++++++++++++ tools/find_avr_targets | 32 +++++ tools/find_linux_targets | 33 +++++ 9 files changed, 841 insertions(+), 5 deletions(-) create mode 100644 pcio/avr/Makefile create mode 100644 pcio/avr/pcio.c create mode 100644 pcio/avr/pcio_w_usb.c create mode 100644 pcio/linux/Makefile create mode 100644 pcio/linux/pciotest.c create mode 100755 tools/find_avr_targets create mode 100755 tools/find_linux_targets diff --git a/.gitignore b/.gitignore index 0ee7f02..9e1f2d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ */avr/compiled +*/linux/compiled *~ \ No newline at end of file diff --git a/Makefile b/Makefile index a95c907..9fee9e6 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,24 @@ all: + @echo "###" >&2 + @echo "### Atmel AVR targets ###" >&2 + @echo "###" >&2 @echo "Do 'make PROCESS.LOAD' or 'make PROCESS.FUSE'" >&2 @echo "where PROCESS is one of" >&2 - @for m in */*/Makefile ; do \ - echo " $$(dirname $$(dirname $$m))" >&2 \ - ; done + @./tools/find_avr_targets + @echo "###" >&2 + @echo "### Linux targets ###" >&2 + @echo "###" >&2 + @echo "Do 'make PROGRAM.LINUX'" >&2 + @echo "where PROGRAM is one of" >&2 + @./tools/find_linux_targets @echo >&2 @exit 1 %.LOAD: - make -C $*/avr $@ + make -C $$(./tools/find_avr_targets $*) $@ %.FUSE: - make -C $*/avr $@ + make -C $$(./tools/find_avr_targets $*) $@ + +%.LINUX: + make -C $$(./tools/find_linux_targets $*) $@ diff --git a/pcio/avr/Makefile b/pcio/avr/Makefile new file mode 100644 index 0000000..4ead37a --- /dev/null +++ b/pcio/avr/Makefile @@ -0,0 +1,19 @@ +TARGETS=pcio pcio_w_usb + +pcio.ARCH=avr +pcio.CHIP=atmega8 +# 16 MHz crystal, brown out +pcio.FUSE_L=0x1f +pcio.FUSE_H=0xd9 +pcio.C=pcio +pcio.H=../lib/serialio + +pcio_w_usb.ARCH=avr +pcio_w_usb.CHIP=atmega16 +# 16 MHz crystal, brown out +pcio_w_usb.FUSE_L=0x1f +pcio_w_usb.FUSE_H=0xd9 +pcio_w_usb.C=pcio_w_usb +pcio_w_usb.H=../lib/serialio + +include ../../lib/avr/Makefile.common diff --git a/pcio/avr/pcio.c b/pcio/avr/pcio.c new file mode 100644 index 0000000..a045fba --- /dev/null +++ b/pcio/avr/pcio.c @@ -0,0 +1,217 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +//#include <avr/signal.h> +#include "serialio.h" + +volatile unsigned char error; + + +volatile unsigned char serial_readbits; +volatile unsigned char serial_readchannels; +volatile unsigned char serial_readconfig; +volatile unsigned int ai0; +volatile unsigned int ai1; +volatile unsigned int ai2; +volatile unsigned int ai3; + +SIGNAL(ADC_vect) +{ + unsigned char channel = ADMUX & 0x0f; + unsigned int value = ADCW; + + switch (channel) { + case 0: { + channel = 1; + ai2 = value; + } break; + case 1: { + channel = 2; + ai3 = value; + } break; + case 2: { + channel = 3; + ai0 = value; + } break; + case 3: { + channel = 0; + ai1 = value; + } break; + default: { + channel = 0; + } break; + } + ADMUX = 0xc0 | channel; // Internal Vref, right adjust + ADCSR = 0xcf; // Enable ADC interrupts, Clock/128 + +} + +typedef enum { cmd_clear_bit, cmd_set_bit, + cmd_read_bit, cmd_read_chan } command; + +SIGNAL(USART_RXC_vect) +{ + char ch = UDR; + + switch (serialio_RXC(ch)) { + case serialio_clearbit: { + switch (serialio_channel) { + // Digital output buffer (ULN2803A) is inverting + case 0: { PORTB = PORTB | 0x01; } break; + case 1: { PORTB = PORTB | 0x10; } break; + case 2: { PORTB = PORTB | 0x20; } break; + case 3: { PORTC = PORTC | 0x10; } break; + case 4: { PORTC = PORTC | 0x20; } break; + case 5: { PORTB = PORTB | 0x08; } break; + } + } break; + case serialio_setbit: { + switch (serialio_channel) { + // Digital output buffer (ULN2803A) is inverting + case 0: { PORTB = PORTB & ~0x01; } break; + case 1: { PORTB = PORTB & ~0x10; } break; + case 2: { PORTB = PORTB & ~0x20; } break; + case 3: { PORTC = PORTC & ~0x10; } break; + case 4: { PORTC = PORTC & ~0x20; } break; + case 5: { PORTB = PORTB & ~0x08; } break; + } + } break; + case serialio_pollbit: { + if (serialio_channel <= 7) { + serial_readbits |= (1<<serialio_channel); + } + } break; + case serialio_pollchannel: { + if (serialio_channel <= 7) { + serial_readchannels |= (1<<serialio_channel); + } else if (serialio_channel == 31) { + serial_readconfig = 1; + } + } break; + case serialio_setchannel: { + switch (serialio_channel) { + case 0: { + OCR1A = serialio_value & 0x3ff; + } break; + case 1: { + OCR1B = serialio_value & 0x3ff; + } break; + } break; + } break; + case serialio_error: { + } break; + case serialio_more: { + } break; + } +} + +/* + * PB0 DO5 + * PB1 AO0 / DO4 + * PB2 AO1 / DO3 + * PB3 DO2 + * PB4 DO1 + * PB5 DO0 + * + * PC0 AI2 + * PC1 AI3 + * PC2 AI0 + * PC3 AI1 + * + * PD2 DI0 + * PD3 DI2 + * PD4 DI4 + * PD5 DI5 + * PD6 DI3 + * PD7 DI1 + * + */ +int main() +{ + serialio_init(); + serial_readbits = 0; + serial_readchannels = 0; + serial_readconfig = 0; + ai0 = 0; + ai1 = 0; + ai2 = 0; + ai3 = 0; + PORTD = 0xfc; // PortD, pull up + DDRD = 0x00; // PortD, all input + PORTB = 0x00; // PortB, no pull up + DDRB = 0xff; // PortB, all outputs + PORTC = 0x00; // PortC, no pull up + DDRC = 0x30; // PortC, bit 4 & 5 outputs + TCCR0 = 0x05; // Timer0, Clock / 1024 + TCCR1A = 0xa3; // OC1A & OC1B 10 bit PWM (PC), clear on upcounting + TCCR1B = 0x01; // Clock / 1 + UCSRA = 0x00; // USART: + UCSRB = 0x98; // USART: RxIntEnable|RxEnable|TxEnable + UCSRC = 0x86; // USART: 8bit, no parity + UBRRH = 0; // USART: 115200 @ 14.7456MHz + UBRRL = 7; // USART: 115200 @ 14.7456MHz + ADMUX = 0xc0; // Internal Vref, right adjust + ADMUX = 0xce; // Internal Vref, right adjust, read 1.22V (Vbg) + ADCSR = 0xcf; // Enable ADC interrupts, Clock/128 + SREG = 0x80; // Global interrupt enable + OCR1A = 512 & 0x3ff; + OCR1B = 512 & 0x3ff; + + while (1) { + unsigned char bits, channels, config; + SREG = 0x00; // Global interrupt disable + bits = serial_readbits; + serial_readbits = 0; + channels = serial_readchannels; + serial_readchannels = 0; + config = serial_readconfig; + serial_readconfig = 0; + SREG = 0x80; // Global interrupt enable + if (bits & 0x01) { serialio_putbit(0, PIND & 0x04); } + if (bits & 0x02) { serialio_putbit(1, PIND & 0x08); } + if (bits & 0x04) { serialio_putbit(2, PIND & 0x10); } + if (bits & 0x08) { serialio_putbit(3, PIND & 0x20); } + if (bits & 0x10) { serialio_putbit(4, PIND & 0x40); } + if (bits & 0x20) { serialio_putbit(5, PIND & 0x80); } + if (channels & 0x01) { serialio_putchannel(0, 1023 - ai0); } + if (channels & 0x02) { serialio_putchannel(1, 1023 - ai1); } + if (channels & 0x04) { serialio_putchannel(2, 1023 - ai2); } + if (channels & 0x08) { serialio_putchannel(3, 1023 - ai3); } + if (config) { + CONF_DIGITAL_IN(0, CONF_RESOLUTION(1)); // DI0 + CONF_DIGITAL_IN(1, CONF_RESOLUTION(1)); // DI1 + CONF_DIGITAL_IN(2, CONF_RESOLUTION(1)); // DI2 + CONF_DIGITAL_IN(3, CONF_RESOLUTION(1)); // DI3 + CONF_DIGITAL_IN(4, CONF_RESOLUTION(1)); // DI4 + CONF_DIGITAL_IN(5, CONF_RESOLUTION(1)); // DI5 + + CONF_DIGITAL_OUT(0, CONF_RESOLUTION(1)); // DO0 + CONF_DIGITAL_OUT(1, CONF_RESOLUTION(1)); // DO1 + CONF_DIGITAL_OUT(2, CONF_RESOLUTION(1)); // DO2 + CONF_DIGITAL_OUT(3, CONF_RESOLUTION(1)); // DO3 + CONF_DIGITAL_OUT(4, CONF_RESOLUTION(1)); // DO4 + CONF_DIGITAL_OUT(5, CONF_RESOLUTION(1)); // DO5 + + CONF_ANALOG_IN(0, CONF_RESOLUTION(10)); // AI0 + CONF_ANALOG_IN(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(1, CONF_RESOLUTION(10)); // AI1 + CONF_ANALOG_IN(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(2, CONF_RESOLUTION(10)); // AI2 + CONF_ANALOG_IN(2, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(2, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(3, CONF_RESOLUTION(10)); // AI3 + CONF_ANALOG_IN(3, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(3, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + + CONF_ANALOG_OUT(0, CONF_RESOLUTION(10)); // AO0 + CONF_ANALOG_OUT(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(9800))); + CONF_ANALOG_OUT(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10170))); + CONF_ANALOG_OUT(1, CONF_RESOLUTION(10)); // AO1 + CONF_ANALOG_OUT(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(9800))); + CONF_ANALOG_OUT(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10106))); + + CONF_END(); + } + } +} diff --git a/pcio/avr/pcio_w_usb.c b/pcio/avr/pcio_w_usb.c new file mode 100644 index 0000000..3d68869 --- /dev/null +++ b/pcio/avr/pcio_w_usb.c @@ -0,0 +1,218 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include "serialio.h" + +volatile unsigned char error; + + +volatile unsigned char serial_readbits; +volatile unsigned char serial_readchannels; +volatile unsigned char serial_readconfig; +volatile unsigned int ai0; +volatile unsigned int ai1; +volatile unsigned int ai2; +volatile unsigned int ai3; + +SIGNAL(ADC_vect) +{ + unsigned char channel = ADMUX & 0x0f; + unsigned int value = ADCW; + + switch (channel) { + case 0: { + channel = 1; + ai0 = value; + } break; + case 1: { + channel = 2; + ai1 = value; + } break; + case 2: { + channel = 3; + ai2 = value; + } break; + case 3: { + channel = 0; + ai3 = value; + } break; + default: { + channel = 0; + } break; + } + ADMUX = 0xc0 | channel; // Internal Vref, right adjust + ADCSRA = 0xcf; // Enable ADC interrupts, Clock/128 + +} + +typedef enum { cmd_clear_bit, cmd_set_bit, + cmd_read_bit, cmd_read_chan } command; + +SIGNAL(USART_RXC_vect) +{ + char ch = UDR; + + switch (serialio_RXC(ch)) { + case serialio_clearbit: { + switch (serialio_channel) { + // Digital output buffer (ULN2803A) is inverting + case 0: { PORTC |= 0x04; } break; + case 1: { PORTC |= 0x08; } break; + case 2: { PORTC |= 0x10; } break; + case 3: { PORTC |= 0x20; } break; + case 4: { PORTC |= 0x40; } break; + case 5: { PORTC |= 0x80; } break; + } + } break; + case serialio_setbit: { + switch (serialio_channel) { + // Digital output buffer (ULN2803A) is inverting + case 0: { PORTC &= ~0x04; } break; + case 1: { PORTC &= ~0x08; } break; + case 2: { PORTC &= ~0x10; } break; + case 3: { PORTC &= ~0x20; } break; + case 4: { PORTC &= ~0x40; } break; + case 5: { PORTC &= ~0x80; } break; + } + } break; + case serialio_pollbit: { + if (serialio_channel <= 7) { + serial_readbits |= (1<<serialio_channel); + } + } break; + case serialio_pollchannel: { + if (serialio_channel <= 7) { + serial_readchannels |= (1<<serialio_channel); + } else if (serialio_channel == 31) { + serial_readconfig = 1; + } + } break; + case serialio_setchannel: { + switch (serialio_channel) { + case 0: { + OCR1B = serialio_value & 0x3ff; + } break; + case 1: { + OCR1A = serialio_value & 0x3ff; + } break; + } break; + } break; + case serialio_error: { + } break; + case serialio_more: { + } break; + } +} + +/* + * PA0 AI0 + * PA1 AI1 + * PA2 AI2 + * PA3 AI3 + * PA4 DI0 + * PA5 DI1 + * PA6 DI2 + * PA7 DI3 + * + * PC2 DO0 + * PC3 DO1 + * PC4 DO2 + * PC5 DO3 + * PC6 DO4 + * PC7 DO5 + * + * PD3 DI5 + * PD4 AO0 + * PD5 AO1 + * PD7 DI4 + * + */ +int main() +{ + serialio_init(); + serial_readbits = 0; + serial_readchannels = 0; + serial_readconfig = 0; + ai0 = 0; + ai1 = 0; + ai2 = 0; + ai3 = 0; + PORTA = 0xf0; // PortA, pull-ups + DDRA = 0x00; // PortA, all inputs + PORTC = 0x00; // PortC, initial data + DDRC = 0xfc; // PortC, 2-7 outputs + PORTD = 0x88; // PortD, pull-ups + DDRD = 0x30; // PortD, 4-5 outputs + TCCR0 = 0x05; // Timer0, Clock / 1024 + TCCR1A = 0xa3; // OC1A & OC1B 10 bit PWM (PC), clear on upcounting + TCCR1B = 0x01; // Clock / 1 + UCSRA = 0x00; // USART: + UCSRB = 0x98; // USART: RxIntEnable|RxEnable|TxEnable + UCSRC = 0x86; // USART: 8bit, no parity + UBRRH = 0; // USART: 115200 @ 14.7456MHz + UBRRL = 7; // USART: 115200 @ 14.7456MHz + ADMUX = 0xc0; // Internal Vref, right adjust + ADMUX = 0xce; // Internal Vref, right adjust, read 1.22V (Vbg) + ADCSRA = 0xcf; // Enable ADC interrupts, Clock/128 + SREG = 0x80; // Global interrupt enable + OCR1A = 512 & 0x3ff; + OCR1B = 512 & 0x3ff; + + while (1) { + unsigned char bits, channels, config; + SREG = 0x00; // Global interrupt disable + bits = serial_readbits; + serial_readbits = 0; + channels = serial_readchannels; + serial_readchannels = 0; + config = serial_readconfig; + serial_readconfig = 0; + SREG = 0x80; // Global interrupt enable + if (bits & 0x01) { serialio_putbit(0, PINA & 0x10); } + if (bits & 0x02) { serialio_putbit(1, PINA & 0x20); } + if (bits & 0x04) { serialio_putbit(2, PINA & 0x40); } + if (bits & 0x08) { serialio_putbit(3, PINA & 0x80); } + if (bits & 0x10) { serialio_putbit(4, PIND & 0x80); } + if (bits & 0x20) { serialio_putbit(5, PIND & 0x08); } + if (channels & 0x01) { serialio_putchannel(0, 1023 - ai0); } + if (channels & 0x02) { serialio_putchannel(1, 1023 - ai1); } + if (channels & 0x04) { serialio_putchannel(2, 1023 - ai2); } + if (channels & 0x08) { serialio_putchannel(3, 1023 - ai3); } + if (config) { + CONF_DIGITAL_IN(0, CONF_RESOLUTION(1)); // DI0 + CONF_DIGITAL_IN(1, CONF_RESOLUTION(1)); // DI1 + CONF_DIGITAL_IN(2, CONF_RESOLUTION(1)); // DI2 + CONF_DIGITAL_IN(3, CONF_RESOLUTION(1)); // DI3 + CONF_DIGITAL_IN(4, CONF_RESOLUTION(1)); // DI4 + CONF_DIGITAL_IN(5, CONF_RESOLUTION(1)); // DI5 + + CONF_DIGITAL_OUT(0, CONF_RESOLUTION(1)); // DO0 + CONF_DIGITAL_OUT(1, CONF_RESOLUTION(1)); // DO1 + CONF_DIGITAL_OUT(2, CONF_RESOLUTION(1)); // DO2 + CONF_DIGITAL_OUT(3, CONF_RESOLUTION(1)); // DO3 + CONF_DIGITAL_OUT(4, CONF_RESOLUTION(1)); // DO4 + CONF_DIGITAL_OUT(5, CONF_RESOLUTION(1)); // DO5 + + CONF_ANALOG_IN(0, CONF_RESOLUTION(10)); // AI0 + CONF_ANALOG_IN(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(1, CONF_RESOLUTION(10)); // AI1 + CONF_ANALOG_IN(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(2, CONF_RESOLUTION(10)); // AI2 + CONF_ANALOG_IN(2, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(2, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + CONF_ANALOG_IN(3, CONF_RESOLUTION(10)); // AI3 + CONF_ANALOG_IN(3, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10400))); + CONF_ANALOG_IN(3, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10300))); + + CONF_ANALOG_OUT(0, CONF_RESOLUTION(10)); // AO0 + CONF_ANALOG_OUT(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(9800))); + CONF_ANALOG_OUT(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10170))); + CONF_ANALOG_OUT(1, CONF_RESOLUTION(10)); // AO1 + CONF_ANALOG_OUT(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(9800))); + CONF_ANALOG_OUT(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10106))); + + CONF_END(); + } + } +} diff --git a/pcio/linux/Makefile b/pcio/linux/Makefile new file mode 100644 index 0000000..7a3863d --- /dev/null +++ b/pcio/linux/Makefile @@ -0,0 +1,21 @@ +CC=gcc +CFLAGS.pciotest=-Wall -lpthread + +.SUFFIXES: .c + +all: pciotest.LINUX + +.PHONY: %.LINUX +%.LINUX: compiled/% | compiled + @/bin/true + +.PRECIOUS: compiled/% +compiled/%: %.c | compiled + echo $* + $(CC) $(CFLAGS.$*) -o $@ $< + +compiled: + mkdir -p $@ + +clean: + rm -rf compiled diff --git a/pcio/linux/pciotest.c b/pcio/linux/pciotest.c new file mode 100644 index 0000000..093dde7 --- /dev/null +++ b/pcio/linux/pciotest.c @@ -0,0 +1,285 @@ +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <string.h> +#include <poll.h> +#include <pthread.h> +#include <semaphore.h> +#include <unistd.h> +#include <signal.h> + +static volatile int OK = 1; + +static pthread_t reader, writer; +static int digital_in = 0; +static int digital_out = 0; +static int analog_in = 0; +static int analog_out = 0; +static int encoder_in = 0; +static int maxdata_in[32]; +static int maxdata_out[32]; + +static int millivolts(int value) { + int val = value >> 4; + int unit = value & 0x7; + int sign = value & 0x8; + if (sign != 0) { val = -val; } + switch (unit) { + case 0: { val = val * 1000; } break; + case 1: {} break; + case 2: {} break; + } + return val; +} + +void *Reader(void *argument) { + int *fd, length, value; + + fd = argument; + length = 0; + value = 0; + for (;;) { + unsigned char ch; + + if (read(*fd, &ch, 1) <= 0) { + fprintf(stderr, "Read failed\n"); + OK = 0; + break; + } + length++; + if ((ch & 0x80) == 0x80) { + value = (value << 7) | (ch & 0x7f); + } else { + unsigned int channel = ch & 0x1f; + value = (value << 2) | ((ch & 0x60) >> 5); + if (length == 1) { + unsigned char cmd = (ch & 0x60) >> 5; + switch (cmd) { + case 0: { // Clear bit + printf("#%d:0 ", channel); + } break; + case 1: { // Set bit + printf("#%d:1 ", channel); + } break; + case 2: { // Read bit + // Currently unused + } break; + case 3: { // Read channel + // Currently unused + } break; + } + } else { + switch (channel) { + case 0:{ printf("I0=%3d ", value); } break; + case 1:{ printf("I1=%3d ", value); } break; + case 2:{ printf("I2=%3d ", value); } break; + case 3:{ printf("I3=%3d ", value); } break; + case 4:{ printf("I4=%3d ", value); } break; + case 5:{ printf("I5=%3d ", value); } break; + case 6:{ printf("I6=%3d ", value); } break; + case 31:{ + int kind = (value>>5)& 0x7; + int cmd = (value>>8)& 0x3; + int conf_channel = value & 0x1f; + int *maxdata = 0; + switch(kind) { + case 1: { + printf("digital in "); + digital_in |= 1 << conf_channel; + } break; + case 2: { + printf("digital out "); + digital_out |= 1 << conf_channel; + } break; + case 3: { + printf("analog in "); + analog_in |= 1 << conf_channel; + maxdata = &maxdata_in[conf_channel]; + } break; + case 4: { + printf("analog out "); + analog_out |= 1 << conf_channel; + maxdata = &maxdata_out[conf_channel]; + } break; + case 5: { + printf("encoder in "); + encoder_in |= 1 << conf_channel; + maxdata = &maxdata_in[conf_channel]; + } break; + } + printf("#%d ", conf_channel); + switch (cmd) { + case 0: { + printf("maxdata %d\n", (1<<(value>>10))-1); + if (maxdata) { *maxdata = (1<<(value>>10))-1; } + } break; + case 1: { printf("min %d\n", millivolts(value>>10)); } break; + case 2: { printf("max %d\n", millivolts(value>>10)); } break; + default: { printf("cmd %d %d\n", cmd, (value>>10)); } break; + } + } break; + default: { + printf("%d=%x (%d)\n", channel, value, length); + } break; + } + } + value = 0; + length = 0; + } + } + return NULL; +} + +void poll_io(int fd) +{ + char ch; + int i; + + // Poll digital in + for (i = 0 ; i < 32 ; i++) { + if (digital_in & (1 << i)) { + ch = 0x40 | i; + write(fd, &ch, 1); + } + } + // Poll analog in + for (i = 0 ; i < 31 ; i++) { + if (analog_in & (1 << i)) { + ch = 0x60 | i; + write(fd, &ch, 1); + } + } + // Poll encoder in + for (i = 0 ; i < 31 ; i++) { + if (encoder_in & (1 << i)) { + ch = 0x60 | i; + write(fd, &ch, 1); + } + } +} + +static void put_char(int fd, unsigned char value) { + write(fd, &value, 1); +} + +static void put_channel(int fd, int channel, int value) { + if (value >= (1L<<30)) { put_char(fd, 0x80 | ((value >> 30) & 0x03)); } + if (value >= (1L<<23)) { put_char(fd, 0x80 | ((value >> 23) & 0x7f)); } + if (value >= (1L<<16)) { put_char(fd, 0x80 | ((value >> 16) & 0x7f)); } + if (value >= (1L<< 9)) { put_char(fd, 0x80 | ((value >> 9) & 0x7f)); } + put_char(fd, 0x80 | ((value >> 2) & 0x7f)); + put_char(fd, ((value << 5) & 0x60) | channel); +} + +void *Writer(void *argument) { + int *fd = argument; + + // Read configuration + char ch = 0x60 | 31; + write(*fd, &ch, 1); + usleep(1000000); + + while (OK) { + int i, j; + for (i = 0 ; i < 32 ; i++) { + for (j = 0 ; j < 32 ; j++) { + if (digital_out & (1 << j)) { + if (i == j) { + printf("1"); + ch = 0x20 | j; + } else { + printf("0"); + ch = 0x00 | j; + } + write(*fd, &ch, 1); + } + } + printf(" "); + for (j = 0 ; j < 31 ; j++) { + if (analog_out & (1 << j)) { + int value = (((i + j) % 32) * maxdata_out[j]) / 32; +// printf("%d = %d\n", j, value); + put_channel(*fd, j, value); + } + } + // Let analog values settle + usleep(10000); + poll_io(*fd); + usleep(100000); + printf("\n"); + } + } + return NULL; +} + + +int main(int argc, char *argv[]) { + int avr; + struct termios old_settings, new_settings; + + if (argc <= 1) { + avr = open("/dev/ttyS0", O_RDWR); + } else { + avr = open(argv[1], O_RDWR); + } + if (avr < 0) { + printf("Couldn't open terminal line\n"); + exit(1); + } + + if (lockf(avr, F_TLOCK, 0)) { + printf("Couldn't lock terminal line\n"); + exit(1); + } + + tcgetattr(avr, &old_settings); + new_settings = old_settings; + new_settings.c_iflag = 0; + new_settings.c_oflag = 0; + new_settings.c_lflag = 0; + new_settings.c_cflag = CLOCAL | CS8 | CREAD; + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + if (argc <= 2) { + cfsetispeed(&new_settings, B115200); + cfsetospeed(&new_settings, B115200); + } else { + if (strcmp(argv[2], "2400") == 0) { + cfsetispeed(&new_settings, B2400); + cfsetospeed(&new_settings, B2400); + } else if (strcmp(argv[2], "9600") == 0) { + cfsetispeed(&new_settings, B9600); + cfsetospeed(&new_settings, B9600); + } else if (strcmp(argv[2], "38400") == 0) { + cfsetispeed(&new_settings, B38400); + cfsetospeed(&new_settings, B38400); + } else if (strcmp(argv[2], "57600") == 0) { + cfsetispeed(&new_settings, B57600); + cfsetospeed(&new_settings, B57600); + } else if (strcmp(argv[2], "115200") == 0) { + cfsetispeed(&new_settings, B115200); + cfsetospeed(&new_settings, B115200); + } else { + printf("Unknown speed %s\n", argv[2]); + exit(1); + } + } + + tcsetattr(avr, TCSADRAIN, &new_settings); + + pthread_create(&reader, NULL, Reader, &avr); + pthread_create(&writer, NULL, Writer, &avr); + while (OK) { + sleep(1); + } + + lockf(avr, F_ULOCK, 0); + tcsetattr(avr, TCSADRAIN, &old_settings); + close(avr); + +} diff --git a/tools/find_avr_targets b/tools/find_avr_targets new file mode 100755 index 0000000..2fbe8f8 --- /dev/null +++ b/tools/find_avr_targets @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +ROOTDIR=$(dirname $(dirname $0)) + +err_report() { + echo "No AVR target(s) found [line $1]" +} + +trap 'err_report $LINENO' ERR + +all_avr_programs() { + egrep '^\S+.CHIP=' ${ROOTDIR}/*/avr/Makefile \ + | sed -re 's|^.*/(\S+)/avr/Makefile:(\S+).CHIP=(\S+)\s*$|\2,\1,\3|' +} + +target_dir() { + dirname $(egrep -l "$1.CHIP=" ${ROOTDIR}/*/avr/Makefile) +} + +if [ $# -eq 0 ] ; then + # Report all possible AVR target programs + for l in $(all_avr_programs | sort) ; do + printf " %-25s %-25s %s\n" \ + $(echo ${l} | sed -re 's|(.*),(.*),(.*)|\1 (\2) [\3]|') + done +elif [ $# -eq 1 ] ; then + target_dir $1 +else + exit 1 +fi diff --git a/tools/find_linux_targets b/tools/find_linux_targets new file mode 100755 index 0000000..f268553 --- /dev/null +++ b/tools/find_linux_targets @@ -0,0 +1,33 @@ +#! /bin/bash + +set -e + +err_report() { + echo "No Linux programs found [line $1]" +} + +trap 'err_report $LINENO' ERR + +ROOTDIR=$(dirname $(dirname $0)) + +all_linux_programs() { + egrep -H '^CFLAGS.\S+=' ${ROOTDIR}/*/linux/Makefile \ + | sed -re 's|^.*/(\S+)/linux/Makefile:CFLAGS.(\S+)=.*$|\2,\1|' + exit 1 +} + +target_dir() { + dirname $(egrep -l "^CFLAGS.$1=" ${ROOTDIR}/*/linux/Makefile) +} + +if [ $# -eq 0 ] ; then + # Report all possible AVR target programs + for l in $(all_linux_programs | sort) ; do + printf " %-25s %-25s %s\n" \ + $(echo ${l} | sed -re 's|(.*),(.*)|\1 (\2)|') + done +elif [ $# -eq 1 ] ; then + target_dir $1 +else + exit 1 +fi -- GitLab