diff options
| author | James Meyer <james.meyer@operamail.com> | 2009-04-20 21:37:50 (GMT) | 
|---|---|---|
| committer | James Meyer <james.meyer@operamail.com> | 2009-04-20 21:37:50 (GMT) | 
| commit | 1ece0333681f86ab6d35367e306870e5cc482ef6 (patch) | |
| tree | 4db85742097da70d90f19877032a7fddef6b0126 /abs/core-testing/lirc-utils | |
| parent | 39cccbd0ad3b8266a3ea460314bb01ce79340b8f (diff) | |
| parent | d1f87e56e01ffc0c6300dafbea2cb3331bf50ab6 (diff) | |
| download | linhes_pkgbuild-1ece0333681f86ab6d35367e306870e5cc482ef6.zip linhes_pkgbuild-1ece0333681f86ab6d35367e306870e5cc482ef6.tar.gz linhes_pkgbuild-1ece0333681f86ab6d35367e306870e5cc482ef6.tar.bz2 | |
Merge branch 'HEAD' of ssh://jams@knoppmyth.net/mount/repository/LinHES-PKGBUILD
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 | 
