/* * Digital in/out and poll commands are sent as one byte: * * +-+-+-+-+-+-+-+-+ * |0|0 0| chan | Bit clear * +-+-+-+-+-+-+-+-+ * * +-+-+-+-+-+-+-+-+ * |0|0 1| chan | Bit set * +-+-+-+-+-+-+-+-+ * * +-+-+-+-+-+-+-+-+ * |0|1 0| chan | Bit get * +-+-+-+-+-+-+-+-+ * * +-+-+-+-+-+-+-+-+ * |0|1 1| chan | Channel get * +-+-+-+-+-+-+-+-+ * * * Channels are sent as 2 to 6 bytes, depending on resolution: * * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * 2 |1| bit8...bit2 | |0|bit| chan | * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * 3 |1|bit15...bit9 | |1| bit8...bit2 | |0|bit| chan | * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * * ... * * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * 6 |1|bit31...bit30| |1|bit29...bit23| ... |0|bit| chan | * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * * * * Channel 31 is special, as it serves as the configuration channel. When * reading from it multiple responses are sent with the following layout * * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * | command specific data |cmd|kind |conf chan| * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * * kind: 000 == end of configuration * 001 == digital in * 010 == digital out * 011 == analog in * 100 == analog out * 101 == counter in * *cmd == 0 (Resolution) * * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * | | # of bits |0 0|kind |conf chan| * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * * # of bits (1..32) * *cmd == 1 (Minimum value) * * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * | minimum |S| unit|0 1|kind |conf chan| * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * * S (sign): 0 == + * 1 == - * unit: 000 == V * 001 == mV * 010 == uV * 100 == A * *cmd == 2 (Maximum value) * * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * | maximum |S| unit|1 0|kind |conf chan| * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * * S (sign): 0 == + * 1 == - * unit: 000 == V * 001 == mV * 010 == uV * 100 == A */ #include <avr/io.h> static volatile unsigned long serialio_value; static volatile unsigned char serialio_channel, serialio_length; static inline void serialio_putchar(unsigned char ch) { while ((UCSRA & 0x20) == 0) {}; UDR = ch; } static inline void serialio_putbit(unsigned char channel, unsigned char value) { if (value) { serialio_putchar(0x20 | (channel & 0x1f)); } else { serialio_putchar(0x00 | (channel & 0x1f)); } } static inline void serialio_putchannel(unsigned char channel, unsigned long value) { if (value >= (1L<<30)) { serialio_putchar(0x80 | ((value >> 30) & 0x03)); } if (value >= (1L<<23)) { serialio_putchar(0x80 | ((value >> 23) & 0x7f)); } if (value >= (1L<<16)) { serialio_putchar(0x80 | ((value >> 16) & 0x7f)); } if (value >= (1L<< 9)) { serialio_putchar(0x80 | ((value >> 9) & 0x7f)); } serialio_putchar(0x80 | ((value >> 2) & 0x7f)); serialio_putchar(((value << 5) & 0x60) | (channel & 0x1f)); } #define CONF_DIG_IN(channel) (0x20 | (channel)&0x1f) #define CONF_DIG_OUT(channel) (0x40 | (channel)&0x1f) #define CONF_END() serialio_putchannel(31, 0) #define CONF_DIGITAL_IN(chan, config) \ serialio_putchannel(31, (0x20|(chan&0x1f)|(config&0xffffff00))) #define CONF_DIGITAL_OUT(chan, config) \ serialio_putchannel(31, (0x40|(chan&0x1f)|(config&0xffffff00))) #define CONF_ANALOG_IN(chan, config) \ serialio_putchannel(31, (0x60|(chan&0x1f)|(config&0xffffff00))) #define CONF_ANALOG_OUT(chan, config) \ serialio_putchannel(31, (0x80|(chan&0x1f)|(config&0xffffff00))) #define CONF_ENCODER_IN(chan, config) \ serialio_putchannel(31, (0xa0|(chan&0x1f)|(config&0xffffff00))) #define CONF_RESOLUTION(bits) (((bits)<<10)|0x000) #define CONF_MIN(value) ((value)|0x100) #define CONF_MAX(value) ((value)|0x200) #define CONF_NEGATIVE_VOLT(volt) (((long)(volt)<<14)|0x2000) #define CONF_POSITIVE_VOLT(volt) ((long)(volt)<<14) #define CONF_NEGATIVE_MILLIVOLT(millivolt) (((long)(millivolt)<<14)|0x2400) #define CONF_POSITIVE_MILLIVOLT(millivolt) ((long)(millivolt)<<14|0x400) #define CONF_POSITIVE_AMPERE(ampere) (((long)(ampere)<<14)|0x1000) static inline void serialio_init() { serialio_value = 0; serialio_channel = 255; serialio_length = 0; } typedef enum { serialio_error, serialio_more, serialio_clearbit, serialio_setbit, serialio_setchannel, serialio_pollbit, serialio_pollchannel } serialio_rxc_status; static inline serialio_rxc_status serialio_RXC(unsigned char ch) { unsigned char result = serialio_error; if (serialio_length == 0) { serialio_value = 0; } serialio_length++; if ((ch & 0x80) == 0x80) { // Collect yet another byte for later processing serialio_value = (serialio_value << 7) | (ch & 0x7f); result = serialio_more; } else { serialio_value = (serialio_value << 2) | ((ch & 0x60) >> 5); serialio_channel = ch & 0x1f; if (serialio_length == 1) { switch (serialio_value & 0x03) { // Digital output buffer (ULN2803A) is inverting case 0: { result = serialio_clearbit; } break; case 1: { result = serialio_setbit; } break; case 2: { result = serialio_pollbit; } break; case 3: { result = serialio_pollchannel; } break; } } else { result = serialio_setchannel; } serialio_length = 0; } return result; }