Improvements to picoLCD driver Infra-Red processing
Martin Tharby Jones <[email protected]> Fri, 13 Sep 2013 20:35:56 +0100
| Newsgroups | gmane.comp.sysutils.lcdproc |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
--------------080202020907090900050006
Content-Type: multipart/alternative;
boundary="------------040805050407000501050005"
--------------040805050407000501050005
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Hello,
I have attached a patch with improvements to the picoLCD IR code.
There are two areas that have been changed:
1. Use multiple USB transfer buffers so that data cannot be lost if the
system is busy.
2. Allow the IR timing data to be sent in microseconds or jiffies
(1/16384s). Using the smaller timing resolution improves the ability
of irrecord to determine the timing of the IR signal.
Martin
--------------040805050407000501050005
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
Hello,<br>
<br>
I have attached a patch with improvements to the picoLCD IR code.<br>
There are two areas that have been changed:<br>
<ol>
<li>Use multiple USB transfer buffers so that data cannot be lost
if the system is busy.</li>
<li>Allow the IR timing data to be sent in microseconds or jiffies
(1/16384s). Using the smaller timing resolution improves the
ability of irrecord to determine the timing of the IR signal.</li>
</ol>
<p>Martin<br>
<br>
</p>
</body>
</html>
--------------040805050407000501050005--
--------------080202020907090900050006
Content-Type: text/x-patch;
name="picoLCD_LIRC.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="picoLCD_LIRC.patch"
Index: LCDd.conf
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/LCDd.conf,v
retrieving revision 1.169
diff -u -r1.169 LCDd.conf
--- LCDd.conf 8 May 2013 19:19:55 -0000 1.169
+++ LCDd.conf 13 Sep 2013 19:13:59 -0000
@@ -35,6 +35,7 @@
# function properly.
# NOTE: Always place a slash as last character !
DriverPath=server/drivers/
+# DriverPath=/usr/lib/lcdproc/
# Tells the server to load the given drivers. Multiple lines can be given.
# The name of the driver is case sensitive and determines the section
@@ -50,10 +51,12 @@
# mdm166a, ms6931, mtc_s16209x, MtxOrb, mx5000, NoritakeVFD, picolcd,
# pyramid, sdeclcd, sed1330, sed1520, serialPOS, serialVFD, shuttleVFD, sli,
# stv5730, svga, t6963, text, tyan, ula200, vlsys_m428, xosd
-Driver=curses
+#Driver=curses
+Driver=picolcd
+Driver=lirc
# Tells the driver to bind to the given interface. [default: 127.0.0.1]
-Bind=127.0.0.1
+Bind=LiFi.local
# Listen on this specified port. [default: 13666]
Port=13666
@@ -116,8 +119,8 @@
ToggleRotateKey=Enter
PrevScreenKey=Left
NextScreenKey=Right
-#ScrollUpKey=Up
-#ScrollDownKey=Down
+ScrollUpKey=Up
+ScrollDownKey=Down
## The menu section. The menu is an internal LCDproc client. ##
@@ -128,12 +131,13 @@
# Up to six keys are supported. The MenuKey (to enter and exit the menu), the
# EnterKey (to select values) and at least one movement keys are required.
# These are the default key assignments:
-MenuKey=Escape
+#MenuKey=Escape
+MenuKey=Minus+Plus
EnterKey=Enter
UpKey=Up
DownKey=Down
-#LeftKey=Left
-#RightKey=Right
+LeftKey=Left
+RightKey=Right
### Driver sections are below this line, in alphabetical order ###
@@ -802,10 +806,10 @@
[lirc]
# Specify an alternative location of the lircrc file [default: ~/.lircrc]
-#lircrc=/etc/lircrc.lcdproc
+lircrc=/etc/lirc/lircrc
# Must be the same as in your lircrc
-#prog=lcdd
+prog=lcdd
@@ -998,7 +1002,7 @@
# Sets the initial state of the backlight upon start-up.
# [default: on; legal: on, off]
-#Backlight=on
+Backlight=on
# Set the initial brightness [default: 1000; legal: 0 - 1000]. Works only
# with the 20x4 device
@@ -1012,7 +1016,7 @@
Contrast=1000
# Link the key lights to the backlight? [default: on; legal: on, off]
-#LinkLights=off
+LinkLights=off
# Light the keys? [default: on; legal: on, off]
Keylights=on
@@ -1030,15 +1034,21 @@
# Host name or IP address of the LIRC instance that is to receive IR codes
# If not set, or set to an empty value, IR support is disabled.
-#LircHost=127.0.0.1
+LircHost=127.0.0.1
# UDP port on which LIRC is listening [default: 8765; legal: 1 - 65535]
LircPort=8765
-# Threshold in jiffies of synthesized gap that triggers flushing the IR data
-# to lirc [default: 100 ; max: 32767 ]
-# 100 means 6.1ms. legal: 16 - 32767; Use 0 to disable.
-LircFlushThreshold=100
+# UDP data time unit for LIRC [default: off; legal: on, off]
+# On: times sent in microseconds (requires LIRC UDP driver that accepts this).
+# Off: times sent in 'jiffies' (1/16384s) (supported by standard LIRC UDP driver).
+LircTime_us=on
+
+# Threshold in microseconds of the gap that triggers flushing the IR data
+# to lirc [default: 8000; legal: 1000 - ]
+# If LircTime_us is on values greater than 32.767ms will disable the flush
+# If LircTime_us is off values greater than 1.999938s will disable the flush
+LircFlushThreshold=10000
Index: docs/lcdproc-user/drivers/picolcd.docbook
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/docs/lcdproc-user/drivers/picolcd.docbook,v
retrieving revision 1.14
diff -u -r1.14 picolcd.docbook
--- docs/lcdproc-user/drivers/picolcd.docbook 10 Dec 2011 15:39:47 -0000 1.14
+++ docs/lcdproc-user/drivers/picolcd.docbook 13 Sep 2013 19:13:59 -0000
@@ -323,7 +323,7 @@
</para>
<para>
LIRC should be configured to use the driver "udp", which will cause it to listen on some
- UDP port for packets containing a series of integers, representing pulse and mark
+ UDP port for packets containing a series of integers, representing mark and space
intervals from the sensor. It doesn't matter whether LCDd or LIRC is started first; if LIRC
isn't listening, the packets from LCDd will be discarded. When LIRC comes back, it will
start picking up the packets. Similarly, LCDd can be stopped and restarted without affecting
@@ -347,16 +347,58 @@
<varlistentry>
<term>
+ <property>LircTime_us</property> = ¶meters.yesdefno;
+ </term>
+ <listitem>
+ <para>
+ If <property>LircTime_us</property> is set to on mark and space times
+ are sent to LIRC in microseconds (requires a LIRC UDP driver that
+ accepts this).
+ </para>
+ <para>
+ If <property>LircTime_us</property> is set to off mark and space times
+ are sent to LIRC in 'jiffies' (1/16384s) (supported by the standard LIRC
+ UDP driver).
+ </para>
+ <para>
+ Default is <literal>off</literal>.
+ </para>
+<note>
+ <para>
+ One 'jiffy' is approximatly 61 microseconds about a tenth of typical IR
+ mark and space times. LIRC configuration program <code>irrecord</code>
+ cannot reliably detect the IR data timing when measured in 'jiffies' it
+ works better with microseconds.
+ </para>
+ <para>
+ I have submitted a patch that modifies the LIRC udp driver to support
+ timing data in microseconds but it has been ignored. The LIRC team
+ currently seems only to be intested in adding IR support to the kernal.
+ You can obtain my modified files from
+ <ulink url="https://github.com/emteejay/Patched-LIRC.git">GitHub</ulink>.
+ The standard UDP driver is satisfactory for most uses but I recommend
+ using the modified driver if you intend to use <code>irrecord</code>
+ </para>
+</note>
+ </listitem>
+</varlistentry>
+
+<varlistentry>
+ <term>
<property>LircFlushThreshold</property> =
<parameter><replaceable>DURATION</replaceable></parameter>
</term>
<listitem>
<para>
- This value is the length in jiffies (1/16384 seconds) of the synthesized sync space that will
- trigger sending the queued IR data to LIRC. Values up to 32767 (2s) are permitted, values lower
- than 16 will suppress the flushing IR data during processing. The default is
- <literal>100</literal> jiffies (6.1ms). It's should only be needed to change this value
- when lircd.conf has a gap < 6100 or the samples > 6300.
+ This value is the length in microseconds of the gap that will trigger
+ sending the queued IR data to LIRC. Values greater than 1000 (1ms) are
+ permitted, lower values will set the default value 8000 (8ms). The
+ maximum depends on the setting of LircTime_us; if LircTime_us is on
+ values greater than 32.767ms will disable the flush, if LircTime_us is
+ off values greater than 1.999938s will disable the flush. The value
+ should be less than the gap times specified in <code>lircd.conf</code>
+ and greater than any space time specified in any header, one, zero, etc.
+ field.
</para>
</listitem>
</varlistentry>
@@ -397,12 +439,27 @@
working, this driver by default adds the gap as well as the sync. However I have
<emphasis>still</emphasis> had trouble getting <code>irrecord</code> to work; you need at least
to feed it a template configuration containing sync and gap data.
+ The LIRC configuration program <code>irrecord</code> cannot reliably
+ detect the IR data timing when measured in 'jiffies' it works better
+ with microseconds, see <code>LircTime_us</code> above.
</para>
-
+<note>
+ <para>
+ The current libusb-1.0 implementation polls at 32Hz to see if any USB
+ processing is required, this is needed when a key has been pressed or
+ some IR data has been received. 32Hz has a period of 31.25ms this is not
+ really fast enough the picoLCD USB transfers can occur every 10ms. This
+ may cause buffer overrun problems for long bursts of IR data. The best
+ solution would be to include USB processing in the main loop <code>select</code>
+ statement this has not been done to avoid major changes to the core
+ code, to work-round this extra USB transfer buffers are allocated. It
+ may also be worth building with <code>PROCESS_FREQ</code> set to 100Hz
+ (in <code>server/main.h</code>).
+ </para>
+</note>
</sect3>
</sect2>
-
<sect2 id="picolcd-copy">
<title>Copyright</title>
Index: server/drivers/picolcd.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/picolcd.c,v
retrieving revision 1.25
diff -u -r1.25 picolcd.c
--- server/drivers/picolcd.c 24 Mar 2013 13:59:22 -0000 1.25
+++ server/drivers/picolcd.c 13 Sep 2013 19:14:00 -0000
@@ -48,15 +48,22 @@
#define NUM_CCs 8 /* max. number of custom characters */
#define KEY_BUFFER_SIZE 8 /* size of the key ring buffer */
+#define ANSI_ESCAPES /* Use colour to make (IR) debug easer to read */
+#ifdef ANSI_ESCAPES
+#define TEXT_NORMAL "\033[0m"
+#define TEXT_RED "\033[31m"
+#else
+#define TEXT_NORMAL ""
+#define TEXT_RED ""
+#endif
+
#ifdef HAVE_LIBUSB_1_0
/**
- * This structure holds the keys reported in a key event. high_key is set if
- * a single key is pressed or it holds the first key if two keys are pressed.
- * low_key holds the second key pressed (if any).
+ * This structure holds the keys reported in a key event.
*/
typedef struct {
- unsigned char high_key;
- unsigned char low_key;
+ unsigned char high_key; /**< Set if a single key is pressed or it holds the first key if two keys are pressed.*/
+ unsigned char low_key; /**< Holds the second key pressed (if any). */
} keys;
#endif
@@ -75,6 +82,37 @@
*/
#undef USE_LIBUSB_SINGLE_SELECT
+/** Multiple buffers are needed to ensure that no USB transfer is missed. Ideally
+ * a single select statement with appropriate timeout should be used, in this
+ * case double buffering is sufficient. When distributed select statements are
+ * used processing of the USB signals is performed by
+ * libusb_handle_events_timeout() in picoLCD_get_key(). This is called at 32Hz
+ * (PROCESS_FREQ) i.e. every 31.25ms which is not really fast enough the picoLCD
+ * USB transfers can occur every 10ms. This may cause buffer overrun problems
+ * for long bursts of IR data, to avoid problems there must be more than 3
+ * buffers.
+ */
+#ifdef USE_LIBUSB_SINGLE_SELECT
+#define USB_BUFFERS 2
+#else
+#define USB_BUFFERS 4
+#endif
+#ifdef HAVE_LIBUSB_1_0
+/**
+ * This structure holds the data for a USB transfer.
+ */
+typedef struct usb_transfer_data {
+ /** structure for the details of the asynchronous USB transfer */
+ struct libusb_transfer *transfer;
+ /** transfer status */
+ int status;
+ /** Pointer to driver private data */
+ Driver *drvthis;
+ /** data buffer for the USB transfer */
+ unsigned char buffer[PICOLCD_MAX_DATA_LEN];
+}UsbTransferData;
+#endif
+
/** Private data for the picoLCD driver */
typedef struct picolcd_private_data {
USB_DEVICE_HANDLE *lcd;
@@ -104,15 +142,13 @@
unsigned char *resptr;
struct timeval lastmsg;
int lastval;
+ int lirc_time_us;
int flush_threshold;
#ifdef HAVE_LIBUSB_1_0
/* Pointer to libusb 1.0 session */
libusb_context *lib_ctx;
- /* data buffer for the asynchronous USB transfer */
- unsigned char input_buffer[PICOLCD_MAX_DATA_LEN];
- /* structure for the details of the asynchronous USB transfer */
- struct libusb_transfer *input_transfer;
- int libusb_status;
+ /* structure for the details of the USB transfer */
+ UsbTransferData input_transfer[USB_BUFFERS];
/* buffer for the key press data */
keys key_buffer[KEY_BUFFER_SIZE];
int key_read_index; /* Read index in the key_buffer */
@@ -136,6 +172,7 @@
static void picolcd_lircsend(Driver *drvthis);
static void ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdata);
#ifdef HAVE_LIBUSB_1_0
+static void free_usb_transfers(Driver *drvthis);
static void key_buffer_put(Driver *drvthis, unsigned char high_key, unsigned char low_key);
static void usb_cb_input(struct libusb_transfer *transfer);
#else
@@ -215,6 +252,7 @@
const char *lirchost;
int lircport;
int id;
+ int i;
int tmp;
p = (PrivateData *) malloc(sizeof(PrivateData));
@@ -242,8 +280,6 @@
libusb_set_debug(p->lib_ctx, 3);
#endif
- p->libusb_status = LIBUSB_SUCCESS;
- p->input_transfer = NULL;
p->key_read_index = 0;
p->key_write_index = 0;
@@ -298,19 +334,36 @@
if (error) {
report(RPT_WARNING, "%s: libusb_set_interface_alt_setting error %d", drvthis->name, error);
}
- p->input_transfer = libusb_alloc_transfer(0);
- if (p->input_transfer == NULL) {
- report(RPT_ERR, "%s: libusb_alloc_transfer failed", drvthis->name);
- return -1;
- }
- libusb_fill_interrupt_transfer(p->input_transfer, p->lcd, LIBUSB_ENDPOINT_IN + 1, p->input_buffer,
- sizeof(p->input_buffer), usb_cb_input, (void *)drvthis, 0);
- error = libusb_submit_transfer(p->input_transfer);
- if (error) {
- report(RPT_ERR, "%s: libusb_submit_transfer error %d", drvthis->name, error);
- libusb_free_transfer(p->input_transfer);
- p->input_transfer = NULL;
- return -1;
+
+ /* Set-up USB input transfer data structures */
+ for (i = 0; i < USB_BUFFERS; i++)
+ p->input_transfer[i].transfer = NULL;
+ for (i = 0; i < USB_BUFFERS; i++)
+ {
+ UsbTransferData *utdp = &p->input_transfer[i];
+
+ utdp->drvthis = drvthis;
+ utdp->transfer = libusb_alloc_transfer(0);
+ if (utdp->transfer == NULL) {
+ report(RPT_ERR, "%s: libusb_alloc_transfer failed", drvthis->name);
+ free_usb_transfers(drvthis);
+ return -1;
+ }
+ libusb_fill_interrupt_transfer(utdp->transfer,
+ p->lcd,
+ LIBUSB_ENDPOINT_IN + 1,
+ utdp->buffer,
+ sizeof(utdp->buffer),
+ usb_cb_input,
+ (void *)utdp,
+ 0);
+ utdp->status = libusb_submit_transfer(utdp->transfer);
+ if (utdp->status) {
+ report(RPT_ERR, "%s: libusb_submit_transfer error %d",
+ drvthis->name, utdp->status);
+ free_usb_transfers(drvthis);
+ return -1;
+ }
}
#else /* The libusb 0.1 way */
@@ -500,20 +553,41 @@
/* LIRC is only enabled if a hostname is set */
p->IRenabled = (lirchost != NULL && *lirchost != '\0') ? 1 : 0;
- tmp = drvthis->config_get_int(drvthis->name, "LircFlushThreshold", 0, DEFAULT_FLUSH_THRESHOLD_JIFFY);
- /* Prevent small 'foolish' values these will disable the check also! */
- if (p->flush_threshold < 16) {
- report(RPT_WARNING, "%s: flush threshold to small - disabled");
- tmp = 0x8000; /* Disabled, send check will always fail! */
- }
- else if (p->flush_threshold > 0x7FFF) {
- report(RPT_WARNING, "%s: flush threshold to large, using default");
- tmp = DEFAULT_FLUSH_THRESHOLD_JIFFY;
+ p->lirc_time_us = drvthis->config_get_bool(drvthis->name, "LircTime_us", 0, DEFAULT_LIRC_TIME_us);
+
+ tmp = drvthis->config_get_int(drvthis->name, "LircFlushThreshold", 0, DEFAULT_FLUSH_THRESHOLD);
+ /*
+ * Enforce a sensible minimum. Only want to flush on gaps between IR bursts not the spaces between marks.
+ */
+ if (tmp < 1000) {
+ report(RPT_WARNING, "%s: flush threshold to small (%d) , using default", drvthis->name, tmp);
+ tmp = DEFAULT_FLUSH_THRESHOLD;
+ }
+ if (p->lirc_time_us) {
+ /*
+ * Values greater than 32.767ms will disable the flush.
+ */
+ if (32727 < tmp) {
+ report(RPT_WARNING, "%s: flush threshold to large (%d), disabled", drvthis->name, tmp);
+ }
+ }
+ else {
+ /*
+ * Scale between microseconds and jiffies (1/16384s)
+ * Values greater than 1999.938ms will disable the flush.
+ */
+ if (0x7FFF * 15625 / 256 < tmp) {
+ report(RPT_WARNING, "%s: flush threshold to large (%d), disabled", drvthis->name, tmp);
+ tmp = 0x8000;
+ }
+ else {
+ tmp = tmp * 256 / 15625;
+ }
}
p->flush_threshold = tmp;
/*
- * Simulate that the last value send was a PULSE, so we start with
+ * Simulate that the last value send was a MARK, so we start with
* sending a SPACE to make LIRC happy
*/
p->lastval = 0;
@@ -545,8 +619,8 @@
p->lircserver.sin_addr = *(struct in_addr *) hostinfo->h_addr; /* IP address */
p->lircserver.sin_port = htons(lircport); /* server port */
- report(RPT_INFO, "%s: IR events will be sent to LIRC on %s:%d, with flush threshold=%d",
- drvthis->name, lirchost, lircport, p->flush_threshold);
+ report(RPT_INFO, "%s: IR events will be sent to LIRC on %s:%d, with flush threshold=%d, time unit: %s",
+ drvthis->name, lirchost, lircport, p->flush_threshold, p->lirc_time_us ? "us" : "1/16384s");
}
report(RPT_INFO, "%s: init complete", drvthis->name);
@@ -567,22 +641,7 @@
#ifdef HAVE_LIBUSB_1_0
int error;
- if (p->input_transfer != NULL) {
- /* Need to cancel transfer before it is freed */
- libusb_cancel_transfer(p->input_transfer);
- while (p->libusb_status != LIBUSB_TRANSFER_CANCELLED) {
- struct timeval timeout;
- /*
- * Wait for the cancellation to complete, the
- * call-back will then have freed the
- * transfer.
- */
- report(RPT_INFO, "%s: waiting for usb transfer to be cancelled", drvthis->name);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- libusb_handle_events_timeout(p->lib_ctx, &timeout);
- }
- }
+ free_usb_transfers(drvthis);
error = libusb_release_interface(p->lcd, 0);
if (error) {
@@ -670,7 +729,7 @@
/**
- * Flush data on screen to the display.
+ * Flush data in screen buffer to the display.
* \param drvthis Pointer to driver structure.
*/
MODULE_EXPORT void
@@ -716,6 +775,23 @@
* \param x Horizontal character position (column).
* \param y Vertical character position (row).
* \param string String that gets written.
+ *
+ * The picoLCD uses a HD44780UA00 which provides ASCII and Japanese fonts.
+ *
+ * Characters 0x20-0x7F are ASCII with the following substitutions:
+ | Index | ASCII | Substitute |
+ | :---: | :---: | :--------------- |
+ | 0x5C | \ | Yen |
+ | 0x7E | ~ | Rightwards Arrow |
+ | 0x7F | DEL | Leftwards Arrow |
+ *
+ * Characters 0xA0-0xDF are half-width Katakana. They map to
+ * the Unicode block starting at U+FF60 and ending at U+FF9F.
+ *
+ * Characters 0xE0-0xFF are various Greek letters and symbols.
+ *
+ * (The HD44780UA02 provides a European font: ASCII, accented characters
+ * and some useful icons.)
*/
MODULE_EXPORT void
picoLCD_string(Driver *drvthis, int x, int y, unsigned char string[])
@@ -1215,8 +1291,9 @@
struct timeval timeout;
/*
* FIXME: It is not efficient to call this at 32Hz, it is only needed
- * if a key has been pressed or IR data has been received. Process
- * any outstanding USB events for our session.
+ * if a key has been pressed or IR data has been received.
+ *
+ * Process any outstanding USB events for our session.
*/
timeout.tv_sec = 0;
timeout.tv_usec = 0;
@@ -1547,7 +1624,7 @@
* LIRC UDP packets expect 16-bit intervals, with MSB set for space.
* Intervals are measured in jiffies (1/16384 s).
* PicoLCD USB packets contain 16-bit intervals, with value negated
- * for space. Intervals are in microseconds.
+ * for mark. Intervals are in microseconds.
* PicoLCD presents the bytes in network order, and they must be put back
* in that order for transmission via UDP.
* One jiffy == 61 us. 537 us == 9j.
@@ -1557,15 +1634,18 @@
* \param cbdata Length of data to be transcoded.
*
* \note The picoLCD introduces two issues:
+ *
* \note 1. Every read contains a maximum of 10 samples (20 bytes), sending the
* converted samples direct to LIRC will lead to timeouts, in LIRC
* while we are still waiting for the rest of the samples. To fix this I
* queue the samples and send it when a sync is detected or by a timeout.
+ *
* \note 2. The sync (long space) are not send by the picoLCD. To fix this we
- * look for a pulse at the end of the last message and a pulse at the
+ * look for a mark at the end of the last message and a mark at the
* begin new message, we then flush the queue and start with a (sync)
* space, with the duration of the time between the last and current
* message.
+ *
* \note To make LIRC happy I send the queued samples with the sync space a the
* begin, and not at the end (the next 'calculated' sync is put at the
* begin of the next message), this is because LIRC requires a space at
@@ -1582,14 +1662,33 @@
/* Check for odd buffer length (invalid buffer) */
if (cbdata & 1) {
+ report(RPT_WARNING, "picolcd: buffer invalid length (%d)", cbdata);
return;
}
/* Get time needed to calculate the time between 2 IR data messages */
gettimeofday(&now, 0);
+#ifdef DEBUG
+ debug(RPT_DEBUG, "picolcd: received %d IR samples", cIntervals);
+ {
+ unsigned char *ptr = data;
+ int c = cIntervals;
+ char logbuf[cbdata * 5];
+ char *logptr = logbuf;
+ while (c--) {
+ unsigned int val = *ptr++;
+ val |= *ptr++ << 8;
+ logptr += sprintf(logptr, " %s%04x",
+ (0x7fff < val) ? TEXT_RED : TEXT_NORMAL,
+ (0x7fff < val) ? 0x10000 - val : val);
+ }
+ debug(RPT_DEBUG, "picolcd: data:%s" TEXT_NORMAL, logbuf);
+ }
+#endif
+
/* Check for a missing SPACE since the last message */
- debug(RPT_INFO, "picolcd: last %04x first %04x", p->lastval, (-w & 0xFFFF));
+ debug(RPT_DEBUG, "picolcd: last %04x first %04x", p->lastval, (-w & 0xFFFF));
if (((p->lastval & 0x8000) == 0) && ((-w & 0x8000) == 0)) {
/*
* Calculate the time passed from the last IR message to now
@@ -1600,53 +1699,105 @@
timersub(&now, &p->lastmsg, &time_gap);
- /* previous message is complete send it without the added space */
- debug(RPT_INFO, "picolcd: missing sync detected, flushing queue before adding sync");
- picolcd_lircsend(drvthis);
+ if (p->resptr != p->result) {
+ /* previous message is complete send it without the added space */
+ debug(RPT_INFO, "picolcd: missing space detected, flushing queue before adding sync");
+ picolcd_lircsend(drvthis);
+ }
+ else {
+ debug(RPT_INFO, "picolcd: missing space detected, adding timed space to buffer");
+ }
- /*
- * Prevent the overflow (2 secs = 32678 jiffies), but allow
- * 2.99 seconds to reach the max
- */
- if (2 <= time_gap.tv_sec) {
+ if (p->lirc_time_us) {
/*
- * microseconds to jiffies (same as (16384/1000000)
- * but no possible int32 overflow)
+ * When sending times in microseconds a single word gives a range up
+ * to 32767us. I am not aware of anything that uses IR pulse or space
+ * times as long as 32ms so the pulse and space times can just be
+ * copied from the buffer see below. The gap between transmissions can
+ * be very long so may need special encoding. LIRC processes times in
+ * microseconds using 24 bits so send a zero word as a flag followed
+ * by a three byte time sent as four bytes to keep the buffer length
+ * even. 24 bits gives a range up to 16777215 so we limit to 16s for
+ * simplicity.
*/
- gap = ((time_gap.tv_sec * 1000000 + time_gap.tv_usec) * 256) / 15625;
+ if (16 <= time_gap.tv_sec) {
+ debug(RPT_INFO, "picolcd: IR transmission gap: 8000 00F42400");
+ *p->resptr++ = 0x00; /* zero */
+ *p->resptr++ = 0x80; /* with space bit */
+ *p->resptr++ = 0x00; /* 16s as 24 bit value */
+ *p->resptr++ = 0x24;
+ *p->resptr++ = 0xf4;
+ *p->resptr++ = 0x00;
+ }
+ else {
+ gap = (time_gap.tv_sec * 1000000 + time_gap.tv_usec);
+ if (0x7FFF < gap) {
+ /* Send as 24 bits */
+ debug(RPT_INFO, "picolcd: IR transmission gap: 8000 %08x", gap);
+ *p->resptr++ = 0x00; /* zero */
+ *p->resptr++ = 0x80; /* with space bit */
+ *p->resptr++ = (unsigned char)(gap & 0xff);
+ *p->resptr++ = (unsigned char)((gap >> 8) & 0xff);
+ *p->resptr++ = (unsigned char)((gap >> 16) & 0xff);
+ *p->resptr++ = 0x00;
+ }
+ else {
+ /* Send a 16 bit space */
+ gap |= 0x8000;
+ debug(RPT_INFO, "picolcd: IR transmission gap: %04x", gap);
+ *p->resptr++ = (unsigned char)(gap & 0xff);
+ *p->resptr++ = (unsigned char)((gap >> 8) & 0xff);
+ }
+ }
}
+ else { /* Intervals measured in jiffies (1/16384 s). */
+ /*
+ * Prevent the overflow (2 secs = 32678 jiffies), but allow
+ * 2.99 seconds to reach the max
+ */
+ if (2 <= time_gap.tv_sec) {
+ /*
+ * microseconds to jiffies (same as (16384/1000000)
+ * but no possible int32 overflow)
+ */
+ gap = ((time_gap.tv_sec * 1000000 + time_gap.tv_usec) * 256) / 15625;
+ }
+ /* Saturate on 15 bit overflow */
+ if (gap >= 0x8000) {
+ gap = 0x7FFF;
+ }
+ /* Make it a space */
+ gap |= 0x8000;
- /* Saturate on 15 bit overflow */
- if (gap >= 0x8000) {
- gap = 0x7FFF;
+ debug(RPT_INFO, "picolcd: injecting space %04x between %04x and %04x",
+ gap, p->lastval, -w & 0xFFFF);
+ *p->resptr++ = (unsigned char)(gap & 0xff);
+ *p->resptr++ = (unsigned char)((gap >> 8) & 0xff);
}
- /* Make it a space */
- gap |= 0x8000;
-
- debug(RPT_INFO, "picolcd: injecting space %04x between %04x and %04x",
- gap, p->lastval, -w & 0xFFFF);
- *p->resptr++ = (unsigned char)(gap & 0xff);
- *p->resptr++ = (unsigned char)((gap >> 8) & 0xff);
}
/* Check if there is enough space left in buffer to store all new samples */
else if (cbdata >= (&p->result[sizeof(p->result)] - p->resptr)) {
/* This should never happen but just to be sure. */
- debug(RPT_INFO, "picolcd: buffer almost full send lirc data now");
+ report(RPT_WARNING, "picolcd: buffer almost full send lirc data now");
picolcd_lircsend(drvthis);
}
for (i = 0; i < cIntervals; i++) {
w = *data++;
w |= *data++ << 8;
- if (w & 0x8000) {
- /* IF w is negative THEN negate. E.g. 0xDCA1 (-9055) -> 9055. */
+ if (w & 0x8000) { /* Mark */
+ /* picoLCD uses negative for mark so negate. E.g. 0xDCA1 (-9055) -> 9055. */
w = 0x10000 - w;
- /* scale: orig is usec, new is jiffy. E.g. 9055usec = 148 jiffy. */
- w = (w * 16384 / 1000000) & 0xFFFF;
+ if (!p->lirc_time_us) {
+ /* scale: orig is usec, new is jiffy. E.g. 9055usec = 148 jiffy. */
+ w = (w * 16384 / 1000000) & 0xFFFF;
+ }
}
- else {
- /* Scale */
- w = w * 16384 / 1000000;
+ else { /* Space */
+ if (!p->lirc_time_us) {
+ /* Scale */
+ w = w * 16384 / 1000000;
+ }
if (w >= p->flush_threshold) {
report(RPT_INFO, "picolcd: detected sync space sending lirc data now");
picolcd_lircsend(drvthis);
@@ -1661,7 +1812,7 @@
p->lastmsg = now;
/*
* Look for a short buffer (a full buffer has 10 samples) with a
- * terminal PULSE
+ * terminal mark
*/
if ((cIntervals < 10) && ((w & 0x8000) == 0)) {
debug(RPT_INFO, "picolcd: IR data end detected sending lirc data now");
@@ -1943,6 +2094,45 @@
#ifdef HAVE_LIBUSB_1_0
/**
+ * Free the USB transfer data.
+ *
+ * \param drvthis Pointer to driver structure
+ */
+static void
+free_usb_transfers(Driver *drvthis) {
+ PrivateData *p = drvthis->private_data;
+ int i;
+
+ for (i = 0; i < USB_BUFFERS; i++)
+ {
+ if (p->input_transfer[i].transfer != NULL) {
+ if (p->input_transfer[i].status == LIBUSB_SUCCESS)
+ {
+ /* Need to cancel transfer before it is freed */
+ libusb_cancel_transfer(p->input_transfer[i].transfer);
+ while (p->input_transfer[i].status != LIBUSB_TRANSFER_CANCELLED) {
+ struct timeval timeout;
+ /*
+ * Wait for the cancellation to complete, the
+ * call-back will then have freed the
+ * transfer.
+ */
+ report(RPT_INFO, "%s: waiting for usb transfer %d to be cancelled", drvthis->name, i);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ libusb_handle_events_timeout(p->lib_ctx, &timeout);
+ }
+ }
+ else
+ {
+ libusb_free_transfer(p->input_transfer[i].transfer);
+ p->input_transfer[i].transfer = NULL;
+ }
+ }
+ }
+}
+
+/**
* Store key press and release events in a buffer ready for the get key function.
* If the buffer is full key codes are discarded.
*
@@ -1985,14 +2175,15 @@
"COMPLETED", "ERROR", "TIMED_OUT", "CANCELLED", "STALL",
"NO_DEVICE", "OVERFLOW"
};
- Driver *drvthis = (Driver *)transfer->user_data;
- PrivateData *p = drvthis->private_data;
+ UsbTransferData *p = (UsbTransferData *)transfer->user_data;
+ Driver *drvthis = p->drvthis;
+ PrivateData *p_data = drvthis->private_data;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
report(RPT_ERR, "%s: input transfer status: %s", drvthis->name, status[transfer->status]);
- p->libusb_status = transfer->status;
+ p->status = transfer->status;
libusb_free_transfer(transfer);
- p->input_transfer = NULL;
+ p->transfer = NULL;
return;
}
@@ -2003,17 +2194,18 @@
break;
case IN_REPORT_IR_DATA:
debug(RPT_INFO, "%s: USB input call-back IR length %i", drvthis->name, transfer->buffer[1]);
- if (p->IRenabled)
+ if (p_data->IRenabled)
ir_transcode(drvthis, &transfer->buffer[2], transfer->buffer[1]);
break;
default:
report(RPT_ERR, "%s: input transfer unexpected data %d", drvthis->name, transfer->buffer[0]);
+ break;
}
/* Re-transmit the input request transfer */
- p->libusb_status = libusb_submit_transfer(p->input_transfer);
- if (p->libusb_status != LIBUSB_SUCCESS)
- report(RPT_ERR, "%s: input transfer submit status %d", drvthis->name, p->libusb_status);
+ p->status = libusb_submit_transfer(transfer);
+ if (p->status != LIBUSB_SUCCESS)
+ report(RPT_ERR, "%s: input transfer submit status %d", drvthis->name, p->status);
}
#endif
Index: server/drivers/picolcd.h
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/picolcd.h,v
retrieving revision 1.14
diff -u -r1.14 picolcd.h
--- server/drivers/picolcd.h 10 Dec 2011 15:39:47 -0000 1.14
+++ server/drivers/picolcd.h 13 Sep 2013 19:14:00 -0000
@@ -36,7 +36,8 @@
#define PICOLCD_MAX_DATA_LEN 24
#define DEFAULT_LIRCPORT 8765
-#define DEFAULT_FLUSH_THRESHOLD_JIFFY 100 /* 6.1 millisec */
+#define DEFAULT_LIRC_TIME_us 0 /* false */
+#define DEFAULT_FLUSH_THRESHOLD 8000 /* microseconds */
#define DEFAULT_CONTRAST 1000 /* Full */
#define DEFAULT_BRIGHTNESS 1000 /* Full */
#define DEFAULT_OFFBRIGHTNESS 0 /* Off */
--------------080202020907090900050006
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
LCDproc mailing list
[email protected]
http://lists.omnipotent.net/mailman/listinfo/lcdproc
--------------080202020907090900050006--