/* Instru2Light - Illumine un instrument de musique en temps réel Copyright (C) 2012-2013 Ludovic Pouzenc This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #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); ftdi_deinit(&ftdi); return 1; } 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; } inline int projector_correction(int in) { //int out=powf(((in-108.f)/162.f),3.f)*256.f+80.f; int out=in*0.25f+0.75*(powf(((in-100.f)/162.f),3.f)*256.f+48.f); if (out>255) out=255; if (out<0) out=0; return out; } int dmx_write_rgb(int r, int g, int b) { if (! ftdi.usb_dev ) return -1; universe[2]=projector_correction(r); universe[3]=projector_correction(g); universe[4]=projector_correction(b); // printf("rgb %3i %3i %3i dmx %3i %3i %3i\n", r,g,b, universe[2], universe[3], universe[4]); 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); } }