summaryrefslogtreecommitdiff
path: root/src/illuminate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/illuminate.c')
-rw-r--r--src/illuminate.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/illuminate.c b/src/illuminate.c
new file mode 100644
index 0000000..a0f146d
--- /dev/null
+++ b/src/illuminate.c
@@ -0,0 +1,164 @@
+#include <ftdi.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "illuminate.h"
+
+// FTDI Vendor ID
+#define VID 0x0403
+// FTDI Product ID
+#define PID 0x6001
+
+#define DMX_CHANNELS 6
+//#define DMX_CHANNELS 512
+//#define DMX_FRAMETIME 24000000
+#define DMX_FRAMETIME 0
+#define DMX_BREAK 110000
+#define DMX_MAB 16000
+
+#define MAX_STR 64
+
+/*
+struct ftdi_device_list
+{
+ // pointer to next entry
+ struct ftdi_device_list *next;
+ // pointer to libusb's usb_device
+ struct usb_device *dev;
+}
+*/
+
+inline void ts_diffadd(struct timespec *res, struct timespec *a, struct timespec *b, struct timespec *c);
+void e(int res, const char *funcname, struct ftdi_context *ftdi, int exit_val);
+int dmx_universe_write(struct ftdi_context *ftdi, unsigned char *universe, int uni_len);
+
+struct ftdi_context ftdi;
+struct ftdi_device_list *devlist=NULL;
+char *manufacturer, *description, *serial;
+unsigned char universe[DMX_CHANNELS+1];
+
+int dmx_init() {
+
+ struct usb_device *dev=NULL;
+
+ struct timespec ts_to_sleep;
+
+ (void) memset(universe, 0, sizeof(universe));
+ (void) memset(&ftdi, 0, sizeof(ftdi));
+
+ manufacturer=malloc(MAX_STR);
+ description=malloc(MAX_STR);
+ serial=malloc(MAX_STR);
+
+ e(ftdi_init(&ftdi),"ftdi_init",&ftdi,10);
+ e(ftdi_usb_find_all(&ftdi, &devlist, VID, PID),"ftdi_usb_find_all",&ftdi,11);
+
+ //Always take the first device
+ if (devlist==NULL || devlist->dev==NULL) {
+ fprintf(stderr, "No usb device detected (looking for USB ID 0x%04X:0x%04X)\n", VID, PID);
+ return(2);
+ }
+ dev=devlist->dev;
+
+// fprintf(stderr, "DEBUG : next==%p\n", devlist->next);
+
+ e(ftdi_usb_get_strings(&ftdi, dev, manufacturer, MAX_STR, description, MAX_STR, serial, MAX_STR),"ftdi_usb_get_strings",&ftdi,12);
+ fprintf(stderr, "Connecting to USB device ('%s','%s','%s')\n", manufacturer, description, serial);
+ e(ftdi_usb_open_dev(&ftdi,dev),"ftdi_usb_open_dev",&ftdi,13);
+ fprintf(stderr, "Connected\n");
+
+ //Init the device
+ e(ftdi_usb_reset(&ftdi),"ftdi_usb_reset",&ftdi,15);
+ e(ftdi_set_baudrate(&ftdi, 250000),"ftdi_set_baudrate",&ftdi,16);
+ e(ftdi_set_line_property(&ftdi, BITS_8, STOP_BIT_2, NONE),"ftdi_set_line_property",&ftdi,17);
+ e(ftdi_setflowctrl(&ftdi, SIO_DISABLE_FLOW_CTRL),"ftdi_setflowctrl",&ftdi,18);
+ e(ftdi_usb_purge_buffers(&ftdi),"ftdi_usb_purge_buffers",&ftdi,19);
+ e(ftdi_setrts(&ftdi, 0),"ftdi_setrts",&ftdi,20);
+
+ // 1ms pause for initialization completion
+ ts_to_sleep.tv_sec=0;
+ ts_to_sleep.tv_nsec=1000000;
+ nanosleep(&ts_to_sleep,NULL);
+
+ return 0;
+}
+
+int dmx_write_rgb(int r, int g, int b) {
+ if (! ftdi.usb_dev ) return -1;
+
+ universe[2]=r;
+ universe[3]=g;
+ universe[4]=b;
+
+ return dmx_universe_write(&ftdi, universe, DMX_CHANNELS);
+}
+
+void dmx_deinit() {
+ e(ftdi_usb_close(&ftdi),"ftdi_usb_close",&ftdi,50);
+ ftdi_list_free(&devlist);
+ ftdi_deinit(&ftdi);
+
+ free(manufacturer);
+ free(description);
+ free(serial);
+}
+
+int dmx_universe_write(struct ftdi_context *ftdi, unsigned char *universe, int uni_len) {
+ //static struct timespec ts_frame_time={0,DMX_FRAMETIME};
+ static struct timespec ts_dmx_break={0,DMX_BREAK};
+ static struct timespec ts_dmx_mab={0,DMX_MAB};
+ //static struct timespec ts_trame_begin={0,0};
+ //struct timespec ts_to_sleep, ts_now;
+
+ // http://www.opendmx.net/index.php/DMX512-A#Timings
+ // http://www.erwinrol.com/?s=dmx
+ // symbo_perdiod is 4us (250kHz)
+ // Full packet minimal timing : DMX_BREAK+DMX_MAB+(1+8+2)*513*symbol_period=22698us
+
+ ftdi_async_complete(ftdi,0);
+ // Wait the end of the previous timeslot
+/*
+ clock_gettime(CLOCK_MONOTONIC, &ts_now);
+ ts_diffadd(&ts_to_sleep,&ts_frame_time,&ts_now,&ts_trame_begin);
+
+ //fprintf(stderr, "DEBUG : ts_to_sleep==%li.%09li\n", ts_to_sleep.tv_sec, ts_to_sleep.tv_nsec);
+// ts_to_sleep.tv_sec=0;
+// ts_to_sleep.tv_nsec=23000000;
+ nanosleep(&ts_to_sleep,NULL);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts_trame_begin);
+*/
+ e(ftdi_set_line_property2(ftdi, BITS_8, STOP_BIT_2, NONE, BREAK_ON),"ftdi_set_line_property2",ftdi,30);
+ nanosleep(&ts_dmx_break,NULL);
+ e(ftdi_set_line_property2(ftdi, BITS_8, STOP_BIT_2, NONE, BREAK_OFF),"ftdi_set_line_property2",ftdi,31);
+ nanosleep(&ts_dmx_mab,NULL);
+
+
+ //return ftdi_write_data(ftdi, universe, uni_len);
+ return ftdi_write_data_async(ftdi, universe, uni_len);
+}
+
+inline void ts_diffadd(struct timespec *res, struct timespec *a, struct timespec *b, struct timespec *c) {
+ time_t rem;
+
+ res->tv_nsec=a->tv_nsec-b->tv_nsec+c->tv_nsec;
+ rem=res->tv_nsec/1000000000;
+ res->tv_nsec=res->tv_nsec%1000000000;
+ res->tv_sec=a->tv_sec-b->tv_sec+c->tv_sec+rem;
+
+ if (res->tv_nsec<0 && res->tv_sec>0) { res->tv_sec--; res->tv_nsec+=1000000000; }
+ if (res->tv_nsec>0 && res->tv_sec<0) { res->tv_nsec-=1000000000; res->tv_sec++; }
+}
+
+void e(int res, const char *funcname, struct ftdi_context *ftdi, int exit_val) {
+ char *reason;
+
+ if ( res < 0 ) {
+ reason=ftdi_get_error_string(ftdi);
+ fprintf(stderr, "Error in %s : %s\n", funcname, reason);
+ exit(exit_val);
+ }
+
+}
+