Browse Source

easyvdr-lirc - uploaded2-3-base-stable-PPA

master
mango 1 year ago
parent
commit
ea4a1669fc
16 changed files with 3952 additions and 182 deletions
  1. +1
    -0
      e/easyvdr-lirc/.pc/.quilt_patches
  2. +1
    -0
      e/easyvdr-lirc/.pc/.quilt_series
  3. +1
    -0
      e/easyvdr-lirc/.pc/.version
  4. +1
    -0
      e/easyvdr-lirc/.pc/applied-patches
  5. +0
    -0
      e/easyvdr-lirc/.pc/lirc-0.9.0.patch/.timestamp
  6. +1821
    -0
      e/easyvdr-lirc/.pc/lirc-0.9.0.patch/configure.ac
  7. +381
    -0
      e/easyvdr-lirc/.pc/lirc-0.9.0.patch/daemons/hw_mplay.c
  8. +38
    -0
      e/easyvdr-lirc/.pc/lirc-0.9.0.patch/daemons/hw_mplay.h
  9. +7
    -1
      e/easyvdr-lirc/configure.ac
  10. +645
    -178
      e/easyvdr-lirc/daemons/hw_mplay.c
  11. +4
    -3
      e/easyvdr-lirc/daemons/hw_mplay.h
  12. +7
    -0
      e/easyvdr-lirc/debian/changelog
  13. +1040
    -0
      e/easyvdr-lirc/debian/patches/lirc-0.9.0.patch
  14. +1
    -0
      e/easyvdr-lirc/debian/patches/series
  15. +1
    -0
      e/easyvdr-lirc/debian/source/format
  16. +3
    -0
      e/easyvdr-lirc/debian/source/options

+ 1
- 0
e/easyvdr-lirc/.pc/.quilt_patches View File

@@ -0,0 +1 @@
debian/patches

+ 1
- 0
e/easyvdr-lirc/.pc/.quilt_series View File

@@ -0,0 +1 @@
series

+ 1
- 0
e/easyvdr-lirc/.pc/.version View File

@@ -0,0 +1 @@
2

+ 1
- 0
e/easyvdr-lirc/.pc/applied-patches View File

@@ -0,0 +1 @@
lirc-0.9.0.patch

+ 0
- 0
e/easyvdr-lirc/.pc/lirc-0.9.0.patch/.timestamp View File


+ 1821
- 0
e/easyvdr-lirc/.pc/lirc-0.9.0.patch/configure.ac
File diff suppressed because it is too large
View File


+ 381
- 0
e/easyvdr-lirc/.pc/lirc-0.9.0.patch/daemons/hw_mplay.c View File

@@ -0,0 +1,381 @@
/****************************************************************************
** hw_mplay.c **************************************************************
****************************************************************************
*
* LIRC driver for Vlsys mplay usb ftdi serial port remote control.
*
* Driver inspire from hw_accent et hw_alsa_usb.
*
* The vlsys mplay is a remote control with an Ir receiver connected to the
* usb bus via a ftdi driver. The device communicate with the host at 38400
* 8N1.
*
* For each keypress on the remote controle, one code byte is transmitted
* follow by regular fixe code byte for repetition if the key is held-down.
* For example, if you press key 1, the remote first send 0x4d (key code)
* and next regulary send 0x7e (repetetion code) as you held-down the key.
* For key 2 you get 0x4e 0x7e 0x7e ...
*
* Copyright (c) 2007 Benoit Laurent <ben905@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/* Functions available for logging (see tools/lircrcd.c).
*
* NOTE: if compiled without the DEBUG option and with SYSLOG,
* you cannot control the amount of debug info sent to syslog,
* even the LOG_DEBUG messages will be logged.
*
* void logprintf(int priority, const char *format, ...)
* Calls the syslog(3) function.
*
* void logperror(int priority, const char *s)
* Uses the syslog(3) to print a message followed by the error message
* strerror (%m) associated to the present errno.
*
* void LOGPRINTF(int priority, const char *format, ...)
* Calls logprintf(), but only if compiled with DEBUG option.
*
* void LOGPERROR(int priority, const char *s)
* Calls logperror(), but only if compiled with DEBUG option.
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#ifndef LIRC_IRTTY
#define LIRC_IRTTY "/dev/ttyUSB0"
#endif

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <termios.h>

#include "lircd.h"
#include "hardware.h"
#include "serial.h"

#include "hw_mplay.h"

/* The mplay code length in bit */
#define MPLAY_CODE_LENGTH 8

/* Code value send by the mplay to indicate a repeatition of the last code */
#define MPLAY_REPEAT_CODE 0x7e

/* Mplay serial baud rate */
#define MPLAY_BAUD_RATE 38400

/* Max time in micro seconde between the reception of repetition code. After
this time, we ignore the key repeat */
#define MAX_TIME_BETWEEN_TWO_REPETITION_CODE 500000

/**************************************************************************
* Definition of local struct that permit to save data from call to call
* of the driver.
**************************************************************************/
static struct {
/* the last receive code */
ir_code rc_code;
/* Int wich indicate that the last reception was a repetition */
int repeat_flag;
/* Date of the last reception */
struct timeval last_reception_time;
/* Flag wich indicate a timeout between the reception of repetition
Some time the receiver lost a key code and only recieved
the associated repetition code. Then the driver interpret
this repetition as a repetition of the last receive key code
and not the lost one (ex: you press Volume+ after Volume-
and the sound continu to go down). To avoid this problem
we set a max time between two repetition. */
int timeout_repetition_flag;
} mplay_local_data = {
0, 0, {
0, 0}, 0};

/**************************************************************************
* Definition of the standard internal hardware interface
* use by lirc for the mplay device
**************************************************************************/
struct hardware hw_mplay = {
LIRC_IRTTY, /* default device */
-1, /* fd */
LIRC_CAN_REC_LIRCCODE, /* features */
0, /* send_mode */
LIRC_MODE_LIRCCODE, /* rec_mode */
MPLAY_CODE_LENGTH, /* code_length */
mplay_init, /* init_func */
mplay_deinit, /* deinit_func */
NULL, /* send_func */
mplay_rec, /* rec_func */
mplay_decode, /* decode_func */
NULL, /* ioctl_func */
NULL, /* readdata */
"mplay"
};

/**************************************************************************
* Definition of the standard internal hardware interface
* use by lirc for the mplay v2 (Monueal Moncaso) devices
**************************************************************************/
struct hardware hw_mplay2 = {
LIRC_IRTTY, /* default device */
-1, /* fd */
LIRC_CAN_REC_LIRCCODE, /* features */
0, /* send_mode */
LIRC_MODE_LIRCCODE, /* rec_mode */
MPLAY_CODE_LENGTH, /* code_length */
mplay2_init, /* init_func */
mplay_deinit, /* deinit_func */
NULL, /* send_func */
mplay_rec, /* rec_func */
mplay_decode, /* decode_func */
NULL, /* ioctl_func */
NULL, /* readdata */
"mplay2"
};

/**************************************************************************
* Lock and initialize the serial port.
* This function is called by the LIRC daemon when the first client
* registers itself.
* Return 1 on success, 0 on error.
**************************************************************************/
int mplay_init(void)
{
int result = 1;
LOGPRINTF(1, "Entering mplay_init()");
/* Creation of a lock file for the port */
if (!tty_create_lock(hw.device)) {
logprintf(LOG_ERR, "Could not create the lock file");
LOGPRINTF(1, "Could not create the lock file");
result = 0;
}
/* Try to open serial port */
else if ((hw.fd = open(hw.device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
logprintf(LOG_ERR, "Could not open the serial port");
LOGPRINTF(1, "Could not open the serial port");
mplay_deinit();
result = 0;
}
/* Serial port configuration */
else if (!tty_reset(hw.fd) || !tty_setbaud(hw.fd, MPLAY_BAUD_RATE)) {
logprintf(LOG_ERR, "could not configure the serial port for '%s'", hw.device);
LOGPRINTF(1, "could not configure the serial port for '%s'", hw.device);
mplay_deinit();
}
return result;
}

int mplay2_init(void)
{
struct termios portset;
signed int len;
char buf = 0x96;
char psResponse[11];

LOGPRINTF(1, "Entering mplay_init()");
/* Creation of a lock file for the port */
if (!tty_create_lock(hw.device)) {
logprintf(LOG_ERR, "Could not create the lock file");
LOGPRINTF(1, "Could not create the lock file");
return 0;
}

LOGPRINTF(0, "open serial port");
/* Try to open serial port (Monueal Moncaso 312 device doesn't like O_NONBLOCK */
if ((hw.fd = open(hw.device, O_RDWR | O_NOCTTY)) < 0) {
logprintf(LOG_ERR, "Could not open the serial port");
LOGPRINTF(1, "Could not open the serial port");
tty_delete_lock();
return 0;
}

/* Get serial device parameters */
if (tcgetattr(hw.fd, &portset) < 0) {
logprintf(LOG_ERR, "Could not get serial port attributes");
LOGPRINTF(1, "Could not get serial port attributes");
mplay_deinit();
return 0;
}

/* use own termios struct instead of using tty_reset , Moncaso doesn't like TCSAFLUSH */
portset.c_cflag &= ~PARENB;
portset.c_cflag &= ~CSTOPB;
portset.c_cflag &= ~CSIZE;
portset.c_cflag = B57600 | CS8;
portset.c_cflag |= (CLOCAL | CREAD);
portset.c_iflag |= (IXON | IXOFF | IXANY);
portset.c_oflag &= ~OPOST;
portset.c_lflag &= ~(ICANON | ECHOE | ECHO | ISIG);
portset.c_cc[VSTART] = 0x11;
portset.c_cc[VSTOP] = 0x13;
portset.c_cc[VEOF] = 0x20;
portset.c_cc[VMIN] = 1;
portset.c_cc[VTIME] = 3;

if (tcsetattr(hw.fd, TCSANOW, &portset) < 0) {
logprintf(LOG_ERR, "Error setting TCSANOW mode of serial device");
LOGPRINTF(1, "Error setting TCSANOW mode of serial device");
mplay_deinit();
return 0;
}

len = write(hw.fd, &buf, 1);
if (len < 0) {
LOGPRINTF(LOG_ERR, "couldn't write to device");
mplay_deinit();
return 0;
}

len = read(hw.fd, &psResponse, 11);
if (len < 0) {
LOGPRINTF(1, "No data recieved during reading");
mplay_deinit();
return 0;
} else
LOGPRINTF(1, "read chars: %s", psResponse);

if (tcgetattr(hw.fd, &portset) < 0) {
logprintf(LOG_ERR, "Could not get serial port attributes");
LOGPRINTF(1, "Could not get serial port attributes");
mplay_deinit();
return 0;
}

portset.c_cflag &= ~PARENB;
portset.c_cflag &= ~CSTOPB;
portset.c_cflag &= ~CSIZE;
portset.c_cflag = B57600 | CS8;
portset.c_cflag |= (CLOCAL | CREAD);
portset.c_iflag |= (IXON | IXOFF | IXANY);
portset.c_oflag &= ~OPOST;
portset.c_lflag &= ~(ICANON | ECHOE | ECHO | ISIG);
portset.c_cc[VSTART] = 0x11;
portset.c_cc[VSTOP] = 0x13;
portset.c_cc[VEOF] = 0x1C;
portset.c_cc[VMIN] = 1;
portset.c_cc[VTIME] = 3;

if (tcsetattr(hw.fd, TCSANOW, &portset) < 0) {
logprintf(LOG_ERR, "Error setting TCSANOW mode of serial device");
LOGPRINTF(1, "Error setting TCSANOW mode of serial device");
mplay_deinit();
return 0;
}

return 1;
}

/**************************************************************************
* Close and release the serial line.
**************************************************************************/
int mplay_deinit(void)
{
LOGPRINTF(1, "Entering mplay_deinit()");
close(hw.fd);
tty_delete_lock();
hw.fd = -1;
return (1);
}

/**************************************************************************
* Receive a code (1 byte) from the remote.
* This function is called by the LIRC daemon when I/O is pending
* from a registered client, e.g. irw.
*
* return NULL if nothing have been received or a lirc code
**************************************************************************/
char *mplay_rec(struct ir_remote *remotes)
{
unsigned char rc_code;
signed int len;
struct timeval current_time;
LOGPRINTF(1, "Entering mplay_rec()");
len = read(hw.fd, &rc_code, 1);
gettimeofday(&current_time, NULL);
if (len != 1) {
/* Something go wrong during the read, we close the device
for prevent endless looping when the device
is disconnected */
LOGPRINTF(1, "Reading error in mplay_rec()");
mplay_deinit();
return NULL;
} else {
/* We have received a code */
if (rc_code == MPLAY_REPEAT_CODE) {
if (mplay_local_data.timeout_repetition_flag == 1) {
/* We ignore the repetition */
return NULL;
} else {
if (time_elapsed(&mplay_local_data.last_reception_time, &current_time) <=
MAX_TIME_BETWEEN_TWO_REPETITION_CODE) {
/* This reception is a repeat */
mplay_local_data.repeat_flag = 1;
/* We save the reception time */
mplay_local_data.last_reception_time = current_time;
} else {
/* To much time between repetition,
the receiver have probably miss
a valide key code. We ignore the
repetition */
mplay_local_data.timeout_repetition_flag = 1;
mplay_local_data.repeat_flag = 0;
return NULL;
}
}
} else {
/* This is a new code */
mplay_local_data.rc_code = rc_code;
mplay_local_data.repeat_flag = 0;
mplay_local_data.timeout_repetition_flag = 0;
mplay_local_data.last_reception_time = current_time;
}
LOGPRINTF(1, "code: %u", (unsigned int)mplay_local_data.rc_code);
LOGPRINTF(1, "repeat_flag: %d", mplay_local_data.repeat_flag);
return decode_all(remotes);
}
}

/**************************************************************************
* This function is called by the LIRC daemon during the transform of a
* received code into an lirc event.
*
* It gets the global variable code (remote keypress code).
*
* It returns:
* prep Code prefix (zero for this LIRC driver)
* codep Code of keypress
* postp Trailing code (zero for this LIRC dirver)
* repeat_flagp True if the keypress is a repeated keypress
* min_remaining_gapp Min extimated time gap remaining before next code
* max_remaining_gapp Max extimated time gap remaining before next code
**************************************************************************/
int mplay_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)
{
LOGPRINTF(1, "Entering mplay_decode(), code = %u\n", (unsigned int)mplay_local_data.rc_code);

if (!map_code(remote, prep, codep, postp, 0, 0, MPLAY_CODE_LENGTH, mplay_local_data.rc_code, 0, 0)) {
return (0);
}
*repeat_flagp = mplay_local_data.repeat_flag;
*min_remaining_gapp = 0;
*max_remaining_gapp = 0;
return 1;
}

+ 38
- 0
e/easyvdr-lirc/.pc/lirc-0.9.0.patch/daemons/hw_mplay.h View File

@@ -0,0 +1,38 @@
/****************************************************************************
** hw_mplay.h **************************************************************
****************************************************************************
*
* LIRC driver for Vlsys mplay usb ftdi serial port remote control.
*
* Author: Benoit Laurent <ben905@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/

#ifndef HW_MPLAY_H
#define HW_MPLAY_H

#include "drivers/lirc.h"

extern int mplay_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);

extern int mplay_init(void);
extern int mplay2_init(void);
extern int mplay_deinit(void);
extern char *mplay_rec(struct ir_remote *remotes);

#endif

+ 7
- 1
e/easyvdr-lirc/configure.ac View File

@@ -467,6 +467,8 @@ atwf83_lib=""
awlibusb_lib=""
dfclibusb_lib=""
srm7500libusb_lib=""
mplay_lib=""
mplay2_lib=""
hw_module="hw_default.o receive.o transmit.o"
HW_DEFAULT="hw_default"
kernel_module=""
@@ -638,9 +640,11 @@ if test "$driver" = "userspace" -o "$driver" = "all"; then
;;
mplay)
hw_module="${hw_module} hw_mplay.o serial.o"
mplay_lib="-lpthread -lrt"
;;
mplay2)
hw_module="${hw_module} hw_mplay.o serial.o"
mplay2_lib="-lpthread -lrt"
;;
pcmak*)
hw_module="${hw_module} hw_pcmak.o serial.o"
@@ -1189,6 +1193,7 @@ if test "$driver" = "mplay"; then
hw_module="hw_mplay.o serial.o"
HW_DEFAULT="hw_mplay"
lircd_conf="vlsystem/lircd.conf.mplay"
mplay_lib="-lpthread -lrt"
fi

if test "$driver" = "mplay2"; then
@@ -1196,6 +1201,7 @@ if test "$driver" = "mplay2"; then
hw_module="hw_mplay.o serial.o"
HW_DEFAULT="hw_mplay2"
lircd_conf="vlsystem/lircd.conf.mplay"
mplay2_lib="-lpthread -lrt"
fi

if test "$driver" = "nslu2"; then
@@ -1669,7 +1675,7 @@ if ! echo ${hw_module}|grep " receive.o" >/dev/null; then
receive="receive.o"
fi

hw_module_libs="${alsa_lib} ${atilibusb_lib} ${awlibusb_lib} ${caraca_lib} ${commandir_lib} ${dfclibusb_lib} ${ftdi_lib} ${iguanaIR_lib} ${irman_lib} ${portaudio_lib} ${srm7500libusb_lib} ${atwf83_lib}"
hw_module_libs="${alsa_lib} ${atilibusb_lib} ${awlibusb_lib} ${caraca_lib} ${commandir_lib} ${dfclibusb_lib} ${ftdi_lib} ${iguanaIR_lib} ${irman_lib} ${portaudio_lib} ${srm7500libusb_lib} ${atwf83_lib} ${mplay_lib} ${mplay2_lib}"

dnl tell the Makefiles what we decided
AC_SUBST(daemon)


+ 645
- 178
e/easyvdr-lirc/daemons/hw_mplay.c View File

@@ -12,11 +12,14 @@
*
* For each keypress on the remote controle, one code byte is transmitted
* follow by regular fixe code byte for repetition if the key is held-down.
* For example, if you press key 1, the remote first send 0x4d (key code)
* and next regulary send 0x7e (repetetion code) as you held-down the key.
* For key 2 you get 0x4e 0x7e 0x7e ...
* For example, if you press key 1, the remote first send 0x4d (key code) and
* next regulary send 0x7e (repetetion code) as you held-down the key. For
* key 2 you get 0x4e 0x7e 0x7e ...
*
* Copyright (c) 2007 Benoit Laurent <ben905@free.fr>
* Copyright (c) 2011,2012
* Wolfgang Hauck <wolfgang.hauck@gmx.de>
* (Added support for wheel/knob.)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,9 +38,9 @@

/* Functions available for logging (see tools/lircrcd.c).
*
* NOTE: if compiled without the DEBUG option and with SYSLOG,
* you cannot control the amount of debug info sent to syslog,
* even the LOG_DEBUG messages will be logged.
* NOTE: if compiled without the DEBUG option and with SYSLOG, you cannot
* control the amount of debug info sent to syslog, even the LOG_DEBUG
* messages will be logged.
*
* void logprintf(int priority, const char *format, ...)
* Calls the syslog(3) function.
@@ -61,10 +64,16 @@
#define LIRC_IRTTY "/dev/ttyUSB0"
#endif

#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/timerfd.h>
#include <sys/ioctl.h>

#include "lircd.h"
#include "hardware.h"
@@ -72,18 +81,82 @@

#include "hw_mplay.h"


/* The mplay code length in bit */
#define MPLAY_CODE_LENGTH 8

/* Wheel angle period */
#define MPLAY_ANGLE_PERIOD 4

/* There was no latest action */
#define MPLAY_ACTION_NONE -1
/* Latest relevant action was wheel turn */
#define MPLAY_ACTION_WHEEL 0
/* Latest relevant action was button press */
#define MPLAY_ACTION_BUTTON 1

/* IR termination code sent by listener thread in error cases */
#define MPLAY_CODE_ERROR 0xFF
/* Code if no action took place */
#define MPLAY_CODE_NOP 0x00
/* Code sent to LIRC framework for counter-clockwise rotation */
#define MPLAY_CODE_TURN_LEFT 0x80
/* Code sent to LIRC framework for clockwise rotation */
#define MPLAY_CODE_TURN_RIGHT 0x81
/* Code sent to LIRC framework for knob press */
#define MPLAY_CODE_KNOB 0x82
/* Code value send by the mplay to indicate a repeatition of the last code */
#define MPLAY_REPEAT_CODE 0x7e
#define MPLAY_CODE_REPEAT 0x7E

/* Period of listener thread in nanoseconds in idle phase (40ms) */
#define MPLAY_LISTENER_PERIOD_IDLE 40000000
/* Period of listener thread in nanoseconds when wheel is busy (2.5ms) */
#define MPLAY_LISTENER_PERIOD_BUSY 2500000
/* Counter for poll actions during busy phase until going idle */
#define MPLAY_LISTENER_COUNTER_WAIT_WHEEL 64
/* Counter for poll actions during busy phase until going idle */
#define MPLAY_LISTENER_COUNTER_WAIT_BUTTON 8
/* Bit position for rotation sensor A */
#define MPLAY_ROTATION_SENSOR_POS_A 8
/* Mask for rotation sensor A */
#define MPLAY_ROTATION_SENSOR_MASK_A (1 << MPLAY_ROTATION_SENSOR_POS_A)
/* Bit position for rotation sensor B */
#define MPLAY_ROTATION_SENSOR_POS_B 5
/* Mask for rotation sensor B */
#define MPLAY_ROTATION_SENSOR_MASK_B (1 << MPLAY_ROTATION_SENSOR_POS_B)
/* Mask for rotation sensor */
#define MPLAY_ROTATION_SENSOR_MASK (MPLAY_ROTATION_SENSOR_MASK_A | MPLAY_ROTATION_SENSOR_MASK_B)

/* Mplay serial baud rate */
#define MPLAY_BAUD_RATE 38400

/* Max time in micro seconde between the reception of repetition code. After
this time, we ignore the key repeat */
#define MAX_TIME_BETWEEN_TWO_REPETITION_CODE 500000
/* Mplay2 serial baud rate */
#define MPLAY2_BAUD_RATE 57600

/* Mplay2 initialisation character sent to device */
#define MPLAY2_INIT_CHAR 0x96

/* Mplay2 initialisation length of response to initialisation character */
#define MPLAY2_INIT_RESPONSE_LENGTH 11

/* Min time in micro seconds between button presses (125ms). Faster button
* presses are ignored because they are likely to be generated by bouncing
* effects. Here, only the knob is subject to bouncing effects. */
#define MIN_TIME_BETWEEN_PRESSES 125000
/* If two knob presses occur within 400ms, this is interpreted as
* repetition. */
#define MAX_TIME_KNOB_PRESS_IS_REPETITION 400000

/* Max time in microseconds between the reception of repetition code (400ms).
* After this time, we ignore key repetitions. */
#define MAX_TIME_BETWEEN_TWO_REPETITION_CODE 400000

/* Convert serial line status to gray code */
#define MPLAY_STATUS_TO_GRAY(s) \
((((s) & MPLAY_ROTATION_SENSOR_MASK_A) >> (MPLAY_ROTATION_SENSOR_POS_A - 1)) | \
(((s) & MPLAY_ROTATION_SENSOR_MASK_B) >> (MPLAY_ROTATION_SENSOR_POS_B)))
/* Convert gray code to binary */
#define MPLAY_GRAY_TO_BIN(g) ((g) ^ ((g) >> 1))

/**************************************************************************
* Definition of local struct that permit to save data from call to call
@@ -96,17 +169,41 @@ static struct {
int repeat_flag;
/* Date of the last reception */
struct timeval last_reception_time;
/* Flag wich indicate a timeout between the reception of repetition
Some time the receiver lost a key code and only recieved
the associated repetition code. Then the driver interpret
this repetition as a repetition of the last receive key code
and not the lost one (ex: you press Volume+ after Volume-
and the sound continu to go down). To avoid this problem
we set a max time between two repetition. */
/* Flag wich indicates a timeout between the reception of repetitions, or detects
* spurious knob presses following shortly after knob has actually been pressed.
*
* Sometimes the receiver loses a key code and only receives the associated repetition
* code. Then the driver interprets this repetition as a repetition of the last received
* key code and not of the lost one (e.g. you press volume+ after volume- and the sound
* continues to go down). To avoid this problem we set a max time between two
* repetition.
*
* As another phenomen, the knob produces too many codes following the first knob press
* to shortly. So, there has to be a minimum distance between button presses. */
int timeout_repetition_flag;
} mplay_local_data = {
0, 0, {
0, 0}, 0};
/* MPLAY_ACTION_WHEEL if wheel was turned latest,
* MPLAY_ACTION_BUTTON if remote control button was pressed latest,
* MPLAY_ACTION_NONE otherwise. */
int latest_action;
/* Latest pressed button other than knob (for handling of repeat sequences) */
unsigned char latest_button;
/* File descriptor of serial port where IR is attached to */
int fd;
/* File descriptors of pipe into LIRC framework. */
int pipefd[2];
/* ID of threat that listens on the serial port. */
pthread_t tid;
} mplayfamily_local_data = {
.rc_code = 0,
.repeat_flag = 0,
.last_reception_time = {0, 0},
.timeout_repetition_flag = 0,
.latest_action = MPLAY_ACTION_NONE,
.latest_button = MPLAY_CODE_ERROR,
.fd = -1,
.pipefd = {-1, -1},
.tid = -1
};

/**************************************************************************
* Definition of the standard internal hardware interface
@@ -119,11 +216,11 @@ struct hardware hw_mplay = {
0, /* send_mode */
LIRC_MODE_LIRCCODE, /* rec_mode */
MPLAY_CODE_LENGTH, /* code_length */
mplay_init, /* init_func */
mplay_deinit, /* deinit_func */
mplay_init, /* init_func */
mplayfamily_deinit, /* deinit_func */
NULL, /* send_func */
mplay_rec, /* rec_func */
mplay_decode, /* decode_func */
mplayfamily_rec, /* rec_func */
mplayfamily_decode, /* decode_func */
NULL, /* ioctl_func */
NULL, /* readdata */
"mplay"
@@ -131,7 +228,7 @@ struct hardware hw_mplay = {

/**************************************************************************
* Definition of the standard internal hardware interface
* use by lirc for the mplay v2 (Monueal Moncaso) devices
* use by lirc for the mplay v2 (Monueal MonCaso) devices
**************************************************************************/
struct hardware hw_mplay2 = {
LIRC_IRTTY, /* default device */
@@ -141,213 +238,582 @@ struct hardware hw_mplay2 = {
LIRC_MODE_LIRCCODE, /* rec_mode */
MPLAY_CODE_LENGTH, /* code_length */
mplay2_init, /* init_func */
mplay_deinit, /* deinit_func */
mplayfamily_deinit, /* deinit_func */
NULL, /* send_func */
mplay_rec, /* rec_func */
mplay_decode, /* decode_func */
mplayfamily_rec, /* rec_func */
mplayfamily_decode, /* decode_func */
NULL, /* ioctl_func */
NULL, /* readdata */
"mplay2"
};


/**************************************************************************
* Lock and initialize the serial port.
* This function is called by the LIRC daemon when the first client
* registers itself.
* Initialises mplay receiver.
* Return 1 on success, 0 on error.
**************************************************************************/
int mplay_init(void)
static int mplay_init_receiver(void)
{
int result = 1;
LOGPRINTF(1, "Entering mplay_init()");
/* Creation of a lock file for the port */
if (!tty_create_lock(hw.device)) {
logprintf(LOG_ERR, "Could not create the lock file");
LOGPRINTF(1, "Could not create the lock file");
result = 0;
}
/* Try to open serial port */
else if ((hw.fd = open(hw.device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
logprintf(LOG_ERR, "Could not open the serial port");
LOGPRINTF(1, "Could not open the serial port");
mplay_deinit();
result = 0;
return 1;
}

/**************************************************************************
* Sends initialisation character to MonCaso 312/320 IR device
* (helper function for mplay2_init).
* Return 1 on success, 0 on error.
**************************************************************************/
static int mplay2_send_init_char(void)
{
const char init = MPLAY2_INIT_CHAR;

if (write(mplayfamily_local_data.fd, &init, 1) < 0) {
return 0;
} else {
return 1;
}
/* Serial port configuration */
else if (!tty_reset(hw.fd) || !tty_setbaud(hw.fd, MPLAY_BAUD_RATE)) {
logprintf(LOG_ERR, "could not configure the serial port for '%s'", hw.device);
LOGPRINTF(1, "could not configure the serial port for '%s'", hw.device);
mplay_deinit();
}

/**************************************************************************
* Retrieves initialisation response from MonCaso 312/320 IR device
* (helper function for mplay2_init).
* MonCaso 320 returns ".M428.M428.".
* Return 1 on success, 0 on error.
**************************************************************************/
static int mplay2_retrieve_init_response(void)
{
int i;
char response[MPLAY2_INIT_RESPONSE_LENGTH + 1]; /* contains string terminating zero */

/* Reset response buffer */
memset(response, 0, sizeof(response));

/* Read-function blocks until characters arrive from serial device */
fcntl(mplayfamily_local_data.fd, F_SETFL, 0);
/* Get response to initialisation character */
for (i = 0; i < MPLAY2_INIT_RESPONSE_LENGTH; i++) {
/* Get next character (blocks until arrival in order to avoid polling) */
if (read(mplayfamily_local_data.fd, &response[i], 1) < 0) {
return 0;
}
}
return result;
/* Restore non-blocking behaviour */
fcntl(mplayfamily_local_data.fd, F_SETFL, FNDELAY);
LOGPRINTF(1, "Device initialisation response: %s", response);

return 1;
}

int mplay2_init(void)
/**************************************************************************
* Initialises MonCaso 312/320 IR receiver.
* Return 1 on success, 0 on error.
**************************************************************************/
static int mplay2_init_receiver(void)
{
struct termios portset;
signed int len;
char buf = 0x96;
char psResponse[11];
return mplay2_send_init_char() && mplay2_retrieve_init_response();
}

LOGPRINTF(1, "Entering mplay_init()");
/* Creation of a lock file for the port */
if (!tty_create_lock(hw.device)) {
logprintf(LOG_ERR, "Could not create the lock file");
LOGPRINTF(1, "Could not create the lock file");
/**************************************************************************
* Cleans up resources used by the listener thread.
**************************************************************************/
static void mplayfamily_listen_cleanup(void* arg)
{
close((int) arg);
}

/**************************************************************************
* Sets period for polling loop in listener thread.
* Returns 1 on success, 0 on error; errno is set.
**************************************************************************/
static int mplayfamily_set_listener_period(int fd, unsigned int period)
{
struct timespec now;
struct itimerspec p;
if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
return 0;
}

LOGPRINTF(0, "open serial port");
/* Try to open serial port (Monueal Moncaso 312 device doesn't like O_NONBLOCK */
if ((hw.fd = open(hw.device, O_RDWR | O_NOCTTY)) < 0) {
logprintf(LOG_ERR, "Could not open the serial port");
LOGPRINTF(1, "Could not open the serial port");
tty_delete_lock();
p.it_interval.tv_sec = 0;
p.it_interval.tv_nsec = period;
p.it_value.tv_sec = now.tv_sec;
p.it_value.tv_nsec = now.tv_nsec;
if (timerfd_settime (fd, TFD_TIMER_ABSTIME, &p, NULL) < 0) {
return 0;
}
return 1;
}

/* Get serial device parameters */
if (tcgetattr(hw.fd, &portset) < 0) {
logprintf(LOG_ERR, "Could not get serial port attributes");
LOGPRINTF(1, "Could not get serial port attributes");
mplay_deinit();
return 0;
/**************************************************************************
* Gets a wheel action.
* The function returns a virtual button press if the absolute angle has
* changed and is a multiple of 4. The absolute value is constructed from
* the sensor measure values by tracking the turn actions. If a wheel
* action has taken place, the function re-triggers the busy phase by
* setting the busy counter to a maximum and reducing the polling period.
*
* Parameters:
* File descriptor of periodic timer;
* counter (in/out), used to control idle/busy polling phases;
* angle measured by sensor(in/out), values 0, 1, 2, 3;
* absolute angle (in/out), tracks sensor measurement values;
* event angle (in/out), when turn took place.
*
* Returns:
* MPLAY_CODE_TURN_LEFT, MPLAY_CODE_TURN_RIGHT,
* MPLAY_CODE_NOP, MPLAY_CODE_ERROR.
**************************************************************************/
static unsigned char mplayfamily_get_wheel(
int fd, unsigned int *counter,
unsigned int *sensor, unsigned int *absolute, unsigned int *event)
{
unsigned char code = MPLAY_CODE_NOP;
unsigned int status; /* Status of wheel sensors */
unsigned int new; /* new angle */

/* Read status of angle sensor */
if (ioctl(mplayfamily_local_data.fd, TIOCMGET, &status) < 0) {
logperror(LOG_ERR, "mplay listener ioctl failed");
return MPLAY_CODE_ERROR;
}
/* Evaluate wheel status */
else {
new = MPLAY_GRAY_TO_BIN(MPLAY_STATUS_TO_GRAY(status));
/* Check if wheel has been turned */
if (new != *sensor) {
signed int diff;
unsigned int direction = (new - *sensor + MPLAY_ANGLE_PERIOD) % MPLAY_ANGLE_PERIOD;
LOGPRINTF(3, "mplay wheel reports angle %d", new);
if (direction > MPLAY_ANGLE_PERIOD / 2) {
(*absolute)--;
LOGPRINTF(3, "mplay wheel turned left");
} else if (direction < MPLAY_ANGLE_PERIOD / 2) {
(*absolute)++;
LOGPRINTF(3, "mplay wheel turned right");
} else {
*absolute += (*absolute - new) % MPLAY_ANGLE_PERIOD;
LOGPRINTF(3, "mplay wheel turn skipped");
}
diff = *absolute - *event;
LOGPRINTF(3, "mplay wheel absolute %u, diff %d", *absolute, diff);
if (diff % MPLAY_ANGLE_PERIOD == 0) {
if (diff > 0) {
LOGPRINTF(2, "mplay wheel clockwise");
*event = *absolute;
code = MPLAY_CODE_TURN_RIGHT;
} else if (diff < 0) {
LOGPRINTF(2, "mplay wheel counter clockwise");
*event = *absolute;
code = MPLAY_CODE_TURN_LEFT;
}
}
*sensor = new;
if (*counter == 0) {
/* Something has happened, so return to busy polling mode;
* which is only necessary if busy period has expired. */
if (!mplayfamily_set_listener_period(fd, MPLAY_LISTENER_PERIOD_BUSY)) {
logperror(LOG_ERR, "mplay listener could not set listener period");
}
LOGPRINTF(2, "mplay polls with busy rate, wheel has been turned");
}
/* Stay alert for a while, enter busy phase */
*counter = MPLAY_LISTENER_COUNTER_WAIT_WHEEL;
}
}

/* use own termios struct instead of using tty_reset , Moncaso doesn't like TCSAFLUSH */
portset.c_cflag &= ~PARENB;
portset.c_cflag &= ~CSTOPB;
portset.c_cflag &= ~CSIZE;
portset.c_cflag = B57600 | CS8;
portset.c_cflag |= (CLOCAL | CREAD);
portset.c_iflag |= (IXON | IXOFF | IXANY);
portset.c_oflag &= ~OPOST;
portset.c_lflag &= ~(ICANON | ECHOE | ECHO | ISIG);
portset.c_cc[VSTART] = 0x11;
portset.c_cc[VSTOP] = 0x13;
portset.c_cc[VEOF] = 0x20;
portset.c_cc[VMIN] = 1;
portset.c_cc[VTIME] = 3;

if (tcsetattr(hw.fd, TCSANOW, &portset) < 0) {
logprintf(LOG_ERR, "Error setting TCSANOW mode of serial device");
LOGPRINTF(1, "Error setting TCSANOW mode of serial device");
mplay_deinit();
return 0;
if (code != MPLAY_CODE_NOP) {
mplayfamily_local_data.latest_action = MPLAY_ACTION_WHEEL;
LOGPRINTF(3, "get wheel: latest action %u, latest button 0x%02x",
mplayfamily_local_data.latest_action, mplayfamily_local_data.latest_button);
}

len = write(hw.fd, &buf, 1);
if (len < 0) {
LOGPRINTF(LOG_ERR, "couldn't write to device");
mplay_deinit();
return 0;
return code;
}

/**************************************************************************
* Returns button presses as read from the serial line.
* The repeat code 0x7E is replaced by the button code, if it conflicts
* with wheel actions (repeat code would refer to wheel actions instead of
* button presses). If the knob has been pressed, the function re-triggers
* the busy phase in order to catch all spurious knob presses caused by
* bouncing effects
*
* Parameters:
* File descriptor of periodic timer;
* counter (in/out), used to control idle/busy polling phases;
**************************************************************************/
static unsigned char mplayfamily_get_button(int fd, unsigned int *counter)
{
unsigned char code = MPLAY_CODE_NOP;
signed int len; /* length of last received button message from serial port */

/* Read any pressed button from IR receiver */
if ((len = read(mplayfamily_local_data.fd, &code, sizeof(code))) == sizeof(code)) {
LOGPRINTF(2, "mplay listener received 0x%02x", code);
if (code == MPLAY_CODE_REPEAT) {
if (mplayfamily_local_data.latest_action == MPLAY_ACTION_WHEEL) {
LOGPRINTF(2, "mplay replaces code by 0x%02x", code);
code = mplayfamily_local_data.latest_button;
mplayfamily_local_data.latest_action = MPLAY_ACTION_BUTTON;
}
} else if (code != MPLAY_CODE_KNOB) {
mplayfamily_local_data.latest_button = code;
mplayfamily_local_data.latest_action = MPLAY_ACTION_BUTTON;
} else {
mplayfamily_local_data.latest_action = MPLAY_ACTION_WHEEL;
if (*counter < MPLAY_LISTENER_COUNTER_WAIT_BUTTON) {
if (*counter == 0) {
/* Knob has been pressed,
* so return to busy polling mode to catch spurious presses,
* but only if busy period has expired. */
if (!mplayfamily_set_listener_period(fd, MPLAY_LISTENER_PERIOD_BUSY)) {
logperror(LOG_ERR, "mplay listener could not set listener period");
}
LOGPRINTF(2, "mplay polls with busy rate, knob has been pressed");
}
/* Stay alert for a while, enter busy phase */
*counter = MPLAY_LISTENER_COUNTER_WAIT_BUTTON;
}
}
LOGPRINTF(3, "mplay get button: latest action %u, latest button 0x%02x",
mplayfamily_local_data.latest_action, mplayfamily_local_data.latest_button);
}
/* Handle read error */
else if (len < 0) {
/* Check if actually an error has occurred */
if (errno != EAGAIN && errno != EWOULDBLOCK) {
logperror(LOG_ERR, "mplay listener serial port read error");
code = MPLAY_CODE_ERROR;
}
}

len = read(hw.fd, &psResponse, 11);
if (len < 0) {
LOGPRINTF(1, "No data recieved during reading");
mplay_deinit();
return 0;
} else
LOGPRINTF(1, "read chars: %s", psResponse);
return code;
}

if (tcgetattr(hw.fd, &portset) < 0) {
logprintf(LOG_ERR, "Could not get serial port attributes");
LOGPRINTF(1, "Could not get serial port attributes");
mplay_deinit();
return 0;
/**************************************************************************
* Polls for button presses and wheel actions; they are piped into the LIRC
* framework where LIRC accesses the read end of a pipe. The function
* implements a polling loop and is called in a polling thread, which is
* cancellation safe.
*
* The function reads every MPLAY_LISTENER_PERIOD_IDLE milliseconds from
* the serial port and evaluates the serial port status lines. If the wheel
* is turned or the knob is pressed, the polling period is temporarily
* shortened to MPLAY_LISTENER_PERIOD_BUSY. Wheel turns are reported as
* remote control button presses delivering the values MPLAY_CODE_TURN_LEFT
* and MPLAY_CODE_TURN_RIGHT.
*
* Button presses from the remote control are read from the serial port.
* Note: Repeat sequences can be interrupted by wheel actions, but no
* button is discarded (one repeat code 0x7E is replaced by the original
* button code having started the repeat sequence).
*
* Wheel turns are reported as angles 0, 1, 3, 4 given in gray code, which
* is delivered in two status lines of the serial port (see masks
* MPLAY_ROTATION_SENSOR_MASK_A and MPLAY_ROTATION_SENSOR_MASK_B).
*
* The wheel has a rasterisation, and if the the wheel snaps in at angles 0
* a button press is simulated (provided a minimal angle distance is
* given). The rasterisation has the additional advantage that it prevents
* a jumping between left/right turns (caused by measurement errors and
* mechanical imprecisions) when turning in only one direction.
**************************************************************************/
static void *mplayfamily_listen(void* arg)
{
unsigned int status; /* status of wheel sensors */
unsigned int sensor; /* current angle position 0, 1, 2 or 3 measured by sensor */
unsigned int absolute; /* absolute angle position */
unsigned int turned; /* angle where a wheel button press was generated */
int fd; /* file descriptor polling timer */
uint64_t expired;
unsigned char code_wheel, code_button; /* button presses */
unsigned int counter = 1; /* controls duration of idle and busy polling phase */
LOGPRINTF(1, "Entering mplayfamily_listen()");

/* Read status of rotation sensor for the first time */
if (ioctl(mplayfamily_local_data.fd, TIOCMGET, &status) < 0) {
LOGPERROR(LOG_ERR, "mplay listener ioctl failed");
}
sensor = MPLAY_GRAY_TO_BIN(MPLAY_STATUS_TO_GRAY(status));
absolute = sensor;
turned = absolute;
LOGPRINTF(3, "mplay sensor %u", sensor);

/* Create periodic timer for polling loop */
if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
logperror(LOG_ERR, "mplay listener could not create timer");
return NULL;
}
pthread_cleanup_push(mplayfamily_listen_cleanup, (void*) fd);

portset.c_cflag &= ~PARENB;
portset.c_cflag &= ~CSTOPB;
portset.c_cflag &= ~CSIZE;
portset.c_cflag = B57600 | CS8;
portset.c_cflag |= (CLOCAL | CREAD);
portset.c_iflag |= (IXON | IXOFF | IXANY);
portset.c_oflag &= ~OPOST;
portset.c_lflag &= ~(ICANON | ECHOE | ECHO | ISIG);
portset.c_cc[VSTART] = 0x11;
portset.c_cc[VSTOP] = 0x13;
portset.c_cc[VEOF] = 0x1C;
portset.c_cc[VMIN] = 1;
portset.c_cc[VTIME] = 3;

if (tcsetattr(hw.fd, TCSANOW, &portset) < 0) {
logprintf(LOG_ERR, "Error setting TCSANOW mode of serial device");
LOGPRINTF(1, "Error setting TCSANOW mode of serial device");
mplay_deinit();
/* Poll for button presses and wheel actions */
while (1) {
/* If busy phase expires return to idle period */
if (counter > 0) {
counter--;
if (counter == 0) {
if (!mplayfamily_set_listener_period(fd, MPLAY_LISTENER_PERIOD_IDLE)) {
logperror(LOG_ERR, "mplay listener could not set listener period");
}
LOGPRINTF(2, "mplay polls with idle rate");
}
}
/* Wait for next event of periodic polling timer */
if (read(fd, &expired, sizeof(uint64_t)) != sizeof(uint64_t)) {
logperror(LOG_ERR, "mplay listener timer failed");
goto poll_exit;
}
/* Evaluate wheel status */
if ((code_wheel = mplayfamily_get_wheel(fd, &counter, &sensor, &absolute, &turned))
!= MPLAY_CODE_NOP) {
/* Pass wheel event to LIRC framework via pipe */
if (write(mplayfamily_local_data.pipefd[1], &code_wheel, sizeof(code_wheel)) < 0) {
logperror(LOG_ERR, "mplay listener pipe write error");
goto poll_exit;
} else if(code_wheel == MPLAY_CODE_ERROR) {
goto poll_exit;
}
}
/* Process all pending button presses and pass them to the LIRC framework via pipe */
if ((code_button = mplayfamily_get_button(fd, &counter)) != MPLAY_CODE_NOP) {
/* Pass button event to LIRC framework via pipe */
if (write(mplayfamily_local_data.pipefd[1], &code_button, sizeof(code_button)) < 0) {
logperror(LOG_ERR, "mplay listener pipe write error");
} else if (code_button == MPLAY_CODE_ERROR) {
goto poll_exit;
}
}
}

poll_exit:

pthread_cleanup_pop(1);

LOGPRINTF(1, "Leaving mplayfamily_listen()");

return NULL;
}

/**************************************************************************
* Locks and initialises a receiver of the mplay family.
*
* Unless the driver specified has appended the option "nowheel" (example:
* --device="/dev/ttyUSB0,nowheel") the function installs a pipe from a
* polling listener thread into the LIRC framework. The listener thread
* watches the serial port, generates remote control button presses (with
* wheel actions) and pipes them into the LIRC framework.
*
* Otherwise the LIRC framework reads directly from the serial port (using
* select, thus blocking until actually a button press arrives).
*
* The first alternative using the listener thread consumes more CPU
* resources.
*
* Parameters: Function to intialise receiver, baud rate for serial port.
*
* Return 1 on success, 0 on error.
**************************************************************************/
static int mplayfamily_init(int (*init_receiver)(void), int baud)
{
char device[128];
char* separator;
int nowheel = 0;
int result = 1;
LOGPRINTF(1, "Entering mplayfamily_init()");

/* Extract device name and option */
LOGPRINTF(1, "Device string '%s'", hw.device);
strncpy(device, hw.device, sizeof(device));
device[sizeof(device) - 1] = 0;
/* A comma announces an option. */
separator = strchr(device, ',');
if (separator != NULL) {
LOGPRINTF(1, "Found option string '%s'", separator + 1);
*separator = 0;
nowheel = strcmp(separator + 1, "nowheel") == 0;
}
LOGPRINTF(1,
"Using device path '%s' (wheel disabled state is %d)",
device, nowheel);

/* Creation of pipe between this driver and LIRC framework */
if (!nowheel && pipe(mplayfamily_local_data.pipefd) == -1) {
logprintf(LOG_ERR, "Could not create pipe");
result = 0;
}
/* Creation of a lock file for serial port */
else if (!tty_create_lock(device)) {
logprintf(LOG_ERR, "Could not create lock file for '%s'", device);
result = 0;
}
/* Try to open serial port */
else if ((mplayfamily_local_data.fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
logprintf(LOG_ERR, "Could not open serial port '%s'", device);
result = 0;
}
/* Serial port configuration */
else if (!tty_reset(mplayfamily_local_data.fd) ||
!tty_setbaud(mplayfamily_local_data.fd, baud)) {
logprintf(LOG_ERR, "Could not configure serial port '%s'", device);
result = 0;
}
/* Initialise a receiver of the mplay family */
else if (!init_receiver()) {
logprintf(LOG_ERR, "Could not initialise device");
result = 0;
}
/* Install serial port listener */
else if (!nowheel && pthread_create(&mplayfamily_local_data.tid, NULL, mplayfamily_listen, NULL)) {
logprintf(LOG_ERR, "Could not create \"listener thread\"");
return 0;
}

return 1;
/* Clean up if an error has occured */
if (result == 0) {
logperror(LOG_ERR, "mplayfamily_init()");
mplayfamily_deinit();
}

/* Redirect reads from serial port to pipe if wheel should be supported*/
hw.fd = nowheel ? mplayfamily_local_data.fd : mplayfamily_local_data.pipefd[0];
return result;
}

/**************************************************************************
* Lock and initialize the serial port for a mplay receiver.
* This function is called by the LIRC daemon when the first client
* registers itself.
* Return 1 on success, 0 on error.
**************************************************************************/
int mplay_init(void)
{
LOGPRINTF(1, "Entering mplay_init()");
return mplayfamily_init(mplay_init_receiver, MPLAY_BAUD_RATE);
}

/**************************************************************************
* Locks and initialises the serial port, MonCaso 312/320 variant.
* This function is called by the LIRC daemon when the first client
* registers itself.
* Return 1 on success, 0 on error.
**************************************************************************/
int mplay2_init(void)
{
LOGPRINTF(1, "Entering mplay2_init()");
return mplayfamily_init(mplay2_init_receiver, MPLAY2_BAUD_RATE);
}

/**************************************************************************
* Close and release the serial line.
* Close serial line and pipe; and release the serial line.
**************************************************************************/
int mplay_deinit(void)
int mplayfamily_deinit(void)
{
LOGPRINTF(1, "Entering mplay_deinit()");
close(hw.fd);
tty_delete_lock();
hw.fd = -1;
return (1);
LOGPRINTF(1, "Entering mplayfamily_deinit()");
if (mplayfamily_local_data.tid != -1) {
if (pthread_cancel(mplayfamily_local_data.tid) < 0) {
logperror(LOG_ERR, "mplay could not cancel listener");
return 0;
}
pthread_join(mplayfamily_local_data.tid, NULL);
mplayfamily_local_data.tid = -1;
}
if (mplayfamily_local_data.pipefd[0] != -1) {
close (mplayfamily_local_data.pipefd[0]);
mplayfamily_local_data.pipefd[0] = -1;
}
if (mplayfamily_local_data.pipefd[1] != -1) {
close (mplayfamily_local_data.pipefd[1]);
mplayfamily_local_data.pipefd[1] = -1;
}
if (hw.fd != -1) {
close(hw.fd);
tty_delete_lock();
hw.fd = -1;
mplayfamily_local_data.fd = -1;
}
return 1;
}

/**************************************************************************
* Receive a code (1 byte) from the remote.
* This function is called by the LIRC daemon when I/O is pending
* from a registered client, e.g. irw.
* This function is called by the LIRC daemon when I/O is pending from a
* registered client, e.g. irw.
*
* return NULL if nothing have been received or a lirc code
* return NULL if nothing has been received, otherwise a lirc code
**************************************************************************/
char *mplay_rec(struct ir_remote *remotes)
char *mplayfamily_rec(struct ir_remote *remotes)
{
unsigned char rc_code;
signed int len;
struct timeval current_time;
LOGPRINTF(1, "Entering mplay_rec()");
LOGPRINTF(1, "Entering mplayfamily_rec()");
len = read(hw.fd, &rc_code, 1);
gettimeofday(&current_time, NULL);
if (len != 1) {
/* Something go wrong during the read, we close the device
for prevent endless looping when the device
is disconnected */
LOGPRINTF(1, "Reading error in mplay_rec()");
mplay_deinit();
/* Something go wrong during the read, we close the device for prevent endless
* looping when the device is disconnected */
LOGPRINTF(1, "Reading error in mplayfamily_rec()");
mplayfamily_deinit();
return NULL;
} else {
/* We have received a code */
if (rc_code == MPLAY_REPEAT_CODE) {
if (mplay_local_data.timeout_repetition_flag == 1) {
if (rc_code == MPLAY_CODE_REPEAT) {
/* This is a repetition code */
if (mplayfamily_local_data.timeout_repetition_flag == 1) {
LOGPRINTF(2, "Ignored received repetition code (timeout)");
/* We ignore the repetition */
return NULL;
} else if (time_elapsed(&mplayfamily_local_data.last_reception_time, &current_time) <=
MAX_TIME_BETWEEN_TWO_REPETITION_CODE) {
LOGPRINTF(2, "Accepted received repetition code");
/* This reception is a repeat */
mplayfamily_local_data.repeat_flag = 1;
/* We save the reception time */
mplayfamily_local_data.last_reception_time = current_time;
} else {
if (time_elapsed(&mplay_local_data.last_reception_time, &current_time) <=
MAX_TIME_BETWEEN_TWO_REPETITION_CODE) {
/* This reception is a repeat */
mplay_local_data.repeat_flag = 1;
/* We save the reception time */
mplay_local_data.last_reception_time = current_time;
} else {
/* To much time between repetition,
the receiver have probably miss
a valide key code. We ignore the
repetition */
mplay_local_data.timeout_repetition_flag = 1;
mplay_local_data.repeat_flag = 0;
return NULL;
}
LOGPRINTF(2, "Received invalid repetition code (timeout)");
/* Too much time between repetitions, the receiver has probably
* missed a valide key code. We ignore the repetition. */
mplayfamily_local_data.timeout_repetition_flag = 1;
mplayfamily_local_data.repeat_flag = 0;
return NULL;
}
} else {
/* This is a new code */
mplay_local_data.rc_code = rc_code;
mplay_local_data.repeat_flag = 0;
mplay_local_data.timeout_repetition_flag = 0;
mplay_local_data.last_reception_time = current_time;
if (rc_code != MPLAY_CODE_KNOB) {
/* Any button other than knob */
LOGPRINTF(2, "Accepted new received code");
mplayfamily_local_data.repeat_flag = 0;
mplayfamily_local_data.rc_code = rc_code;
mplayfamily_local_data.timeout_repetition_flag = 0;
mplayfamily_local_data.last_reception_time = current_time;
} else if (mplayfamily_local_data.rc_code != MPLAY_CODE_KNOB ||
time_elapsed(&mplayfamily_local_data.last_reception_time, &current_time) >
MIN_TIME_BETWEEN_PRESSES) {
/* Knob has been pressed after sufficiently large amount of time */
LOGPRINTF(2, "Accepted new knob code");
if (mplayfamily_local_data.rc_code == MPLAY_CODE_KNOB &&
time_elapsed(&mplayfamily_local_data.last_reception_time, &current_time) <
MAX_TIME_KNOB_PRESS_IS_REPETITION) {
LOGPRINTF(2, "Interpret knob code as repeated knob code");
mplayfamily_local_data.repeat_flag = 1;
} else {
mplayfamily_local_data.repeat_flag = 0;
}
mplayfamily_local_data.rc_code = rc_code;
mplayfamily_local_data.timeout_repetition_flag = 0;
mplayfamily_local_data.last_reception_time = current_time;
} else {
/* This seems to be a spurious knob press, so ignore it.
* It has been received too shortly
* after the last received knob press. */
LOGPRINTF(2, "Ignored spurious code 0x%02x at %li sec %li usec",
rc_code, current_time.tv_sec, current_time.tv_usec);
return NULL;
}
}
LOGPRINTF(1, "code: %u", (unsigned int)mplay_local_data.rc_code);
LOGPRINTF(1, "repeat_flag: %d", mplay_local_data.repeat_flag);
LOGPRINTF(1, "code: 0x%02x", (unsigned int)mplayfamily_local_data.rc_code);
LOGPRINTF(1, "repeat_flag: %d", mplayfamily_local_data.repeat_flag);
LOGPRINTF(2, "current_time: %li sec %li usec", current_time.tv_sec, current_time.tv_usec);
return decode_all(remotes);
}
}
@@ -366,15 +832,16 @@ char *mplay_rec(struct ir_remote *remotes)
* min_remaining_gapp Min extimated time gap remaining before next code
* max_remaining_gapp Max extimated time gap remaining before next code
**************************************************************************/
int mplay_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 mplayfamily_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)
{
LOGPRINTF(1, "Entering mplay_decode(), code = %u\n", (unsigned int)mplay_local_data.rc_code);
LOGPRINTF(1, "Entering mplayfamily_decode(), code=0x%02x\n", (unsigned int)mplayfamily_local_data.rc_code);

if (!map_code(remote, prep, codep, postp, 0, 0, MPLAY_CODE_LENGTH, mplay_local_data.rc_code, 0, 0)) {
if (!map_code(remote, prep, codep, postp, 0, 0, MPLAY_CODE_LENGTH, mplayfamily_local_data.rc_code, 0, 0)) {
return (0);
}
*repeat_flagp = mplay_local_data.repeat_flag;
*repeat_flagp = mplayfamily_local_data.repeat_flag;
*min_remaining_gapp = 0;
*max_remaining_gapp = 0;
return 1;


+ 4
- 3
e/easyvdr-lirc/daemons/hw_mplay.h View File

@@ -27,12 +27,13 @@

#include "drivers/lirc.h"

extern int mplay_decode(struct ir_remote *remote, ir_code * prep, ir_code * codep, ir_code * postp, int *repeat_flagp,
extern int mplayfamily_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);

extern int mplay_init(void);
extern int mplay2_init(void);
extern int mplay_deinit(void);
extern char *mplay_rec(struct ir_remote *remotes);
extern int mplayfamily_deinit(void);
extern char *mplayfamily_rec(struct ir_remote *remotes);

#endif

+ 7
- 0
e/easyvdr-lirc/debian/changelog View File

@@ -1,3 +1,10 @@
easyvdr-lirc (0.9.0-11easyVDR3~trusty) trusty; urgency=high

* added patch by user womiha
* https://www.easy-vdr.de/thread-17938-post-182206.html#pid182206

-- Wolfgang Mangold <vdr@gmx.de> Sat, 03 Nov 2018 00:24:34 +0100

easyvdr-lirc (0.9.0-11easyVDR2~trusty) trusty; urgency=high

* change start


+ 1040
- 0
e/easyvdr-lirc/debian/patches/lirc-0.9.0.patch
File diff suppressed because it is too large
View File


+ 1
- 0
e/easyvdr-lirc/debian/patches/series View File

@@ -0,0 +1 @@
lirc-0.9.0.patch

+ 1
- 0
e/easyvdr-lirc/debian/source/format View File

@@ -0,0 +1 @@
3.0 (native)

+ 3
- 0
e/easyvdr-lirc/debian/source/options View File

@@ -0,0 +1,3 @@
compression = "xz"
unapply-patches
abort-on-upstream-changes

Loading…
Cancel
Save