diff options
Diffstat (limited to 'abs/core-testing/lirc-utils')
-rw-r--r-- | abs/core-testing/lirc-utils/PKGBUILD | 7 | ||||
-rwxr-xr-x | abs/core-testing/lirc-utils/hw_commandir.c | 1926 | ||||
-rwxr-xr-x | abs/core-testing/lirc-utils/hw_commandir.h | 175 |
3 files changed, 2106 insertions, 2 deletions
diff --git a/abs/core-testing/lirc-utils/PKGBUILD b/abs/core-testing/lirc-utils/PKGBUILD index e35db01..c151e5e 100644 --- a/abs/core-testing/lirc-utils/PKGBUILD +++ b/abs/core-testing/lirc-utils/PKGBUILD @@ -3,7 +3,7 @@ pkgname=lirc-utils pkgver=0.8.5CVS -pkgrel=2 +pkgrel=3 pkgdesc="Linux Infrared Remote Control utils" arch=(i686 x86_64) url="http://www.lirc.org/" @@ -17,7 +17,9 @@ backup=('etc/lircd.conf' 'etc/lircmd.conf'\ options=('!libtool' '!makeflags') source=(http://www.blushingpenguin.com/mark/lmilk/lirc-0.8.5-CVS-pvr150.tar.bz2 \ lircd lircmd lirc.logrotate lircd.conf.d \ - kernel-2.6.26.patch lirc_atiusb.patch) + kernel-2.6.26.patch lirc_atiusb.patch + hw_commandir.c + hw_commandir.h) md5sums=('b96dae91b566143b3af433fa2714ec9a' '909ad968afa10e4511e1da277bb23c3b'\ '85f7fdac55e5256967241864049bf5e9' '3deb02604b37811d41816e9b4385fcc3'\ '5b1f8c9cd788a39a6283f93302ce5c6e' '1753acd774f50b638e6173d364de53fd'\ @@ -26,6 +28,7 @@ md5sums=('b96dae91b566143b3af433fa2714ec9a' '909ad968afa10e4511e1da277bb23c3b'\ build() { # configure cd $startdir/src/lirc-0.8.5-CVS-pvr150 || return 1 + cp $startdir/src/hw_commandir.* $startdir/src/lirc-0.8.5-CVS-pvr150/daemons # patch -Np1 -i ../kernel-2.6.26.patch || return 1 patch -Np1 -i ../lirc_atiusb.patch || return 1 diff --git a/abs/core-testing/lirc-utils/hw_commandir.c b/abs/core-testing/lirc-utils/hw_commandir.c new file mode 100755 index 0000000..40ac0de --- /dev/null +++ b/abs/core-testing/lirc-utils/hw_commandir.c @@ -0,0 +1,1926 @@ +/* CommandIR transceivers driver 0.96 + * Supporting CommandIR II and CommandIR Mini (and multiple of both) + * April-June 2008, Matthew Bodkin + * December 2008, bug fixes, Matthew Bodkin + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/utsname.h> + +#include "hardware.h" +#include "ir_remote.h" +#include "lircd.h" +#include "receive.h" +#include "transmit.h" +#include "hw_commandir.h" +#include <usb.h> + +#define RAPID_DECODE 1 + +extern struct ir_remote *repeat_remote; +extern char *progname; + + +/********************************************************************** + * + * internal function prototypes + * + **********************************************************************/ +static int commandir_init(); +static int commandir_deinit(void); +static char *commandir_rec(struct ir_remote *remotes); +static void commandir_read_loop(); +static int cmdir_convert_RX(unsigned char *orig_rxbuffer); +static unsigned int get_time_value(unsigned int firstint, + unsigned int secondint, unsigned char overflow); +static lirc_t commandir_readdata(lirc_t timeout); +static int commandir_send(struct ir_remote *remote,struct ir_ncode *code); +static int commandir_ioctl(unsigned int cmd, void *arg); +//static void setEmitterMask(unsigned char highbyte, unsigned char lowbyte); +static void setEmitterMask(int bitmask); +static void commandir_transmit(char *buffer, int bytes, int bitmask, + unsigned int); +static void commandir_child_init(); +static void shutdown_usb(); +static void hardware_scan(); +static void hardware_disconnect(int); +static void hardware_setorder(); +static void raise_event(unsigned int); +static int commandir_read(); +static int check_irsend_commandir(unsigned char *command); +static int commandir_decode(char *command); +static int commandir_receive_decode(struct ir_remote *remote, + ir_code *prep,ir_code *codep,ir_code *postp, + int *repeat_flagp, + lirc_t *min_remaining_gapp, lirc_t *max_remaining_gapp); +static void pipeline_check(); +static int inline get_bit(int bitnum); +static void add_to_tx_pipeline(unsigned char *buffer, int bytes, + int channel_mask, unsigned int); +static void recalc_tx_available(int); +static void set_hash_mask(int channel_mask); +static int commandir2_convert_RX(unsigned short *bufferrx, + unsigned char numvalues); +static void cleanup_commandir_dev(int spotnum); + +/********************************************************************** + * + * CommandIR Vars + * + **********************************************************************/ +static int current_transmitter_mask = 0xff; +static char unsigned commandir_data_buffer[512]; +static int last_mc_time = -1; +static int commandir_rx_num = 0; + + +static char channels_en[MAX_DEVICES]; +static char open_bus_hash[USB_MAX_BUSES][USB_MAX_BUSDEV]; +static int tx_order[MAX_DEVICES]; +static char device_count = 0; +static int mini_freq[MAX_DEVICES]; +static int child_pipe_write = 0; +static char haveInited = 0; +// Fake 'commandir' remote signal values +static unsigned int signal_base[2][2] = { {100|PULSE_BIT, 200}, + {1000|PULSE_BIT, 200} }; + +// Pipes to and from the child/parent +static pid_t child_pid = -1; +static int pipe_fd[2] = { -1, -1 }; +static int pipe_tochild[2] = { -1, -1 }; +static int tochild_read = -1, tochild_write = -1; + +struct commandir_device +{ + usb_dev_handle *cmdir_udev; + int bus; + int busdev; + int interface; + int location; + int hw_type; + int hw_revision; + int hw_subversion; + unsigned char devnum; + int endpoint_max[3]; +} open_commandir_devices[4]; + +struct hardware hw_commandir = +{ + NULL, /* default device */ + -1, /* fd */ + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_SET_TRANSMITTER_MASK| + LIRC_CAN_REC_MODE2, + LIRC_MODE_PULSE, /* send_mode */ + LIRC_MODE_MODE2, /* rec_mode */ + sizeof(lirc_t), /* code_length in BITS */ + commandir_init, /* init_func */ + NULL, /* config_func */ + commandir_deinit, /* deinit_func */ + commandir_send, /* send_func */ + commandir_rec, /* rec_func */ + commandir_receive_decode, /* decode_func */ + commandir_ioctl, /* ioctl_func */ + commandir_readdata, /* readdata */ + "commandir" +}; + +/*** LIRC Interface Functions - Non-blocking parent thread +*/ + +static int commandir_receive_decode(struct ir_remote *remote, + ir_code *prep,ir_code *codep,ir_code *postp, + int *repeat_flagp, + lirc_t *min_remaining_gapp, lirc_t *max_remaining_gapp) { + + int i; + i = receive_decode(remote, + prep,codep,postp, + repeat_flagp, + min_remaining_gapp, max_remaining_gapp); + + if(i > 0){ + static char rx_char[3] = {3, 0, RXDECODE_HEADER_LIRC}; + write(tochild_write, rx_char, 3); + } + + return i; +} + + +static int commandir_init() +{ + long fd_flags; + if(haveInited){ + static char init_char[3] = {3, 0, INIT_HEADER_LIRC}; + write(tochild_write, init_char, 3); + return 1; + } + + init_rec_buffer(); // LIRC's rec + init_send_buffer(); // LIRC's send + + /* A separate process will be forked to read data from the USB + * receiver and write it to a pipe. hw.fd is set to the readable + * end of this pipe. */ + if (pipe(pipe_fd) != 0) + { + logprintf(LOG_ERR, "couldn't open pipe 1"); + return 0; + } + + hw.fd = pipe_fd[0]; // the READ end of the Pipe + + if (pipe(pipe_tochild) != 0) + { + logprintf(LOG_ERR, "couldn't open pipe 1"); + return 0; + } + + tochild_read = pipe_tochild[0]; // the READ end of the Pipe + tochild_write = pipe_tochild[1]; // the WRITE end of the Pipe + + fd_flags = fcntl(pipe_tochild[0], F_GETFL); + if(fcntl(pipe_tochild[0], F_SETFL, fd_flags | O_NONBLOCK) == -1) + { + logprintf(LOG_ERR, "can't set pipe to non-blocking"); + return 0; + } + + child_pid= fork(); + if (child_pid== -1) + { + logprintf(LOG_ERR, "couldn't fork child process"); + return 0; + } + else if (child_pid== 0) + { + child_pipe_write = pipe_fd[1]; + commandir_child_init(); + commandir_read_loop(); + return 0; + } + haveInited = 1; + + logprintf(LOG_ERR, "CommandIR driver initialized"); + return 1; +} + + +static int commandir_deinit(void) +{ + /* Trying something a bit new with this driver. Keeping the driver + * connected so in the future we can still monitor in the client */ + if(USB_KEEP_WARM && (!strncmp(progname, "lircd", 5))) + { + static char deinit_char[3] = {3, 0, DEINIT_HEADER_LIRC}; + write(tochild_write, deinit_char, 3); + logprintf(LOG_ERR, "LIRC_deinit but keeping warm"); + } + else + { + if (tochild_read >= 0) + { + if (close(tochild_read) < 0) + { + logprintf(LOG_ERR, "Error closing pipe2");; + } + tochild_read = tochild_write = -1; + } + + if(haveInited){ + // shutdown all USB + if(child_pid > 0) + { + logprintf(LOG_ERR, "Closing child process"); + kill(child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + child_pid = -1; + haveInited = 0; + } + } + + if (hw.fd >= 0) + { + if (close(hw.fd) < 0) logprintf(LOG_ERR, "Error closing pipe"); + hw.fd = -1; + } + + logprintf(LOG_ERR, "commandir_deinit()"); + } + return(1); +} + +static int commandir_send(struct ir_remote *remote,struct ir_ncode *code) +{ + int length; + lirc_t *signals; + + if(!init_send(remote,code)) { + return 0; + } + + length = send_buffer.wptr; + signals = send_buffer.data; + + if (length <= 0 || signals == NULL) { + return 0; + } + + int cmdir_cnt =0; + char cmdir_char[70]; + + // Set the frequency of the signal along with the signal + transmitters + cmdir_char[0] = 7; + cmdir_char[1] = 0; + + cmdir_char[2] = FREQ_HEADER_LIRC; + cmdir_char[3] = (remote->freq >> 24) & (0xff); + cmdir_char[4] = (remote->freq >> 16) & (0xff); + cmdir_char[5] = (remote->freq >> 8) & (0xff); + cmdir_char[6] = (remote->freq & 0xff); + + write(tochild_write, cmdir_char, cmdir_char[0]); + + cmdir_cnt = 3; + + unsigned char * send_signals = malloc(sizeof(signals) * length + 4); + + send_signals[0] = (sizeof(lirc_t) * length + 4) & 0xff; + send_signals[1] = ((sizeof(lirc_t) * length + 4) >> 8) & 0xff; + + send_signals[2] = TX_LIRC_T; + send_signals[3] = (char)current_transmitter_mask; + + memcpy(&send_signals[4], signals, sizeof(lirc_t) * length); + + if(write(tochild_write, send_signals, + send_signals[0] + send_signals[1] * 256) < 0) + { + logprintf(LOG_ERR, "Error writing to child_write"); + } + + free(send_signals); + return(length); +} + +static char *commandir_rec(struct ir_remote *remotes) +{ + char * returnit; + if (!clear_rec_buffer()) return NULL; + returnit = decode_all(remotes); + return returnit; +} + +static int commandir_ioctl(unsigned int cmd, void *arg) +{ + unsigned int ivalue; + char cmdir_char[5]; + + switch(cmd) + { + case LIRC_SET_TRANSMITTER_MASK: + + ivalue=*(unsigned int*)arg; + + if(ivalue >= MAX_MASK) return (MAX_CHANNELS); + + /* Support the old way of setting the frequency of the signal along + * with the signal + transmitters */ + cmdir_char[0] = 5; + cmdir_char[1] = 0; + cmdir_char[2] = CHANNEL_EN_MASK; + cmdir_char[3] = (unsigned char)(ivalue & 0x00FF); // Low bits + cmdir_char[4] = (unsigned char)(ivalue >> 8); // High bits + + write(tochild_write, cmdir_char, cmdir_char[0]); + + return (0); + + default: + logprintf(LOG_ERR, "Unknown ioctl - %d", cmd); + return(-1); + } + + return 1; +} + +static lirc_t commandir_readdata(lirc_t timeout) +{ + lirc_t code = 0; + struct timeval tv = {0, timeout}; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(hw.fd, &fds); + + /* attempt a read with a timeout using select */ + if (select(hw.fd + 1, &fds, NULL, &fds, &tv) > 0) + /* if we failed to get data return 0 */ + if (read(hw.fd, &code, sizeof(lirc_t)) <= 0) + commandir_deinit(); + return code; +} + +/*** End of parent fork / LIRC accessible functions */ + + + + + + + + + + + + + + + +/*** CommandIR Client Process Functions (Handle all USB operations) + */ + +int channels_space_available[MAX_CHANNELS]; +int channels_space_updated = 0; // last updated time + +char * signalq[MAX_SIGNALQ]; // how many signals can be queued +int signalq_len[MAX_SIGNALQ]; +int signalq_bitmask[MAX_SIGNALQ]; +unsigned int signalq_frequency[MAX_SIGNALQ]; + +int top_signalq = -1; +int next_signalq_per_channel[MAX_CHANNELS]; + +unsigned char commandir_tx_start[MAX_CHANNELS*4]; +unsigned char commandir_tx_end[MAX_CHANNELS*4]; +unsigned char commandir_tx_available[MAX_CHANNELS]; +unsigned char lastSendSignalID[MAX_CHANNELS]; +unsigned char commandir_last_signal_id[MAX_CHANNELS]; + + +// Global variables to convert channel masks to consistant easier formats +unsigned char hash_mask[MAX_CHANNELS]; +unsigned char selected_channels[MAX_CHANNELS]; +unsigned char total_selected_channels = 0; +int shutdown_pending = 0; +int read_delay = WAIT_BETWEEN_READS_US; +int insert_fast_zeros = 0; + +int rx_hold = 0; + +// This is the only one for pre-pipelinging +int pre_pipeline_emitter_mask = 0x000f; // default tx on only first CommandIR + + +static void pipeline_check() +{ + /* Transmit from the pipeline if it's time and there's space + * what's available should now be updated in the main_loop + */ + + int i,j,k; + + i=0; + if(top_signalq < 0) return; + + while(i <= top_signalq) + { + + // Are ALL the channels this signal should TX on currently available? + int oktosend = 1; + set_hash_mask( signalq_bitmask[ i ] ); + for(j = 0; j<total_selected_channels; j++) + { + if(commandir_tx_available[ selected_channels[j] ] < + (36 + (signalq_len[ i ])/sizeof(lirc_t))) + { + oktosend = 0; + break; + } + } + + if(oktosend) + { + // great, TX this on all the channels. + + commandir_transmit(signalq[ i ], signalq_len[ i ], signalq_bitmask[ i ], signalq_frequency[ i ]); + + for(j = 0; j<total_selected_channels; j++) + { + /* commandir_tx_available[ selected_channels[j] ] -= + (64 + (signalq_len[ i ])/sizeof(lirc_t)); */ + commandir_tx_available[ selected_channels[j] ] = 0; + } + + /* Free up the memory, and see if there are new next_signalq's + * (any more for this channel to TX) + */ + free(signalq[i]); + + for(k=i; k<top_signalq; k++) + { + signalq[k] = signalq[k+1]; + signalq_len[k] = signalq_len[k+1]; + signalq_bitmask[k] = signalq_bitmask[k+1]; + signalq_frequency[k] = signalq_frequency[k+1]; + } + top_signalq--; + } + else + { + i++; + } + } +} + +static int get_bit(int bitnum) +{ + int r = 1; + return r << bitnum; // bit 0 is 1, bit 1 is 10, bit 2 is 100... +} + +static void add_to_tx_pipeline(unsigned char *buffer, int bytes, + int channel_mask, unsigned int frequency) +{ + /* *buffer points to a buffer that will be OVERWRITTEN; malloc our copy. + * buffer is a LIRC_T packet for CommandIR + */ + top_signalq++; + if(top_signalq > MAX_SIGNALQ) + { + logprintf(LOG_ERR, "Too many signals in queue: > %d", MAX_SIGNALQ); + return; + } + + signalq[top_signalq] = malloc(bytes); + + signalq_len[top_signalq] = bytes; + signalq_bitmask[top_signalq] = channel_mask; + signalq_frequency[top_signalq] = frequency; + + lirc_t *oldsignal, *newsignal; + int x, pulse_now = 1; + int projected_signal_length; + short aPCAFOM = 0; + float afPCAFOM = 0.0; + int difference = 0; + + afPCAFOM = (6000000.0 / ((frequency > 0) ? frequency : DEFAULT_FREQ) ) ; + aPCAFOM = afPCAFOM; + + // Trim off mid-modulation pulse fragments, add to space for exact signals + for(x=0; x<(bytes/sizeof(lirc_t)); x++) + { + oldsignal = (lirc_t *)&buffer[x*sizeof(lirc_t)]; + newsignal = (lirc_t *)signalq[top_signalq]; + newsignal += x; + + if(pulse_now==1){ + projected_signal_length = + (((int)( (*oldsignal * 12)/( afPCAFOM ) )) * aPCAFOM) / 12; + difference = *oldsignal - projected_signal_length; + // take off difference plus 1 full FOM cycle + *newsignal = *oldsignal - difference - (aPCAFOM / 12); + + } + else + { + if(difference != 0) + { + // Add anything subtracted from the pulse to the space + *newsignal = *oldsignal + difference + (aPCAFOM / 12); + difference = 0; + } + + } + + pulse_now++; + if(pulse_now > 1) pulse_now = 0; + } + + return; +} + +static void recalc_tx_available(int which_commandir) +{ + int i; + int length = 0; + static int failsafe = 0; + + if(lastSendSignalID[which_commandir] != + commandir_last_signal_id[which_commandir]) + { + /* INNOVATIONONE_FLAG:REMOVE This will be removed pending testing + * for a future release + */ + if(failsafe++ < 1000) + { + return; + } + logprintf(LOG_ERR, "Error: required the failsafe"); + } + + failsafe = 0; + for(i=which_commandir*4; i<((which_commandir+1)*4); i++) + { + length = commandir_tx_end[i] - commandir_tx_start[i]; + if(length < 0) length += 0xff; + + if(commandir_tx_available[i] < 0xff - length) + commandir_tx_available[i] = 0xff - length; + + } +} + +static void set_hash_mask(int channel_mask) // eg, 8 +{ + // bitwise set of hash_mask for easier coding... + int i,j; + j=channel_mask; + total_selected_channels = 0; + for(i=0; i<MAX_CHANNELS; i++) + { + hash_mask[i] = j & 0x01; + j = j >> 1; + if(hash_mask[i]) + selected_channels[total_selected_channels++] = i; + } +} + + +static void commandir_transmit(char *buffer, int bytes, int bitmask, + unsigned int frequency) +{ + /*** Send a TX command to 1 or more CommandIRs. + * Keep in mind: TX frequency, TX channels, TX signal length, + * which CommandIR, & what hardware version + */ + + int send_status; + unsigned char packet[TX_BUFFER_SIZE]; + /* So we know where there should be gaps between signals and more + * importantly, where there shouldn't be + */ + static char signalid = 1; + + /* Depending on the tx channels, then depending on what hardware it is, + * set the freq if needed, and send the buffer with the channel header + * that's right for that CommandIR + */ + + int devicenum = 0; + int sent = 0, tosend = 0; + unsigned char mini_tx_mask = 0; + lirc_t * signals; // have bytes/sizeof(lirc_t) signals + signals = (lirc_t *)buffer; + int total_signals = 0; + int i; + char cmdir_char[66]; + int which_signal = 0; + + total_signals = bytes / sizeof(lirc_t); + + setEmitterMask(bitmask); + + for(devicenum = 0; devicenum < device_count; devicenum++) + { + // Do we transmit on any channels on this device? + if(channels_en[ devicenum ]) + { + which_signal = 0; + switch(open_commandir_devices[ tx_order[devicenum] ].hw_type) + { + case HW_COMMANDIR_2: + + mini_tx_mask = 0; + // Short enough loop to unroll + if(channels_en[ devicenum ] & 1) mini_tx_mask |= 0x10; + if(channels_en[ devicenum ] & 2) mini_tx_mask |= 0x20; + if(channels_en[ devicenum ] & 4) mini_tx_mask |= 0x40; + if(channels_en[ devicenum ] & 8) mini_tx_mask |= 0x80; + + packet[1] = TX_COMMANDIR_II; + packet[2] = mini_tx_mask; + + short PCAFOM = 0; + float fPCAFOM = 0.0; + + if(bytes/sizeof(lirc_t) > 255) + { + logprintf(LOG_ERR, "Error: signal over max size"); + continue; + } + + fPCAFOM = (6000000 / ((frequency > 0) ? frequency : + DEFAULT_FREQ) ) ; + PCAFOM = fPCAFOM; + + lastSendSignalID[ tx_order[devicenum] ] = packet[5] = (getpid() + signalid++) + 1; + + packet[4] = PCAFOM & 0xff; + packet[3] = (PCAFOM >> 8) & 0xff; + + short packlets_to_send = 0, sending_this_time = 0; + + packlets_to_send = bytes / sizeof(lirc_t); + + int attempts; + for(attempts = 0; attempts < 10; attempts++) + { + + if((packlets_to_send*3 + 7) > open_commandir_devices[ tx_order[devicenum] ].endpoint_max[1]) + { + sending_this_time = open_commandir_devices[ tx_order[devicenum] ].endpoint_max[1]/3 - 3; + } + else + { + sending_this_time = packlets_to_send; + } + int sending; + + for(i=0; i<sending_this_time; i++) + { + sending = signals[which_signal++]; + + packet[i*3+7] = sending >> 8; // high1 + packet[i*3+8] = sending & 0xff; // low + packet[i*3+9] = sending >> 16 & 0xff; // high2 + } + + packet[0] = (sending_this_time * 3 + 7); + packet[6] = (sending_this_time == packlets_to_send) ? 0xcb : 0x00; + + send_status=usb_bulk_write( + open_commandir_devices[ tx_order[devicenum] ].cmdir_udev, + 2, // endpoint2 + (char*)packet, + packet[0], + USB_TIMEOUT_MS); + if(send_status < 0) + { + // Error transmitting. + hardware_scan(); + return; + } + + packlets_to_send -= ((send_status - 7) / 3); + if(!packlets_to_send) + { + // "No more packlets to send\n" + break; + } + } + continue; // for transmitting on next CommandIR device + + + case HW_COMMANDIR_MINI: + mini_tx_mask = 0; + if(channels_en[ devicenum ] & 1) mini_tx_mask |= 0x80; + if(channels_en[ devicenum ] & 2) mini_tx_mask |= 0x40; + if(channels_en[ devicenum ] & 4) mini_tx_mask |= 0x20; + if(channels_en[ devicenum ] & 8) mini_tx_mask |= 0x10; + + char freqPulseWidth = DEFAULT_PULSE_WIDTH; + + freqPulseWidth = (unsigned char)((1000000 / + ((frequency > 0) ? frequency: DEFAULT_FREQ) ) / 2); + + if(freqPulseWidth == 0) + { + freqPulseWidth = DEFAULT_PULSE_WIDTH; + } + + if(mini_freq[ tx_order[devicenum] ] != freqPulseWidth) + { + // Update the CommandIR Mini's next tx frequency + cmdir_char[0] = FREQ_HEADER; + cmdir_char[1] = freqPulseWidth; + cmdir_char[2] = 0; + mini_freq[ tx_order[devicenum] ] = freqPulseWidth; + send_status=usb_bulk_write( + open_commandir_devices[ tx_order[devicenum] ].cmdir_udev, + 2, // endpoint2 + cmdir_char, + 2, // 2 bytes + USB_TIMEOUT_MS); + if(send_status < 2) + { + // Error transmitting. + hardware_scan(); + return ; + } + } + + unsigned int mod_signal_length=0; + + cmdir_char[0] = TX_HEADER_NEW; + cmdir_char[1] = mini_tx_mask; + + unsigned int hibyte, lobyte; + + sent = 0; + which_signal = 0; + while(sent < (bytes / sizeof(lirc_t) * 2 ) ) + { + tosend = (bytes / sizeof(lirc_t) * 2 ) - sent; + + if(tosend > (MAX_HW_MINI_PACKET - 2)) + { + tosend = MAX_HW_MINI_PACKET - 2; + } + + for(i=0;i<(tosend/2);i++) // 2 bytes per CommandIR pkt + { + mod_signal_length = signals[which_signal++] >> 3; + hibyte = mod_signal_length/256; + lobyte = mod_signal_length%256; + cmdir_char[i*2+3] = lobyte; + cmdir_char[i*2+2] = hibyte; + } + + send_status=usb_bulk_write( + open_commandir_devices[ tx_order[devicenum] ].cmdir_udev, + 2, // endpoint2 + cmdir_char, + tosend + 2, + USB_TIMEOUT_MS); + if(send_status < 1) + { + // Error transmitting. + hardware_scan(); + return; + } + sent += tosend; + } // while unsent data + continue; // for transmitting on next CommandIR device + default: + logprintf(LOG_ERR, "Unknown hardware: %d", + open_commandir_devices[tx_order[devicenum]].hw_type); + } // hardware switch() + } // if we should tx on this device + } // for each device we have +} + + +static void commandir_child_init() +{ + alarm(0); + signal(SIGTERM, shutdown_usb); + signal(SIGPIPE, SIG_DFL); + signal(SIGINT, shutdown_usb); + signal(SIGHUP, SIG_IGN); + signal(SIGALRM, SIG_IGN); + + logprintf(LOG_ERR, "Child Initializing CommandIR Hardware"); + + usb_init(); + int i; + for(i=0;i<MAX_CHANNELS;i++) + { + next_signalq_per_channel[i] = -1; + channels_en[i] = 0xff; + } +/* + // Check kernel version: support fast decoding + char checkV[] = {0,0,0,0,0,0,0,0,0,0}; + FILE * checkfile; + int kernel_major = 0, kernel_minor = 0; + + checkfile=fopen("/proc/sys/kernel/osrelease", "r"); + if(checkfile!=NULL) + { + fgets(checkV, 7, checkfile); + printf("Checking: %s.\n", checkV); + printf("Version checking %s.\n", &checkV[4]); + kernel_major = atoi(&checkV[2]); + kernel_minor = atoi(&checkV[4]); + printf("Major is: %d, minor is %d.\n", kernel_major, kernel_minor); + fclose(checkfile); + } + + if(kernel_major < 6){ + insert_fast_zeros = 0; + logprintf(LOG_ERR, "Fast decoding disabled"); + } + else + { + if(kernel_minor <= 24) + { + logprintf(LOG_ERR, "Fast decoding enabled (1)"); + insert_fast_zeros = 1; + } + else + { + logprintf(LOG_ERR, "Fast decoding enabled"); + insert_fast_zeros = 2; + } + }*/ + hardware_scan(); +} + +static void hardware_disconnect(int commandir_spot) +{ + /* We had a read/write error, try disconnecting it and force _scan to + * reconnect - otherwise we may get perpetual read/write errors + */ + + int x; + + // reset the hash so we don't try and disconnect this device again + // device_count is decremented here + cleanup_commandir_dev(commandir_spot); + + raise_event(COMMANDIR_UNPLUG_1 + commandir_spot); + + /* Cases are: + removing device 0 when there's no more device (do nothing) + removing device < MAX when there's still 1+ devices (patch up) + removing device==MAX when there's more devices (do nothing) + */ + + // new device count-- from cleanup (if device_count > 0 AND commandir removed isn't 0 or max) + if( (device_count > 0) && (commandir_spot != device_count) ) + { + /* It wasn't the top device removed, and there's + * more than 1 device, so we have some vars to patch up + */ + for(x=commandir_spot; x<(device_count); x++) + { + channels_en[x] = channels_en[x+1]; + mini_freq[x] = mini_freq[x+1]; + commandir_last_signal_id[x] = commandir_last_signal_id[x+1]; + lastSendSignalID[x] = lastSendSignalID[x+1]; + memcpy(&open_commandir_devices[x], + &open_commandir_devices[x+1], + sizeof(struct commandir_device)); + } + + // Reset the TOP one that was just removed: + channels_en[(int)device_count] = 0x0f; + mini_freq[(int)device_count] = -1; + commandir_last_signal_id[(int)device_count] = 0; + lastSendSignalID[(int)device_count] = 0; + open_commandir_devices[(int)device_count].cmdir_udev = 0; + open_commandir_devices[(int)device_count].bus = 0; + open_commandir_devices[(int)device_count].busdev = 0; + open_commandir_devices[(int)device_count].interface = 0; + open_commandir_devices[(int)device_count].hw_type = 0; + open_commandir_devices[(int)device_count].hw_revision = 0; + open_commandir_devices[(int)device_count].hw_subversion = 0; + + } + + if(commandir_rx_num>=commandir_spot) + { + commandir_rx_num--; + } + + hardware_setorder(); +} + +static void hardware_setorder(){ + /* Tried to order to the detected CommandIRs based on bus and dev ids + * so they remain the same on reboot. Adding a new device in front + * will mean it becomes device 0 and emitters or scripts must be fixed + * Need a different param, these still change. + */ + + tx_order[0] = tx_order[1] = tx_order[2] = tx_order[3] = 0; + mini_freq[0] = mini_freq[1] = mini_freq[2] = mini_freq[3] = -1; + int largest = 0; + int tmpvals[4]; + int x, tx_spots, find_spot; + + for(x=0; x<device_count; x++) + { + tmpvals[x] = 256 * open_commandir_devices[x].bus + + open_commandir_devices[x].busdev; + } + + for(tx_spots = 0; tx_spots < device_count; tx_spots++) + { + largest = 0; + for(find_spot = 0; find_spot < device_count; find_spot++) + { + if(tmpvals[find_spot] > tmpvals[largest]) + { + largest = find_spot; + } + } + tx_order[device_count - tx_spots - 1 ] = largest; + tmpvals[largest] = 0; + } + + + // The formerly receiving CommandIR has been unplugged + if(commandir_rx_num < 0) + { + if(device_count > 0) + commandir_rx_num = 0; + } + + // Clear all pending signals + for(x=top_signalq; x >= 0; x--) + { + free(signalq[top_signalq]); + } + top_signalq = -1; + +} + +static void cleanup_commandir_dev(int spotnum) +{ + int location, devnum; + + location = open_commandir_devices[spotnum].location; + devnum = open_commandir_devices[spotnum].devnum; + + open_bus_hash[ location ][ devnum ] = 0; + device_count--; + + if(open_commandir_devices[spotnum].cmdir_udev==NULL) + { + return; + } + usb_release_interface(open_commandir_devices[spotnum].cmdir_udev, + open_commandir_devices[spotnum].interface); + usb_close(open_commandir_devices[spotnum].cmdir_udev); + open_commandir_devices[spotnum].cmdir_udev = NULL; +} + + +static void hardware_scan() +{ + // Scan for hardware changes; libusb doesn't notify us... + unsigned char located = 0; + struct usb_bus *bus = 0; + struct usb_device *dev = 0; + + int scan_find[MAX_DEVICES][2]; // [0]=bus#, [1]=busdev# + unsigned char found = 0; + // Using hash for performance instead of memory conservation (+1k) + unsigned char still_found[USB_MAX_BUSES][USB_MAX_BUSDEV]; + unsigned changed = 0; + int find_spot = 0; + + usb_find_busses(); + usb_find_devices(); + + for (bus = usb_busses; bus; bus = bus->next) + { + for (dev = bus->devices; dev; dev = dev->next) + { + if (dev->descriptor.idVendor == USB_CMDIR_VENDOR_ID) + { + located++; + // Do we already know about it? + if(!open_bus_hash[bus->location][dev->devnum]){ + // Then it's new, open it if we have a spot available + for(find_spot=0; find_spot < MAX_DEVICES; find_spot++) + { + if(open_commandir_devices[find_spot].cmdir_udev == NULL) + { + // Try to open here + open_commandir_devices[find_spot].cmdir_udev = usb_open(dev); + if(open_commandir_devices[find_spot].cmdir_udev == NULL) + { + logprintf(LOG_ERR, + "Error opening commandir - bus %d, device %d.", + bus, dev); + break; + } + else + { + + // Try to set configuration; not needed on Linux +// int usb_set_configuration(usb_dev_handle *dev, int configuration); + int r = 0; +// r = usb_set_configuration(open_commandir_devices[find_spot].cmdir_udev, 1); +// printf("Set_configuration returned %d.\n", r); + + r = usb_claim_interface( + open_commandir_devices[find_spot].cmdir_udev,0); + if(r < 0) + { + cleanup_commandir_dev(find_spot); + logprintf(LOG_ERR, + "Unable to claim CommandIR - Is it already busy?" + ); + logprintf(LOG_ERR, + "Try 'rmmod commandir' or check for other lircds" + ); + break; + } + else + { + // great, it's ours + open_commandir_devices[find_spot].location = bus->location; + open_commandir_devices[find_spot].devnum = dev->devnum; + open_bus_hash[bus->location][dev->devnum] = 1; + open_commandir_devices[find_spot].bus = bus->location; + open_commandir_devices[find_spot].busdev = dev->devnum; + scan_find[++found][0] = bus->location; + scan_find[found][1] = dev->devnum; + device_count++; + changed++; + still_found[bus->location][dev->devnum] = 1; + + struct usb_config_descriptor *config = &dev->config[0]; + struct usb_interface *interface = &config->interface[0]; + struct usb_interface_descriptor *ainterface = &interface->altsetting[0]; +/* struct usb_endpoint_descriptor *endpoint = &ainterface->endpoint[2];*/ + + int i;// Load wMaxPacketSize for each endpoint; subtract 0x80 + // for double-buffer bit + for (i = 0; i < ainterface->bNumEndpoints; i++) + { + open_commandir_devices[find_spot].endpoint_max[ + (ainterface->endpoint[i].bEndpointAddress >= 0x80) + ? (ainterface->endpoint[i].bEndpointAddress-0x80) + : (ainterface->endpoint[i].bEndpointAddress)] + = ainterface->endpoint[i].wMaxPacketSize; + } + + // compensate for double buffer: + open_commandir_devices[find_spot].endpoint_max[1] *= 2; + + // Always use the latest to RX: + commandir_rx_num = find_spot; + + switch(dev->descriptor.iProduct) + { + case 2: + logprintf(LOG_ERR, "Product identified as CommandIR II"); + open_commandir_devices[find_spot].hw_type = HW_COMMANDIR_2; + open_commandir_devices[find_spot].hw_revision = 0; + open_commandir_devices[find_spot].hw_subversion = 0; + + int send_status = 0, tries=20; + static char get_version[] = {2, GET_VERSION}; + + send_status = 4; // just to start the while() + + while(tries--){ + usleep(USB_TIMEOUT_US); // wait a moment + + // try moving this below: + send_status = usb_bulk_write( + open_commandir_devices[find_spot].cmdir_udev, + 2, // endpoint2 + get_version, + 2, + 1500); + if(send_status < 0) + { + logprintf(LOG_ERR, + "Unable to write version request - Is CommandIR busy? Error %d", send_status); + break; + } + + send_status = usb_bulk_read( + open_commandir_devices[find_spot].cmdir_udev, + 1, + (char *)commandir_data_buffer, + open_commandir_devices[ find_spot ].endpoint_max[1], + 1500); + + if(send_status < 0) + { + logprintf(LOG_ERR, + "Unable to read version request - Is CommandIR busy? Error %d", send_status); + cleanup_commandir_dev(find_spot); + break; + } + if(send_status==3) + { + if(commandir_data_buffer[0]==GET_VERSION) + { + // Sending back version information. + open_commandir_devices[find_spot].hw_revision = + commandir_data_buffer[1]; + open_commandir_devices[find_spot].hw_subversion = + commandir_data_buffer[2]; + logprintf(LOG_ERR, "Hardware revision is %d.%d.", + commandir_data_buffer[1], commandir_data_buffer[2]); + break; + } + else + { + continue; + } + } + + } + break; + default: + logprintf(LOG_ERR, "Product identified as CommandIR Mini"); + open_commandir_devices[find_spot].hw_type = + HW_COMMANDIR_MINI; + } + + if(open_commandir_devices[find_spot].hw_type == + HW_COMMANDIR_UNKNOWN) + { + logprintf(LOG_ERR, "Product UNKNOWN - cleanup"); + cleanup_commandir_dev(find_spot); + } + else + { + lastSendSignalID[find_spot] = 0; + commandir_last_signal_id[find_spot] = 0; + } + break; // don't keep looping through find_spot + } // claim? + }// open? + }// spot available? + }// for(spots) + } // if we haven't seen it before + else + { + still_found[bus->location][dev->devnum] = 1; + } + }// if it's a CommandIR + }// for bus dev's + }// for bus's + + if(!located) + { + logprintf(LOG_ERR, "No CommandIRs found"); + } + + /* Check if any we currently know about have been removed + * (Usually, we get a read/write error first) + */ + for(find_spot = 0; find_spot < MAX_DEVICES; find_spot++) + { + if(open_commandir_devices[find_spot].cmdir_udev != NULL) + { + if(still_found[open_commandir_devices[find_spot].location] + [open_commandir_devices[find_spot].devnum] != 1) + { + logprintf(LOG_ERR, "Commandir %d removed from [%d][%d].", find_spot,open_commandir_devices[find_spot].location, open_commandir_devices[find_spot].devnum); + raise_event(COMMANDIR_UNPLUG_1 + find_spot); + hardware_disconnect(find_spot); + commandir_rx_num = -1; + changed++; + } + } + } + + if(changed) + { + hardware_setorder(); + raise_event(COMMANDIR_REORDERED); + } + +} + + +// Shutdown everything and terminate +static void shutdown_usb() +{ + int x; + + // Wait for any TX to complete before shutting down + if(top_signalq >= 0) + { + shutdown_pending++; + logprintf(LOG_ERR, "Waiting for signals to finish transmitting before shutdown"); + return; + } + + for(x=0; x<MAX_DEVICES; x++) + { + if(open_commandir_devices[x].cmdir_udev ) + { + usb_release_interface(open_commandir_devices[x].cmdir_udev, + open_commandir_devices[x].interface); + usb_close(open_commandir_devices[x].cmdir_udev); + } + } + logprintf(LOG_ERR, "CommandIR driver child cleaned up and exiting"); + raise_event(COMMANDIR_STOPPED); + + _exit(EXIT_SUCCESS); +} + +static void commandir_read_loop() +{ + // Read from CommandIR, Write to pipe + + unsigned char commands[MAX_COMMAND]; + int curCommandStart = 0; + int curCommandLength = 0; + int bytes_read; + unsigned char periodic_checks = 0; + static unsigned char rx_decode_led[7] = {7, PROC_SET, 0x40, 0, 0,4, 2}; + static unsigned char init_led[7] = {7, PROC_SET, 0x00, 0x01, 3, 55, 2}; + static unsigned char deinit_led[7] = {7, PROC_SET, 0x0, 0x02, 3, 45, 2}; + static unsigned int LIRC_frequency = 38000; + + int send_status = 0; + int i = 0; + int tmp = 0; + int tmp2 = 0; + + raise_event(COMMANDIR_READY); + + for(;;){ + /*** This is the main loop the monitors control and TX events from + * the parent, and monitors the CommandIR RX buffer + */ + + curCommandStart = 0; + curCommandLength = 0; + bytes_read = read(tochild_read, commands, MAX_COMMAND); + + if(shutdown_pending > 0 && (top_signalq==-1)) + shutdown_usb(); + + if(bytes_read > 0){ + + while(curCommandStart < bytes_read){ + curCommandLength = commands[curCommandStart] + + commands[curCommandStart + 1] * 256; + + switch(commands[curCommandStart + 2]){ // the control value + case DEINIT_HEADER_LIRC: + for(i=0; i<device_count; i++) + { + if(open_commandir_devices[tx_order[i]].hw_type == + HW_COMMANDIR_2) + { + if(open_commandir_devices[tx_order[i]].cmdir_udev > 0) + { + send_status=usb_bulk_write( + open_commandir_devices[tx_order[i]].cmdir_udev, + 2, // endpoint2 + (char*)deinit_led, + 7, // bytes + USB_TIMEOUT_MS); + } + rx_hold = 1; // Put a hold on RX, but queue events + } + } + + break; + case INIT_HEADER_LIRC: + for(i=0; i<device_count; i++) + { + if(open_commandir_devices[tx_order[i]].hw_type == + HW_COMMANDIR_2) + { + if(open_commandir_devices[tx_order[i] ].cmdir_udev > 0) + { + send_status=usb_bulk_write( + open_commandir_devices[tx_order[i] ].cmdir_udev, + 2, // endpoint2 + (char*)init_led, + 7, // bytes + USB_TIMEOUT_MS); + } + rx_hold = 0; // Resume RX after queue events + } + } + break; + case RXDECODE_HEADER_LIRC: + // Successful RX decode: show it on the light. + if(open_commandir_devices[commandir_rx_num].cmdir_udev > 0) + { + send_status=usb_bulk_write( + open_commandir_devices[commandir_rx_num].cmdir_udev, + 2, // endpoint2 + (char*)rx_decode_led, + 7, // bytes + USB_TIMEOUT_MS); + + } + break; + + case FREQ_HEADER_LIRC: + LIRC_frequency = (commands[curCommandStart + 6] & 0x000000ff) | + ((commands[curCommandStart + 5] << 8) & 0x0000ff00) | + ((commands[curCommandStart + 4] << 16) & 0x00ff0000) | + ((commands[curCommandStart + 3] << 24) & 0xff000000); + if(!LIRC_frequency) + LIRC_frequency = DEFAULT_FREQ; + break; + case TX_HEADER_NEW: + case TX_LIRC_T: + if(curCommandLength==64) + { + if(check_irsend_commandir(&commands[curCommandStart + 4])) + { + break; // it's a command for us + } + } + add_to_tx_pipeline(&commands[curCommandStart + 4], + curCommandLength - 4, pre_pipeline_emitter_mask, LIRC_frequency); + break; + + case CHANNEL_EN_MASK: + pre_pipeline_emitter_mask = (commands[curCommandStart+4] << 8) | + commands[curCommandStart+3]; + break; + } + curCommandStart += curCommandLength; + + } + } + // If we're receiving, make sure the commandir buffer doesn't overrun + if(commandir_read() < 20 ) + tmp = 2; + while(tmp-- > 0) + { + tmp2 = commandir_read(); +// printf("commandir_read() (%d) returning %d.\n", tmp,tmp2); + } + if(tmp2 < 20 ){ + // once in a while, but never while we're retreaving a signal + if(++periodic_checks>100) + { + hardware_scan(); + periodic_checks = 0; + } + else + { + usleep(read_delay); + } + } + } + +} + +static int check_irsend_commandir(unsigned char *command) +{ + // decode the code like LIRC would do, and take an action + int commandir_code = 0; + + commandir_code = commandir_decode((char*)command); + + if(commandir_code > 0xef) + { + // It's a settransmitters command + int channel = commandir_code & 0x0f; + + // can only set 1 bit from here so far.., + pre_pipeline_emitter_mask = 0x0001 << channel; + + return commandir_code; + } + + switch(commandir_code) + { + case 0x53: + read_delay /= 2; // "faster" means less time + if(read_delay < MIN_WAIT_BETWEEN_READS_US) + read_delay = MIN_WAIT_BETWEEN_READS_US; + break; + case 0x54: + read_delay *= 2; // "slower" means more time + if(read_delay > MAX_WAIT_BETWEEN_READS_US) + read_delay = MAX_WAIT_BETWEEN_READS_US; + break; + + case 0x09: + case 0x0A: + logprintf(LOG_ERR, "Re-selecting RX not implemented yet"); + break; + + case 0xe6: // disable-fast-decode + logprintf(LOG_ERR, "Fast decoding disabled"); + insert_fast_zeros = 0; + break; + + case 0xe7: // enable-fast-decode + case 0xe9: // force-fast-decode-2 + logprintf(LOG_ERR, "Fast decoding enabled"); + insert_fast_zeros = 2; + break; + + case 0xe8: // force-fast-decode-1 + logprintf(LOG_ERR, "Fast decoding enabled (1)"); + insert_fast_zeros = 1; + break; + + default: + if(commandir_code > 0x60 && commandir_code < 0xf0) + { + int ledhigh = 0, ledlow = 0, ledprog = -1; + // LED Command + switch(commandir_code >> 4) + { + case 0x6: ledlow = 0x80; break; + case 0x7: ledlow = 0x40; break; + case 0x8: ledlow = 0x20; break; + case 0x9: ledlow = 0x10; break; + case 0xa: ledlow = 0x04; break; + case 0xb: ledhigh = 0x80; break; + case 0xc: ledlow = 0x01; break; + case 0xd: ledlow = 0x02; break; + case 0xe: ledlow = 0x08; break; + } + ledprog = (commandir_code & 0x0f) - 1; + + if( ((ledhigh + ledlow) > 0) && ledprog > -1) + { + // Set light: + static unsigned char lightchange[7] = {7, + PROC_SET, 0, 0, 0, 0, 3}; + lightchange[2] = ledhigh; + lightchange[3] = ledlow; + lightchange[4] = ledprog; + int send_status = 0; + + send_status=usb_bulk_write( + open_commandir_devices[tx_order[0]].cmdir_udev, + 2, // endpoint2 + (char *)lightchange, + 7, // bytes + USB_TIMEOUT_MS); + } + + return commandir_code; // done + } + + } + + return commandir_code; +} + + +// return how many RX's were in the last receive; so we know whether to poll more frequently or not +static int commandir_read() +{ + + /*** Which CommandIRs do we have to read from? Poll RX CommandIRs + * regularly, but non-receiving CommandIRs should be more periodically + */ + + int i,j; + int read_received = 0; + int read_retval = 0; + int conv_retval = 0; + int max_read = 5; + static int zeroterminated = 0; + + for(i=0; i<device_count; i++) + { + + switch(open_commandir_devices[tx_order[i]].hw_type) + { + case HW_COMMANDIR_2: + + read_retval = usb_bulk_read( + open_commandir_devices[ tx_order[i] ].cmdir_udev, + 1, + (char *)commandir_data_buffer, + open_commandir_devices[ tx_order[i] ].endpoint_max[1], + 5000); + + if(read_retval==0) + break; + + if(read_retval < 1) + { + if(read_retval < 0) + { + if(read_retval == -19){ + logprintf(LOG_ERR, "Read Error - CommandIR probably unplugged"); + } + else + { + logprintf(LOG_ERR, + "Didn't receive a full packet from a CommandIR II! - err %d ." + , read_retval); + } + hardware_disconnect(tx_order[i]); + hardware_scan(); + } + // 0 bytes is the most frequency case; nothing to report + + break; + } + + if(commandir_data_buffer[0]==RX_HEADER_TXAVAIL) + { + // sending us the current tx_start, tx_end arrays, and where it's at + commandir_tx_start[tx_order[i]*4] = commandir_data_buffer[4]; + commandir_tx_start[tx_order[i]*4+1] = commandir_data_buffer[3]; + commandir_tx_start[tx_order[i]*4+2] = commandir_data_buffer[2]; + commandir_tx_start[tx_order[i]*4+3] = commandir_data_buffer[1]; + + commandir_tx_end[tx_order[i]*4] = commandir_data_buffer[8]; + commandir_tx_end[tx_order[i]*4+1] = commandir_data_buffer[7]; + commandir_tx_end[tx_order[i]*4+2] = commandir_data_buffer[6]; + commandir_tx_end[tx_order[i]*4+3] = commandir_data_buffer[5]; + + commandir_last_signal_id[ tx_order[i] ] = commandir_data_buffer[9]; + + recalc_tx_available(tx_order[i]); + pipeline_check(); + if(top_signalq > 0) + { + read_received++; + } + + // This ALSO implies there's NO MORE RX DATA. + lirc_t lirc_zero_buffer[2] = {0, 0}; + + int tmp4 = 0; + if(zeroterminated>1001) + { + // Send LIRC a 0,0 packet to allow IMMEDIATE decoding + if(insert_fast_zeros > 0) + { + tmp4 = write(child_pipe_write, lirc_zero_buffer, sizeof(lirc_t)*insert_fast_zeros); + } + zeroterminated = 0; + } + else + { + if((zeroterminated < 1000) && (zeroterminated > 0)) + zeroterminated += 1000; + if(zeroterminated > 1000) + zeroterminated++; + } + + break; + } + + + if(commandir_data_buffer[0]==RX_HEADER_EVENTS) + { + for(j=1; j<(read_retval); j++) + { + raise_event(commandir_data_buffer[j]+tx_order[i]*0x10); + } + } + else + { + if( (commandir_data_buffer[0]==RX_HEADER_DATA) && + (commandir_rx_num==tx_order[i]) ) + { + if(rx_hold==0) // Only if we should be listening for remote cmds + { + zeroterminated = 1; + conv_retval = commandir2_convert_RX( + (unsigned short *)&commandir_data_buffer[2], + commandir_data_buffer[1]); + read_received = conv_retval; // header + } + } + } + break; + + case HW_COMMANDIR_MINI: + + max_read = 5; + while(max_read--){ + + read_retval = usb_bulk_read( + open_commandir_devices[ tx_order[i] ].cmdir_udev, + 1, + (char *)commandir_data_buffer, + 64, + USB_TIMEOUT_MS); + + if (!(read_retval == MAX_HW_MINI_PACKET)) + { + if(read_retval == -19){ + logprintf(LOG_ERR, "Read Error - CommandIR probably unplugged"); + } + else + { + logprintf(LOG_ERR, + "Didn't receive a full packet from a Mini! - err %d ." + , read_retval); + } + + hardware_disconnect(tx_order[i]); + hardware_scan(); + break; + } + + + if ( (commandir_data_buffer[1] > 0) && + (commandir_rx_num==tx_order[i]) ) + { + conv_retval = cmdir_convert_RX(commandir_data_buffer); + + read_received += commandir_data_buffer[1]; + + if(commandir_data_buffer[1] < 20) + { + // Lots of hardware buffer room left; don't tie up CPU + break; + } + } + else + { + break; + } + } // while; should only repeat if there's more RX data + + /* CommandIR Mini only has 1 buffer */ + commandir_tx_start[tx_order[i]*4] = 0; + commandir_tx_start[tx_order[i]*4+1] = 0; + commandir_tx_start[tx_order[i]*4+2] = 0; + commandir_tx_start[tx_order[i]*4+3] = 0; + + commandir_tx_end[tx_order[i]*4] = commandir_data_buffer[2]; + commandir_tx_end[tx_order[i]*4+1] = commandir_data_buffer[2]; + commandir_tx_end[tx_order[i]*4+2] = commandir_data_buffer[2]; + commandir_tx_end[tx_order[i]*4+3] = commandir_data_buffer[2]; + + /* .. and it can't pipeline... */ + commandir_last_signal_id[i] = lastSendSignalID[i]; + recalc_tx_available(tx_order[i]); + pipeline_check(); + break; + case HW_COMMANDIR_UNKNOWN: + break; + } // end switch + } // for each attached hardware device + return read_received; +} + +static void setEmitterMask(int bitmask) +{ + channels_en[0] = bitmask & 0x0F; + channels_en[1] = (bitmask >> 4) & 0xfF; + channels_en[2] = (bitmask >> 8) & 0xfF; + channels_en[3] = (bitmask >> 12) & 0xfF; +} + + +static int commandir2_convert_RX(unsigned short *bufferrx, + unsigned char numvalues) +{ + // convert hardware timestamp values to elapsed time values + + int i; + int curpos = 0; + int bytes_w = 0; + lirc_t lirc_data_buffer[256]; + + i=0; + int pca_count = 0; + int overflows = 0; + + while(curpos < numvalues ) + { + pca_count = (bufferrx[curpos] & 0x3fff) << 2; + pca_count = pca_count / 12; + + if(bufferrx[curpos] & COMMANDIR_2_OVERFLOW_MASK) + { + overflows = bufferrx[curpos+1]; + lirc_data_buffer[i] = pca_count + (overflows * 0xffff / 12); + + if(bufferrx[curpos] & COMMANDIR_2_PULSE_MASK) + { + lirc_data_buffer[i] |= PULSE_BIT; + } + curpos++; + + } + else + { + lirc_data_buffer[i] = pca_count; + if(bufferrx[curpos] & COMMANDIR_2_PULSE_MASK) + { + lirc_data_buffer[i] |= PULSE_BIT; + } + } + + curpos++; + i++; + if(i> 255) + { + break; + } + } + + bytes_w = write(child_pipe_write, lirc_data_buffer, sizeof(lirc_t)*i); + + if (bytes_w < 0) + { + logprintf(LOG_ERR, "Can't write to LIRC pipe! %d", child_pipe_write); + return 0; + } + + return bytes_w; +} + + + + +// Originally from lirc_cmdir.c +static int cmdir_convert_RX(unsigned char *orig_rxbuffer) +{ + unsigned int num_data_values = 0; + unsigned int num_data_bytes = 0; + unsigned int asint1 = 0, asint2 = 0, overflows = 0; + int i; + int bytes_w; // Pipe write + lirc_t lirc_data_buffer[256]; + + + num_data_bytes = orig_rxbuffer[1]; + + /* check if num_bytes is multiple of 3; if not, error */ + if (num_data_bytes%3 > 0) return -1; + if (num_data_bytes > 60) return -3; + if (num_data_bytes < 3) return -2; + + num_data_values = num_data_bytes/3; + + asint2 = orig_rxbuffer[3] + orig_rxbuffer[4] * 0xff; + if(last_mc_time==-1) + { + // The first time we run there's no previous time value + last_mc_time = asint2 - 110000; + if(last_mc_time < 0) last_mc_time+=0xffff; + } + + asint1 = last_mc_time; + overflows = orig_rxbuffer[5]; + + for(i=2; i<num_data_values+2; i++) + { + if(overflows < 0xff) + { + // space + lirc_data_buffer[i-2] = get_time_value(asint1, + asint2, overflows) - 26; + } + else + { // pulse + lirc_data_buffer[i-2] = get_time_value(asint1, + asint2, 0) + 26; + lirc_data_buffer[i-2] |= PULSE_BIT; + } + asint1 = asint2; + asint2 = orig_rxbuffer[i*3] + orig_rxbuffer[i*3+1] * 0xff; + overflows = orig_rxbuffer[i*3+2]; + } + last_mc_time = asint1; + + + bytes_w = write(child_pipe_write, lirc_data_buffer, sizeof(lirc_t)*num_data_values); + + if (bytes_w < 0) + { + logprintf(LOG_ERR, "Can't write to LIRC pipe! %d", child_pipe_write); + goto done; + } + +done: + return bytes_w; + +} + + + + +static unsigned int get_time_value(unsigned int firstint, + unsigned int secondint, unsigned char overflow) +{ + /* get difference between two MCU timestamps, CommandIR Mini version */ + unsigned int t_answer = 0; + + if (secondint > firstint) + { + t_answer = secondint - firstint + overflow*0xffff; + } + else + { + if (overflow > 0) + { + t_answer = (65536 - firstint) + secondint + (overflow - 1)*0xffff - 250; + } + else + { + t_answer = (65536 - firstint) + secondint; + } + } + + /* clamp to long signal */ + if (t_answer > 16000000) t_answer = PULSE_MASK; + return t_answer; +} + + +static void raise_event(unsigned int eventid) +{ + /* Raise an LIRC Event by + * Generating lirc_t Pattern + */ + static lirc_t event_data[18] = {LIRCCODE_GAP, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int i, bytes_w; + + // logprintf(LOG_ERR, "Raising event %d", eventid); + for(i=0; i<8; i++) + { + if( (eventid & 0x80) ) + { + event_data[i*2+1] = signal_base[0][0]; + event_data[i*2+2] = signal_base[0][1]; + } + else + { + event_data[i*2+1] = signal_base[1][0]; + event_data[i*2+2] = signal_base[1][1]; + } + eventid = eventid << 1; + } + + event_data[16] = LIRCCODE_GAP*4; + + bytes_w = write(child_pipe_write, event_data, sizeof(lirc_t) * 17); + + if (bytes_w < 0) + { + logprintf(LOG_ERR, "Can't write to LIRC pipe! %d", child_pipe_write); + } + +} + +static int commandir_decode(char *command) +{ + // Decode the signal to a number, just like LIRC; + // there's probably a built-in way to do this. + int i; + int code = 0; + + lirc_t *codes; + codes = (lirc_t *)command; + + for(i=0; i<15; i+=2) + { + code = code << 1; + if(codes[i]==100) + code |= 1; + } + return code; +} + diff --git a/abs/core-testing/lirc-utils/hw_commandir.h b/abs/core-testing/lirc-utils/hw_commandir.h new file mode 100755 index 0000000..2280f6c --- /dev/null +++ b/abs/core-testing/lirc-utils/hw_commandir.h @@ -0,0 +1,175 @@ + +/**************************************************************************** + ** hw_commandir.h ********************************************************** + **************************************************************************** + * + * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de> + * -- Original hw_default.h + * Modified for CommandIR Transceivers, April-June 2008, Matthew Bodkin + * + */ + +#ifndef HW_COMMANDIR_H +#define HW_COMMANDIR_H + +#define RX_BUFFER_SIZE 1024 +#define TX_BUFFER_SIZE 1024 +#define TX_QUEUE 1 +#define RX_QUEUE 0 +#define MAX_COMMANDIRS 4 +#define MAX_COMMAND 8192 + +/* transmitter channel control */ +#define MAX_DEVICES 4 +#define MAX_CHANNELS 16 +#define DEVICE_CHANNELS 4 +#define MAX_MASK 0xffff +#define MAX_SIGNALQ 100 + +/* CommandIR control codes */ +#define CHANNEL_EN_MASK 1 +#define FREQ_HEADER 2 +#define MCU_CTRL_SIZE 3 +#define TX_HEADER 7 +#define TX_HEADER_NEW 8 +/* New for CommandIR II */ + +#define READ_INPUTS 10 +#define PROC_SET 11 +#define INIT_FUNCTION 12 +#define RX_SELECT 13 +#define TX_COMMANDIR_II 14 +/* Internal to driver */ +#define TX_LIRC_T 15 +#define FREQ_HEADER_LIRC 16 +#define RXDECODE_HEADER_LIRC 17 +#define INIT_HEADER_LIRC 18 +#define DEINIT_HEADER_LIRC 19 +#define GET_VERSION 20 + +#define COMMANDIR_2_PULSE_MASK 0x8000 +#define COMMANDIR_2_OVERFLOW_MASK 0x4000 + +#define DEFAULT_PULSE_WIDTH 13 + +#define USB_CMDIR_VENDOR_ID 0x10c4 +#define USB_CMDIR_PRODUCT_ID 0x0003 +#define USB_CMDIR_MINOR_BASE 192 + +#define HW_COMMANDIR_MINI 1 +#define HW_COMMANDIR_2 2 +#define HW_COMMANDIR_UNKNOWN 127 + +#define MAX_HW_MINI_PACKET 64 + +// CommandIR has lots of buffer room, we don't need to poll constantly +#define USB_TIMEOUT_MS 5000 +#define USB_TIMEOUT_US 1000 +#define WAIT_BETWEEN_READS_US 10000 +#define MAX_WAIT_BETWEEN_READS_US 5000000 +#define MIN_WAIT_BETWEEN_READS_US 5000 + +#define USB_MAX_BUSES 8 +#define USB_MAX_BUSDEV 127 + +#define RX_HEADER_DATA 0x01 +#define RX_HEADER_EVENTS 0x02 +#define RX_HEADER_TXAVAIL 0x03 + + +// We keep CommandIR's OPEN even on -deinit for speed and to monitor +// Other non-LIRC events (plugin, suspend, etc) +#define USB_KEEP_WARM 1 + +// CommandIR lircd.conf event driven code definitions +#define LIRCCODE_GAP 125000 +#define JACK_PLUG_1 0x01 +#define JACK_PLUG_2 0x02 +#define JACK_PLUG_3 0x03 +#define JACK_PLUG_4 0x04 +#define JACK_PLUG_5 0x11 +#define JACK_PLUG_6 0x12 +#define JACK_PLUG_7 0x13 +#define JACK_PLUG_8 0x14 +#define JACK_PLUG_9 0x21 +#define JACK_PLUG_10 0x22 +#define JACK_PLUG_11 0x23 +#define JACK_PLUG_12 0x24 +#define JACK_PLUG_13 0x31 +#define JACK_PLUG_14 0x32 +#define JACK_PLUG_15 0x33 +#define JACK_PLUG_16 0x34 + +#define JACK_UNPLUG_1 0x05 +#define JACK_UNPLUG_2 0x06 +#define JACK_UNPLUG_3 0x07 +#define JACK_UNPLUG_4 0x08 +#define JACK_UNPLUG_5 0x15 +#define JACK_UNPLUG_6 0x16 +#define JACK_UNPLUG_7 0x17 +#define JACK_UNPLUG_8 0x18 +#define JACK_UNPLUG_9 0x25 +#define JACK_UNPLUG_10 0x26 +#define JACK_UNPLUG_11 0x27 +#define JACK_UNPLUG_12 0x28 +#define JACK_UNPLUG_13 0x35 +#define JACK_UNPLUG_14 0x36 +#define JACK_UNPLUG_15 0x37 +#define JACK_UNPLUG_16 0x38 + +#define SELECT_TX_INTERNAL 0x09 +#define SELECT_TX_ExTERNAL 0x0A + +#define SELECT_TX_ON_1 0x0D +#define SELECT_TX_ON_2 0x1D +#define SELECT_TX_ON_3 0x2D +#define SELECT_TX_ON_4 0x3D + +#define JACK_PLUG_RX_1 0x0B +#define JACK_UNPLUG_RX_1 0x0C +#define JACK_PLUG_RX_2 0x1B +#define JACK_UNPLUG_RX_2 0x1C +#define JACK_PLUG_RX_3 0x2B +#define JACK_UNPLUG_RX_3 0x2C +#define JACK_PLUG_RX_4 0x3B +#define JACK_UNPLUG_RX_4 0x3C + +#define COMMANDIR_PLUG_1 0x41 +#define COMMANDIR_PLUG_2 0x42 +#define COMMANDIR_PLUG_3 0x43 +#define COMMANDIR_PLUG_4 0x44 + +#define COMMANDIR_UNPLUG_1 0x45 +#define COMMANDIR_UNPLUG_2 0x46 +#define COMMANDIR_UNPLUG_3 0x47 +#define COMMANDIR_UNPLUG_4 0x48 + +#define COMMANDIR_REORDERED 0x50 +#define COMMANDIR_READY 0x51 +#define COMMANDIR_STOPPED 0x52 +#define COMMANDIR_POLL_FASTER 0x53 +#define COMMANDIR_POLL_SLOWER 0x54 + +#define SETTRANSMITTERS_1 0xf0 +#define SETTRANSMITTERS_2 0xf1 +#define SETTRANSMITTERS_3 0xf2 +#define SETTRANSMITTERS_4 0xf3 +#define SETTRANSMITTERS_5 0xf4 +#define SETTRANSMITTERS_6 0xf5 +#define SETTRANSMITTERS_7 0xf6 +#define SETTRANSMITTERS_8 0xf7 +#define SETTRANSMITTERS_9 0xf8 +#define SETTRANSMITTERS_10 0xf9 +#define SETTRANSMITTERS_11 0xfa +#define SETTRANSMITTERS_12 0xfb +#define SETTRANSMITTERS_13 0xfc +#define SETTRANSMITTERS_14 0xfd +#define SETTRANSMITTERS_15 0xfe +#define SETTRANSMITTERS_16 0xff + +// What's in a returning data packet +#define COMMANDIR_RX_EVENTS 0x02 +#define COMMANDIR_RX_DATA 0x01 + + +#endif |