summaryrefslogtreecommitdiffstats
path: root/abs/core/lirc_085-utils/hw_commandir.c
diff options
context:
space:
mode:
Diffstat (limited to 'abs/core/lirc_085-utils/hw_commandir.c')
-rwxr-xr-xabs/core/lirc_085-utils/hw_commandir.c1926
1 files changed, 1926 insertions, 0 deletions
diff --git a/abs/core/lirc_085-utils/hw_commandir.c b/abs/core/lirc_085-utils/hw_commandir.c
new file mode 100755
index 0000000..40ac0de
--- /dev/null
+++ b/abs/core/lirc_085-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;
+}
+