From 373bb32332b117236720af0ff971769fc5930ba6 Mon Sep 17 00:00:00 2001 From: James McKenzie Date: Mon, 15 Dec 2014 12:05:41 +0000 Subject: fish --- userland/Makefile | 20 ++ userland/cp210x.c | 534 ++++++++++++++++++++++++++++++++++++++++++++ userland/cp210x.h | 97 ++++++++ userland/cp210x_int.h | 82 +++++++ userland/libradiator.c | 364 ++++++++++++++++++++++++++++++ userland/program_radiator.c | 23 ++ userland/radiator.c | 34 +++ userland/radiator.h | 21 ++ 8 files changed, 1175 insertions(+) create mode 100644 userland/Makefile create mode 100644 userland/cp210x.c create mode 100644 userland/cp210x.h create mode 100644 userland/cp210x_int.h create mode 100644 userland/libradiator.c create mode 100644 userland/program_radiator.c create mode 100644 userland/radiator.c create mode 100644 userland/radiator.h (limited to 'userland') diff --git a/userland/Makefile b/userland/Makefile new file mode 100644 index 0000000..d45447c --- /dev/null +++ b/userland/Makefile @@ -0,0 +1,20 @@ + +PROGS=radiator program_radiator +CSRCS=libradiator.c cp210x.c + +USBINC=$(shell pkg-config --cflags libusb-1.0) +USBLIB=$(shell pkg-config --libs libusb-1.0) + +CFLAGS=${USBINC} -g -Wall -Wno-unused +LIBS=${USBLIB} -g + +OBJS=${CSRCS:%.c=%.o} + +default:${PROGS} + +${PROGS}: %:%.o ${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} $@.o ${LIBS} + + +clean: + /bin/rm -f core ${OBJS} ${PROGS} ${PROGS:%=%.o} diff --git a/userland/cp210x.c b/userland/cp210x.c new file mode 100644 index 0000000..2c1892b --- /dev/null +++ b/userland/cp210x.c @@ -0,0 +1,534 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cp210x_int.h" +#include "cp210x.h" + + +#define cpu_to_le32(a) htole32(a) +#define le32_to_cpu(a) le32toh(a) + +#define cpu_to_be16(a) htobe16(a) +#define be16_to_cpu(a) be16toh(a) + +#define TIMEOUT 300 + + +static int +cp210x_ctlmsg (CP210X * c, uint8_t request, + uint8_t requestype, uint16_t value, uint16_t index, void *data, + uint16_t size) +{ + uint8_t *tbuf; + int ret; + + if (!(tbuf = malloc (size))) + return -ENOMEM; + if (requestype & 0x80) + { + ret = libusb_control_transfer (c->handle, requestype, + request, value, index, tbuf, size, + TIMEOUT); + if (ret > 0 && size) + memcpy (data, tbuf, size); + } + else + { + if (size) + memcpy (tbuf, data, size); + ret = libusb_control_transfer (c->handle, requestype, + request, value, index, tbuf, size, + TIMEOUT); + } + free (tbuf); + + if (ret < 0 && ret != -EPIPE) + { + fprintf (stderr, "cp210x: control failed cmd rqt %u " + "rq %u len %u ret %d\n", requestype, request, size, ret); + } + return ret; +} + + + +static int +cp210x_get_config (CP210X * c, uint8_t request, unsigned int *data, int size) +{ + uint32_t *buf; + int result, i, length; + + /* Number of integers required to contain the array */ + length = (((size - 1) | 3) + 1) / 4; + + buf = calloc (length, sizeof (uint32_t)); + if (!buf) + { + fprintf (stderr, "%s - out of memory.\n", __FUNCTION__); + return -ENOMEM; + } + + /* Issue the request, attempting to read 'size' bytes */ + result = libusb_control_transfer (c->handle, + REQTYPE_INTERFACE_TO_HOST, request, + 0x0000, c->interface, (uint8_t *) buf, + size, TIMEOUT); + + /* Convert data into an array of integers */ + for (i = 0; i < length; i++) + data[i] = le32_to_cpu (buf[i]); + + free (buf); + + if (result != size) + { + fprintf (stderr, + "%s - Unable to send config request, request=0x%x size=%d result=%d\n", + __FUNCTION__, request, size, result); + if (result > 0) + result = -EPROTO; + + return result; + } + + return 0; +} + + +int +cp210x_set_config (CP210X * c, uint8_t request, unsigned int *data, int size) +{ + uint32_t *buf; + int result, i, length; + + /* Number of integers required to contain the array */ + length = (((size - 1) | 3) + 1) / 4; + + buf = malloc (length * sizeof (uint32_t)); + if (!buf) + { + fprintf (stderr, "%s - out of memory.\n", __FUNCTION__); + return -ENOMEM; + } + + /* Array of integers into bytes */ + for (i = 0; i < length; i++) + buf[i] = cpu_to_le32 (data[i]); + + if (size > 2) + { + result = libusb_control_transfer (c->handle, + REQTYPE_HOST_TO_INTERFACE, request, + 0x0000, c->interface, (uint8_t *) buf, + size, TIMEOUT); + } + else + { + result = libusb_control_transfer (c->handle, + REQTYPE_HOST_TO_INTERFACE, request, + data[0], c->interface, NULL, 0, + TIMEOUT); + } + + free (buf); + + if ((size > 2 && result != size) || result < 0) + { + fprintf (stderr, + "%s - Unable to send request, request=0x%x size=%d result=%d\n", + __FUNCTION__, request, size, result); + if (result > 0) + result = -EPROTO; + + return result; + } + + return 0; +} + + +static int +cp210x_set_config_single (CP210X * c, uint8_t request, unsigned int data) +{ + return cp210x_set_config (c, request, &data, 2); +} + +static int +cp210x_set_u16 (CP210X * c, int cmd, unsigned int value) +{ + return cp210x_ctlmsg (c, 0xff, 0x40, 0x3700 | (cmd & 0xff), value, 0, 0); +} + +static int +cp210x_set_string (CP210X * c, int cmd, uint8_t * usbstr, size_t len, + size_t maxlen) +{ + + int ret; + + if (len > maxlen) + return -EMSGSIZE; + + + ret = cp210x_ctlmsg (c, 0xff, 0x40, 0x3700 | (cmd & 0xff), 0, usbstr, len); + + fprintf (stderr, "%s - cmd 0x%02x len %d ret %d %x %x %x %x %x %x\n", + __FUNCTION__, cmd, (int) len, ret, usbstr[0], usbstr[1], usbstr[2], + usbstr[3], usbstr[4], usbstr[5]); + + return ret; +} + + +int +cp210x_set_gpio (CP210X * c, uint8_t gpio) +{ + return cp210x_ctlmsg (c, 0xff, REQTYPE_HOST_TO_DEVICE, 0x37e1, + ((uint16_t) gpio << 8) | CP_GPIO_MASK, NULL, 0); +} + + +int +cp210x_set_portconf (CP210X * c, struct cp210x_port_config *config) +{ + int ret; + struct cp210x_port_config be_config; + + memset (&be_config, 0, sizeof (be_config)); + + be_config.reset.mode = cpu_to_be16 (config->reset.mode); + be_config.reset.low_power = 0; // cpu_to_be16(config->reset.low_power); + be_config.reset.latch = cpu_to_be16 (config->reset.latch); + + be_config.suspend.mode = cpu_to_be16 (config->suspend.mode); + be_config.suspend.low_power = 0; // cpu_to_be16(config->suspend.low_power); + be_config.suspend.latch = cpu_to_be16 (config->suspend.latch); + + be_config.enhanced_fxn = config->enhanced_fxn; + + ret = + cp210x_ctlmsg (c, 0xff, REQTYPE_HOST_TO_DEVICE, 0x370c, 0, &be_config, + sizeof (be_config)); + if (ret == sizeof (be_config)) + return 0; + else if (ret >= 0) + return -EPROTO; + else + return ret; +} + + +int +cp210x_get_portconf (CP210X * c, struct cp210x_port_config *config) +{ + int ret; + + ret = + cp210x_ctlmsg (c, 0xff, REQTYPE_DEVICE_TO_HOST, 0x370c, 0, config, + sizeof (*config)); + + if (ret != sizeof (*config)) + return (ret >= 0) ? -EPROTO : ret; + + /* Words from cp2103 are MSB */ + + config->reset.mode = be16_to_cpu (config->reset.mode); + config->reset.low_power = be16_to_cpu (config->reset.low_power); + config->reset.latch = be16_to_cpu (config->reset.latch); + + config->suspend.mode = be16_to_cpu (config->suspend.mode); + config->suspend.low_power = be16_to_cpu (config->suspend.low_power); + config->suspend.latch = be16_to_cpu (config->suspend.latch); + + /* apparently not implemented yet */ + config->reset.low_power = 0; + config->suspend.low_power = 0; + + return 0; +} + + + +int +cp210x_set_dtr (CP210X * c, int on) +{ + unsigned int control; + control = on ? CONTROL_DTR : 0; + control |= CONTROL_WRITE_DTR; + + return cp210x_set_config (c, CP210X_SET_MHS, &control, 2); +} + +int +cp210x_set_vid (CP210X * c, uint16_t vid) +{ + return cp210x_set_u16 (c, 1, vid); +} + +int +cp210x_set_pid (CP210X * c, uint16_t pid) +{ + return cp210x_set_u16 (c, 2, pid); +} + + +int +cp210x_set_dev_ver (CP210X * c, uint16_t ver) +{ + return cp210x_set_u16 (c, 7, ver); +} + + +ssize_t +cp210x_read (CP210X * c, void *buf, size_t len, unsigned int timeout) +{ + int red = 0; + int err; + + timeout /= 1000; + + err = libusb_bulk_transfer (c->handle, 0x81, buf, len, &red, timeout); + + switch (err) + { + case 0: + break; + case LIBUSB_ERROR_TIMEOUT: + return 0; + default: + return -1; + } + + return red; +} + + + +int +cp210x_set_mfg (CP210X * c, uint8_t *s,int len) +{ + return cp210x_set_string (c, 0x0, s, len, + CP210X_MAX_MFG_STRLEN); +} + + +int +cp210x_set_product (CP210X * c, uint8_t *s,int len) +{ + + return cp210x_set_string (c, 0x3, s, len, + CP210X_MAX_PRODUCT_STRLEN); +} + + +int +cp210x_set_serial (CP210X * c, uint8_t *s,int len) +{ + + return cp210x_set_string (c, 0x4, s, len, + CP210X_MAX_SERIAL_STRLEN); +} + + + + +int +cp210x_setup (CP210X * c) +{ + + unsigned int bits; + unsigned int modem_ctl[4]; + uint32_t baud; + + + if (cp210x_set_config_single (c, CP210X_IFC_ENABLE, UART_ENABLE)) + { + + fprintf (stderr, "failed to start uart\n"); + return -1; + } + + + baud = 115200; + + if (cp210x_set_config (c, CP210X_SET_BAUDRATE, &baud, sizeof (baud))) + { + fprintf (stderr, "failed to set baud rate to %u\n", baud); + return -1; + } + + + + cp210x_get_config (c, CP210X_GET_LINE_CTL, &bits, 2); + + bits &= ~BITS_DATA_MASK; + bits |= BITS_DATA_8; + if (cp210x_set_config (c, CP210X_SET_LINE_CTL, &bits, 2)) + { + fprintf (stderr, + "Number of data bits requested not supported by device\n"); + return -1; + } + + + cp210x_get_config (c, CP210X_GET_LINE_CTL, &bits, 2); + bits &= ~BITS_PARITY_MASK; + bits |= BITS_PARITY_SPACE; + if (cp210x_set_config (c, CP210X_SET_LINE_CTL, &bits, 2)) + { + fprintf (stderr, "Parity mode not supported by device\n"); + return -1; + } + + cp210x_get_config (c, CP210X_GET_LINE_CTL, &bits, 2); + bits &= ~BITS_STOP_MASK; + bits |= BITS_STOP_1; + if (cp210x_set_config (c, CP210X_SET_LINE_CTL, &bits, 2)) + { + fprintf (stderr, + "Number of stop bits requested not supported by device\n"); + return -1; + } + + + cp210x_get_config (c, CP210X_GET_FLOW, modem_ctl, 16); + modem_ctl[0] &= ~0x7B; + modem_ctl[0] |= 0x01; + modem_ctl[1] |= 0x40; + + if (cp210x_set_config (c, CP210X_SET_FLOW, modem_ctl, 16)) + { + fprintf (stderr, "Couldn't disable modem control\n"); + return -1; + } + + + return 0; +} + + + +static libusb_device * +find_device (void) +{ + libusb_device **list; + libusb_device *found = NULL; + ssize_t cnt; + ssize_t i = 0; + + libusb_init (NULL); + + cnt = libusb_get_device_list (NULL, &list); + + if (cnt < 0) + return NULL; + + + for (i = 0; i < cnt; i++) + { + struct libusb_device_descriptor desc = { 0 }; + libusb_device *device = list[i]; + + libusb_get_device_descriptor (device, &desc); + + + if (((desc.idVendor == 0x10c4) && (desc.idProduct == 0xea60)) + ||((desc.idVendor == 0x413c) && (desc.idProduct == 0x9500))) + { + libusb_ref_device (device); + libusb_free_device_list (list, 1); + + return device; + break; + } + } + libusb_free_device_list (list, 1); + return NULL; +} + + + +int +cp210x_reset (CP210X * c) +{ + libusb_reset_device (c->handle); + + if (libusb_set_configuration (c->handle, 1) < 0 || + libusb_claim_interface (c->handle, 0) < 0) + return -1; + + + if (cp210x_setup (c)) + return -1; + + + return 0; +} + +CP210X * +cp210x_open (void) +{ + CP210X *c = malloc (sizeof (CP210X)); + + c->device = find_device (); + c->handle = NULL; + + if (!c->device) + { + free (c); + return NULL; + } + libusb_open (c->device, &c->handle); + + if (!c->handle) + { + free (c); + return NULL; + } + + libusb_detach_kernel_driver (c->handle, 0); + libusb_detach_kernel_driver (c->handle, 1); + + libusb_reset_device (c->handle); + + c->interface = 0; + if (libusb_set_configuration (c->handle, 1) < 0 || + libusb_claim_interface (c->handle, 0) < 0) + { + + libusb_close (c->handle); + libusb_unref_device (c->device); + free (c); + return NULL; + + + } + + + if (cp210x_setup (c)) + { + libusb_close (c->handle); + libusb_unref_device (c->device); + free (c); + return NULL; + } + + return c; +} + +void +cp210x_close (CP210X * c) +{ + libusb_close (c->handle); + libusb_unref_device (c->device); + free (c); +} diff --git a/userland/cp210x.h b/userland/cp210x.h new file mode 100644 index 0000000..4b9beff --- /dev/null +++ b/userland/cp210x.h @@ -0,0 +1,97 @@ +#ifndef _CP210X_H_ +#define _CP210X_H_ + +#include +typedef struct { + libusb_device *device; + libusb_device_handle *handle; + int interface; +} CP210X; + +struct cp210x_port_state { + uint16_t mode; /* push-pull = 1, open-drain = 0 */ + uint16_t low_power; /* 1 = ground the pin, and disable */ + uint16_t latch; +} __attribute__((packed)); + +/* LOPWR MODE LATCH */ +/* 0 0 0 Pin drivers are totem pole, and inital config sinks current to GND */ +/* 0 0 1 Pin drivers are totem pole, and inital config sources current from VIO */ +/* 0 1 0 Pin drivers are open drain, and inital config sinks current to GND */ +/* 0 1 1 Pin drivers are open drain, and inital config leaves pin HI-Z (you want this for inputs) */ +/* 1 X X Pin drivers are disabled, and pin sinks current to GND */ + +struct cp210x_port_config { + struct cp210x_port_state reset; + struct cp210x_port_state suspend; + uint8_t enhanced_fxn; +} __attribute__((packed)); + + +#define CP_EFXN_GPIO_0_IS_TXLED (1 << 0) +#define CP_EFXN_GPIO_1_IS_RXLED (1 << 1) +#define CP_EFXN_GPIO_2_IS_RS485_TX (1 << 2) +#define CP_EFXN_UNUSED_1 (1 << 3) /* Set to zero */ +#define CP_EFXN_ENABLE_WPU (1 << 4) +#define CP_EFXN_UNUSED_2 (1 << 5) /* Set to zero */ +#define CP_EFXN_SERIAL_AUTOOFF (1 << 6) +#define CP_EFXN_GPIOL_AUTOOFF (1 << 7) + + +#define CP_PIN_RI (1 << 0) +#define CP_PIN_DCD (1 << 1) +#define CP_PIN_DTR (1 << 2) +#define CP_PIN_DSR (1 << 3) +#define CP_PIN_TXD (1 << 4) +#define CP_PIN_RXD (1 << 5) +#define CP_PIN_RTS (1 << 6) +#define CP_PIN_CTS (1 << 7) +#define CP_PIN_GPIO_0 (1 << 8) +#define CP_PIN_GPIO_1 (1 << 9) +#define CP_PIN_GPIO_2 (1 << 10) +#define CP_PIN_GPIO_3 (1 << 11) +#define CP_PIN_UNUSED_1 (1 << 12) +#define CP_PIN_UNUSED_2 (1 << 13) +#define CP_PIN_GPIO_SUSPEND (1 << 14) +#define CP_PIN_GPIO_NSUSPEND (1 << 15) + +#define CP_INPUT_PINS (CP_PIN_RXD|CP_PIN_CTS|CP_PIN_DSR|CP_PIN_RI|CP_PIN_DCD) + + + + + + +/* CP2103 GPIO */ +#define CP_GPIO_0 0x01 +#define CP_GPIO_1 0x02 +#define CP_GPIO_2 0x04 +#define CP_GPIO_3 0x08 +#define CP_GPIO_MASK (CP_GPIO_0|CP_GPIO_1|CP_GPIO_2|CP_GPIO_3) + + +#define CP210X_MAX_PRODUCT_STRLEN 0x7d +#define CP210X_MAX_SERIAL_STRLEN 0x3f +#define CP210X_MAX_MFG_STRLEN 0x18 +#define CP210X_MAX_MAXPOWER 250 + + + + +extern int cp210x_set_config(CP210X *c, uint8_t request, unsigned int *data, int size); +extern int cp210x_set_gpio(CP210X *c, uint8_t gpio); +extern int cp210x_set_portconf(CP210X *c, struct cp210x_port_config *config); +extern int cp210x_get_portconf(CP210X *c, struct cp210x_port_config *config); +extern int cp210x_set_dtr(CP210X *c, int on); +extern int cp210x_set_vid(CP210X *c, uint16_t vid); +extern int cp210x_set_pid(CP210X *c, uint16_t pid); +extern int cp210x_set_dev_ver(CP210X *c, uint16_t ver); +extern ssize_t cp210x_read(CP210X *c, void *buf, size_t len, unsigned int timeout); +extern int cp210x_set_mfg(CP210X *c, uint8_t *s, int len); +extern int cp210x_set_product(CP210X *c, uint8_t *s, int len); +extern int cp210x_set_serial(CP210X *c, uint8_t *s, int len); +extern int cp210x_setup(CP210X *c); +extern int cp210x_reset(CP210X *c); +extern CP210X *cp210x_open(void); +extern void cp210x_close(CP210X *c); +#endif diff --git a/userland/cp210x_int.h b/userland/cp210x_int.h new file mode 100644 index 0000000..5a5ee3a --- /dev/null +++ b/userland/cp210x_int.h @@ -0,0 +1,82 @@ +#ifndef _CPIO210X_H +#define _CPIO210X_H + +/* Config request types */ +#define REQTYPE_HOST_TO_INTERFACE 0x41 +#define REQTYPE_INTERFACE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_DEVICE 0x40 +#define REQTYPE_DEVICE_TO_HOST 0xc0 + +/* Config request codes */ +#define CP210X_IFC_ENABLE 0x00 +#define CP210X_SET_BAUDDIV 0x01 +#define CP210X_GET_BAUDDIV 0x02 +#define CP210X_SET_LINE_CTL 0x03 +#define CP210X_GET_LINE_CTL 0x04 +#define CP210X_SET_BREAK 0x05 +#define CP210X_IMM_CHAR 0x06 +#define CP210X_SET_MHS 0x07 +#define CP210X_GET_MDMSTS 0x08 +#define CP210X_SET_XON 0x09 +#define CP210X_SET_XOFF 0x0A +#define CP210X_SET_EVENTMASK 0x0B +#define CP210X_GET_EVENTMASK 0x0C +#define CP210X_SET_CHAR 0x0D +#define CP210X_GET_CHARS 0x0E +#define CP210X_GET_PROPS 0x0F +#define CP210X_GET_COMM_STATUS 0x10 +#define CP210X_RESET 0x11 +#define CP210X_PURGE 0x12 +#define CP210X_SET_FLOW 0x13 +#define CP210X_GET_FLOW 0x14 +#define CP210X_EMBED_EVENTS 0x15 +#define CP210X_GET_EVENTSTATE 0x16 +#define CP210X_SET_CHARS 0x19 +#define CP210X_GET_BAUDRATE 0x1D +#define CP210X_SET_BAUDRATE 0x1E + +/* CP210X_IFC_ENABLE */ +#define UART_ENABLE 0x0001 +#define UART_DISABLE 0x0000 + +/* CP210X_(SET|GET)_BAUDDIV */ +#define BAUD_RATE_GEN_FREQ 0x384000 + +/* CP210X_(SET|GET)_LINE_CTL */ +#define BITS_DATA_MASK 0X0f00 +#define BITS_DATA_5 0X0500 +#define BITS_DATA_6 0X0600 +#define BITS_DATA_7 0X0700 +#define BITS_DATA_8 0X0800 +#define BITS_DATA_9 0X0900 + +#define BITS_PARITY_MASK 0x00f0 +#define BITS_PARITY_NONE 0x0000 +#define BITS_PARITY_ODD 0x0010 +#define BITS_PARITY_EVEN 0x0020 +#define BITS_PARITY_MARK 0x0030 +#define BITS_PARITY_SPACE 0x0040 + +#define BITS_STOP_MASK 0x000f +#define BITS_STOP_1 0x0000 +#define BITS_STOP_1_5 0x0001 +#define BITS_STOP_2 0x0002 + +/* CP210X_SET_BREAK */ +#define BREAK_ON 0x0001 +#define BREAK_OFF 0x0000 + +/* CP210X_(SET_MHS|GET_MDMSTS) */ +#define CONTROL_DTR 0x0001 +#define CONTROL_RTS 0x0002 +#define CONTROL_CTS 0x0010 +#define CONTROL_DSR 0x0020 +#define CONTROL_RING 0x0040 +#define CONTROL_DCD 0x0080 +#define CONTROL_WRITE_DTR 0x0100 +#define CONTROL_WRITE_RTS 0x0200 + + +#endif /* _CPIO210X_H */ + + diff --git a/userland/libradiator.c b/userland/libradiator.c new file mode 100644 index 0000000..15d2e21 --- /dev/null +++ b/userland/libradiator.c @@ -0,0 +1,364 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "radiator.h" + + + + +/* + * bit 0: 1 left leg NPN base + * bit 1: 2 left leg PNP base + * bit 2: 4 right leg PNP base + * bit 3: 8 right leg NPN base + */ + +#define LEFT_NPN_OFF 0 +#define LEFT_NPN_ON 1 +#define LEFT_PNP_OFF 2 +#define LEFT_PNP_ON 0 + +#define LEFT_LOW (LEFT_NPN_ON | LEFT_PNP_OFF) +#define LEFT_HI (LEFT_NPN_OFF | LEFT_PNP_ON) +#define LEFT_OFF (LEFT_NPN_OFF | LEFT_PNP_OFF) + +#define RIGHT_NPN_OFF 0 +#define RIGHT_NPN_ON 8 +#define RIGHT_PNP_OFF 4 +#define RIGHT_PNP_ON 0 + + +#define RIGHT_LOW (RIGHT_NPN_ON | RIGHT_PNP_OFF) +#define RIGHT_HI (RIGHT_NPN_OFF | RIGHT_PNP_ON) +#define RIGHT_OFF (RIGHT_NPN_OFF | RIGHT_PNP_OFF) + +#define BRAKE (RIGHT_LOW | LEFT_LOW) +#define FORWARDS (RIGHT_LOW | LEFT_HI) +#define BACKWARDS (RIGHT_HI | LEFT_LOW) +#define OFF (RIGHT_OFF| LEFT_OFF) + +#define TIMEOUT 750000 /*75ms */ +#define RUN_IN 50 +#define RELEASE_TENSION 10 + + +static int brake_motor(Radiator *r) +{ + int i=BRAKE; + printf (" Motor braking\n"); + return cp210x_set_gpio(r->cp210x,i); +} + +static int +drive_motor (Radiator*r, int dir) +{ + int i; + + if (dir > 0) + { + printf (" Motor forwards\n"); + i = FORWARDS; + } + else if (dir < 0) + { + printf (" Motor backwards\n"); + i = BACKWARDS; + } + else + { + printf (" Motor off\n"); + i = OFF; + } + + return cp210x_set_gpio(r->cp210x,i); +} + + +static int +sensor_led_power (Radiator *r, int on) +{ + +unsigned int control; + +printf (" Rotation sensor power %s\n", on ? "on" : "off"); + +return cp210x_set_dtr(r->cp210x,on); + +} + + +static int count_steps (Radiator *r, int count) +{ + int counted = 0; + struct timeval tv; + char buf[128]; + int i; + fd_set rfds; + + printf (" Counting %d steps", count); + fflush(stdout); + + + while (count) + { + i=cp210x_read(r->cp210x,buf,sizeof(buf),TIMEOUT); + + if (i==0) break; + + if (i<0) continue; + + counted+=i; + if (count>0) { + count-=i; + if (count<0) count=0; + } + + printf ("."); + fflush (stdout); + } + + printf ("%d steps\n", counted); + return counted; +} + + + + +static int +drive_motor_count (Radiator * r, int dir, int steps) +{ + int s1, s2, ret; + + sensor_led_power (r, 1); + drive_motor (r, dir); + s1 = count_steps (r, steps); + if (s1 != steps) { + printf (" Hit end stop\n"); + drive_motor (r, 0); + } else { + brake_motor(r); + } + s2 = count_steps (r, -1); + sensor_led_power (r, 0); + drive_motor (r, 0); + + /*did we hit an end stop? */ + if (s1 != steps) + ret = s1 - s2; + else + ret = s1 + s2; + + printf (" %d steps under power (of %d), %d steps coasting -> %d steps\n", + s1, steps, s2, ret); + + r->pos += ret * dir; + + /*Recalibrate our notion of ends */ + + if (s1 != steps) + { + if (dir == -1) + { + r->pos = 0; + } + else + { + r->max = r->pos; + } + } + + return ret; +} + + + + +int +radiator_set_pos (Radiator * r, int wanted) +{ + int guard, delta; + + delta = wanted - r->pos; + printf ("Now at %d want %d, delta %d\n", r->pos, wanted, delta); + + if (wanted == 0) + { + drive_motor_count (r, -1, -1); + return 0; + } + else if (r->max && (wanted >= r->max)) + { + drive_motor_count (r, 1, -1); + return 0; + } + + + guard = r->overshoot * 3; + + if ((delta > -guard) && (delta < guard)) + { + printf ("Too close\n"); + + drive_motor_count (r, (r->pos > r->half) ? -1 : 1, RUN_IN); + + delta = wanted - r->pos; + printf ("Now at %d want %d, delta %d\n", r->pos, wanted, delta); + } + + + if (delta < 0) + { + drive_motor_count (r, -1, (-delta) - r->overshoot); + } + else if (delta > 0) + { + drive_motor_count (r, 1, delta - r->overshoot); + } + + printf ("Wanted %d, got %d\n", wanted, r->pos); + + return 0; +} + +void +radiator_calibrate (Radiator * r) +{ + radiator_set_pos (r, 0); + + drive_motor_count (r, 1, RUN_IN); + + r->overshoot = r->pos - RUN_IN; +} + + + +static int utf16(uint8_t *dst,uint8_t *src) +{ +int len=0; + + +while (*src) { + *(dst++)=*(src++); + len+=2; + *(dst++)=0; +} +len+=2; + +return len; +} + + +static int make_usb_descriptor(uint8_t *dst,char *src) +{ +int len; +len=utf16(dst+2,(uint8_t *) src); +//memcpy(dst+2,src,len); +dst[0]=len+2; +dst[1]=0x3; +return len+2; +} + + +int +radiator_program (Radiator * r) +{ + uint8_t buf[256]; + struct cp210x_port_config config; + memset (&config, 0, sizeof (config)); + uint16_t vid,pid; + int len; + + + cp210x_get_portconf(r->cp210x,&config); + + printf + ("config was reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n", + config.reset.mode, config.reset.low_power, config.reset.latch, + config.suspend.mode, config.suspend.low_power, config.suspend.latch, + config.enhanced_fxn); + + + memset (&config, 0, sizeof (config)); + + config.reset.mode = ~CP_INPUT_PINS; + config.reset.low_power = 0; + config.reset.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2; + config.suspend.mode = ~CP_INPUT_PINS; + config.suspend.low_power = 0; + config.suspend.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2; + config.enhanced_fxn = CP_EFXN_ENABLE_WPU; + + + cp210x_set_portconf(r->cp210x,&config); + + memset (&config, 0, sizeof (config)); + cp210x_get_portconf(r->cp210x,&config); + + + printf + ("config is reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n", + config.reset.mode, config.reset.low_power, config.reset.latch, + config.suspend.mode, config.suspend.low_power, config.suspend.latch, + config.enhanced_fxn); + + memset(buf,0,sizeof(buf)); + +vid=0x413c; + + cp210x_set_vid(r->cp210x,vid); + +pid=0x9500; + cp210x_set_pid(r->cp210x,pid); + + len=make_usb_descriptor(buf,"USB Radiator Valve"); + cp210x_set_product(r->cp210x, buf,len); + + len=make_usb_descriptor(buf,"000001"); + cp210x_set_serial (r->cp210x,buf,len); + + len=make_usb_descriptor(buf,"Global Panaceas"); + cp210x_set_mfg (r->cp210x,buf,len); + + cp210x_reset(r->cp210x); + + return 0; +} + +Radiator * +radiator_open (char *path, int quiet) +{ + Radiator *r = malloc (sizeof (Radiator)); + + + r->cp210x=cp210x_open(); + + if (!r->cp210x) { + free(r); + return NULL; + } + + + if (!quiet) + radiator_calibrate (r); + + return r; +} + + +void +radiator_close (Radiator * r) +{ + cp210x_close(r->cp210x); + free (r); +} + + + diff --git a/userland/program_radiator.c b/userland/program_radiator.c new file mode 100644 index 0000000..75077da --- /dev/null +++ b/userland/program_radiator.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include "radiator.h" + +int +main (int argc, char *argv[]) +{ + Radiator *r; + int pos; + char buf[1024]; + + + r = radiator_open (argv[1],1); + + if (!r) + return -1; + + radiator_program(r); + + return 0; +} diff --git a/userland/radiator.c b/userland/radiator.c new file mode 100644 index 0000000..2d594da --- /dev/null +++ b/userland/radiator.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include "radiator.h" + +int +main (int argc, char *argv[]) +{ + Radiator *r; + int pos; + char buf[1024]; + + + r = radiator_open (argv[1],0); + + if (!r) + return -1; + + + for (;;) + { + printf ("Current position %d (end stop at %d, overshoots by %d)\n", + r->pos, r->max, r->overshoot); + printf ("Enter new>"); + fflush (stdout); + buf[sizeof (buf) - 1] = 0; + fgets (buf, sizeof (buf) - 1, stdin); + radiator_set_pos (r, atoi (buf)); + } + + + return 0; +} diff --git a/userland/radiator.h b/userland/radiator.h new file mode 100644 index 0000000..da912c0 --- /dev/null +++ b/userland/radiator.h @@ -0,0 +1,21 @@ +#ifndef _RADIATOR_H_ +#define _RADIATOR_H_ + +#include "cp210x.h" + +typedef struct +{ + CP210X *cp210x; + int pos; + int half; + int overshoot; + int max; +} Radiator; + +int radiator_set_pos (Radiator * r, int wanted); +void radiator_calibrate (Radiator * r); +int radiator_program (Radiator * r); +Radiator *radiator_open (char *s, int quiet); +void radiator_close (Radiator * r); + +#endif /* _RADIATOR_H_ */ -- cgit v1.2.3