mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 15:02:58 +02:00
@@ -24,14 +24,6 @@ libstb_hal_la_LIBADD += \
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BOXTYPE_SPARK
|
|
||||||
#libstb_hal_test_LDADD += -lasound
|
|
||||||
SUBDIRS += libspark libeplayer3-sh4
|
|
||||||
libstb_hal_la_LIBADD += \
|
|
||||||
libspark/libspark.la \
|
|
||||||
libeplayer3-sh4/libeplayer3_sh4.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BOXTYPE_DUCKBOX
|
if BOXTYPE_DUCKBOX
|
||||||
#libstb_hal_test_LDADD += -lasound
|
#libstb_hal_test_LDADD += -lasound
|
||||||
SUBDIRS += libduckbox libeplayer3-sh4 libdvbci
|
SUBDIRS += libduckbox libeplayer3-sh4 libdvbci
|
||||||
|
28
acinclude.m4
28
acinclude.m4
@@ -75,9 +75,9 @@ AC_SYS_LARGEFILE
|
|||||||
|
|
||||||
AC_DEFUN([TUXBOX_BOXTYPE], [
|
AC_DEFUN([TUXBOX_BOXTYPE], [
|
||||||
AC_ARG_WITH(boxtype,
|
AC_ARG_WITH(boxtype,
|
||||||
AS_HELP_STRING([--with-boxtype], [valid values: generic, spark, duckbox, armbox, mipsbox]),
|
AS_HELP_STRING([--with-boxtype], [valid values: generic, duckbox, armbox, mipsbox]),
|
||||||
[case "${withval}" in
|
[case "${withval}" in
|
||||||
generic|spark|duckbox|armbox|mipsbox)
|
generic|duckbox|armbox|mipsbox)
|
||||||
BOXTYPE="$withval"
|
BOXTYPE="$withval"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -88,7 +88,6 @@ AC_ARG_WITH(boxtype,
|
|||||||
|
|
||||||
AC_ARG_WITH(boxmodel,
|
AC_ARG_WITH(boxmodel,
|
||||||
AS_HELP_STRING([--with-boxmodel], [valid for generic: generic, raspi])
|
AS_HELP_STRING([--with-boxmodel], [valid for generic: generic, raspi])
|
||||||
AS_HELP_STRING([], [valid for spark: spark, spark7162])
|
|
||||||
AS_HELP_STRING([], [valid for duckbox: ufs910, ufs912, ufs913, ufs922, atevio7500, fortis_hdbox, octagon1008, cuberevo, cuberevo_mini, cuberevo_mini2, cuberevo_250hd, cuberevo_2000hd, cuberevo_3000hd, ipbox9900, ipbox99, ipbox55, tf7700])
|
AS_HELP_STRING([], [valid for duckbox: ufs910, ufs912, ufs913, ufs922, atevio7500, fortis_hdbox, octagon1008, cuberevo, cuberevo_mini, cuberevo_mini2, cuberevo_250hd, cuberevo_2000hd, cuberevo_3000hd, ipbox9900, ipbox99, ipbox55, tf7700])
|
||||||
AS_HELP_STRING([], [valid for armbox: hd60, hd61, multiboxse, hd51, bre2ze4k, h7, osmini4k, osmio4k, osmio4kplus, vusolo4k, vuduo4k, vuduo4kse, vuultimo4k, vuuno4k, vuuno4kse, vuzero4k])
|
AS_HELP_STRING([], [valid for armbox: hd60, hd61, multiboxse, hd51, bre2ze4k, h7, osmini4k, osmio4k, osmio4kplus, vusolo4k, vuduo4k, vuduo4kse, vuultimo4k, vuuno4k, vuuno4kse, vuzero4k])
|
||||||
AS_HELP_STRING([], [valid for mipsbox: vuduo, vuduo2, gb800se, osnino, osninoplus, osninopro]),
|
AS_HELP_STRING([], [valid for mipsbox: vuduo, vuduo2, gb800se, osnino, osninoplus, osninopro]),
|
||||||
@@ -100,13 +99,6 @@ AS_HELP_STRING([], [valid for mipsbox: vuduo, vuduo2, gb800se, osnino, osninoplu
|
|||||||
AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE])
|
AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE])
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
spark|spark7162)
|
|
||||||
if test "$BOXTYPE" = "spark"; then
|
|
||||||
BOXMODEL="$withval"
|
|
||||||
else
|
|
||||||
AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE])
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
ufs910|ufs912|ufs913|ufs922|atevio7500|fortis_hdbox|octagon1008|cuberevo|cuberevo_mini|cuberevo_mini2|cuberevo_250hd|cuberevo_2000hd|cuberevo_3000hd|ipbox9900|ipbox99|ipbox55|tf7700)
|
ufs910|ufs912|ufs913|ufs922|atevio7500|fortis_hdbox|octagon1008|cuberevo|cuberevo_mini|cuberevo_mini2|cuberevo_250hd|cuberevo_2000hd|cuberevo_3000hd|ipbox9900|ipbox99|ipbox55|tf7700)
|
||||||
if test "$BOXTYPE" = "duckbox"; then
|
if test "$BOXTYPE" = "duckbox"; then
|
||||||
BOXMODEL="$withval"
|
BOXMODEL="$withval"
|
||||||
@@ -138,7 +130,6 @@ AC_SUBST(BOXTYPE)
|
|||||||
AC_SUBST(BOXMODEL)
|
AC_SUBST(BOXMODEL)
|
||||||
|
|
||||||
AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic")
|
AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic")
|
||||||
AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark")
|
|
||||||
AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox")
|
AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox")
|
||||||
AM_CONDITIONAL(BOXTYPE_ARMBOX, test "$BOXTYPE" = "armbox")
|
AM_CONDITIONAL(BOXTYPE_ARMBOX, test "$BOXTYPE" = "armbox")
|
||||||
AM_CONDITIONAL(BOXTYPE_MIPSBOX, test "$BOXTYPE" = "mipsbox")
|
AM_CONDITIONAL(BOXTYPE_MIPSBOX, test "$BOXTYPE" = "mipsbox")
|
||||||
@@ -147,17 +138,11 @@ AM_CONDITIONAL(BOXTYPE_MIPSBOX, test "$BOXTYPE" = "mipsbox")
|
|||||||
AM_CONDITIONAL(BOXMODEL_GENERIC, test "$BOXMODEL" = "generic")
|
AM_CONDITIONAL(BOXMODEL_GENERIC, test "$BOXMODEL" = "generic")
|
||||||
AM_CONDITIONAL(BOXMODEL_RASPI, test "$BOXMODEL" = "raspi")
|
AM_CONDITIONAL(BOXMODEL_RASPI, test "$BOXMODEL" = "raspi")
|
||||||
|
|
||||||
# spark
|
|
||||||
AM_CONDITIONAL(BOXMODEL_SPARK, test "$BOXMODEL" = "spark")
|
|
||||||
AM_CONDITIONAL(BOXMODEL_SPARK7162, test "$BOXMODEL" = "spark7162")
|
|
||||||
|
|
||||||
# duckbox
|
# duckbox
|
||||||
AM_CONDITIONAL(BOXMODEL_UFS910, test "$BOXMODEL" = "ufs910")
|
AM_CONDITIONAL(BOXMODEL_UFS910, test "$BOXMODEL" = "ufs910")
|
||||||
AM_CONDITIONAL(BOXMODEL_UFS912, test "$BOXMODEL" = "ufs912")
|
AM_CONDITIONAL(BOXMODEL_UFS912, test "$BOXMODEL" = "ufs912")
|
||||||
AM_CONDITIONAL(BOXMODEL_UFS913, test "$BOXMODEL" = "ufs913")
|
AM_CONDITIONAL(BOXMODEL_UFS913, test "$BOXMODEL" = "ufs913")
|
||||||
AM_CONDITIONAL(BOXMODEL_UFS922, test "$BOXMODEL" = "ufs922")
|
AM_CONDITIONAL(BOXMODEL_UFS922, test "$BOXMODEL" = "ufs922")
|
||||||
AM_CONDITIONAL(BOXMODEL_SPARK, test "$BOXMODEL" = "spark")
|
|
||||||
AM_CONDITIONAL(BOXMODEL_SPARK7162, test "$BOXMODEL" = "spark7162")
|
|
||||||
AM_CONDITIONAL(BOXMODEL_ATEVIO7500, test "$BOXMODEL" = "atevio7500")
|
AM_CONDITIONAL(BOXMODEL_ATEVIO7500, test "$BOXMODEL" = "atevio7500")
|
||||||
AM_CONDITIONAL(BOXMODEL_FORTIS_HDBOX, test "$BOXMODEL" = "fortis_hdbox")
|
AM_CONDITIONAL(BOXMODEL_FORTIS_HDBOX, test "$BOXMODEL" = "fortis_hdbox")
|
||||||
AM_CONDITIONAL(BOXMODEL_OCTAGON1008, test "$BOXMODEL" = "octagon1008")
|
AM_CONDITIONAL(BOXMODEL_OCTAGON1008, test "$BOXMODEL" = "octagon1008")
|
||||||
@@ -205,9 +190,6 @@ AM_CONDITIONAL(BOXMODEL_OSNINOPRO, test "$BOXMODEL" = "osninopro")
|
|||||||
|
|
||||||
if test "$BOXTYPE" = "generic"; then
|
if test "$BOXTYPE" = "generic"; then
|
||||||
AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC])
|
AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC])
|
||||||
elif test "$BOXTYPE" = "spark"; then
|
|
||||||
AC_DEFINE(HAVE_SPARK_HARDWARE, 1, [building for a goldenmedia 990 or edision pingulux])
|
|
||||||
AC_DEFINE(HAVE_SH4_HARDWARE, 1, [building for a sh4 box])
|
|
||||||
elif test "$BOXTYPE" = "duckbox"; then
|
elif test "$BOXTYPE" = "duckbox"; then
|
||||||
AC_DEFINE(HAVE_DUCKBOX_HARDWARE, 1, [building for a duckbox])
|
AC_DEFINE(HAVE_DUCKBOX_HARDWARE, 1, [building for a duckbox])
|
||||||
AC_DEFINE(HAVE_SH4_HARDWARE, 1, [building for a sh4 box])
|
AC_DEFINE(HAVE_SH4_HARDWARE, 1, [building for a sh4 box])
|
||||||
@@ -223,12 +205,6 @@ if test "$BOXMODEL" = "generic"; then
|
|||||||
elif test "$BOXMODEL" = "raspi"; then
|
elif test "$BOXMODEL" = "raspi"; then
|
||||||
AC_DEFINE(BOXMODEL_RASPI, 1, [raspberry pi])
|
AC_DEFINE(BOXMODEL_RASPI, 1, [raspberry pi])
|
||||||
|
|
||||||
# spark
|
|
||||||
elif test "$BOXMODEL" = "spark"; then
|
|
||||||
AC_DEFINE(BOXMODEL_SPARK, 1, [spark])
|
|
||||||
elif test "$BOXMODEL" = "spark7162"; then
|
|
||||||
AC_DEFINE(BOXMODEL_SPARK7162, 1, [spark7162])
|
|
||||||
|
|
||||||
# duckbox
|
# duckbox
|
||||||
elif test "$BOXMODEL" = "ufs910"; then
|
elif test "$BOXMODEL" = "ufs910"; then
|
||||||
AC_DEFINE(BOXMODEL_UFS910, 1, [ufs910])
|
AC_DEFINE(BOXMODEL_UFS910, 1, [ufs910])
|
||||||
|
@@ -60,7 +60,7 @@ unsigned long cCpuFreqManager::GetDelta(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
unsigned long cCpuFreqManager::GetCpuFreq(void)
|
unsigned long cCpuFreqManager::GetCpuFreq(void)
|
||||||
{
|
{
|
||||||
int freq = 0;
|
int freq = 0;
|
||||||
@@ -88,7 +88,7 @@ unsigned long cCpuFreqManager::GetCpuFreq(void)
|
|||||||
bool cCpuFreqManager::SetCpuFreq(unsigned long f)
|
bool cCpuFreqManager::SetCpuFreq(unsigned long f)
|
||||||
{
|
{
|
||||||
hal_info("%s(%lu) => set standby = %s\n", __func__, f, f ? "true" : "false");
|
hal_info("%s(%lu) => set standby = %s\n", __func__, f, f ? "true" : "false");
|
||||||
#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
FILE *pll0 = fopen("/proc/cpu_frequ/pll0_ndiv_mdiv", "w");
|
FILE *pll0 = fopen("/proc/cpu_frequ/pll0_ndiv_mdiv", "w");
|
||||||
|
@@ -93,7 +93,6 @@ libeplayer3/Makefile
|
|||||||
libeplayer3-sh4/Makefile
|
libeplayer3-sh4/Makefile
|
||||||
libgeneric-pc/Makefile
|
libgeneric-pc/Makefile
|
||||||
libraspi/Makefile
|
libraspi/Makefile
|
||||||
libspark/Makefile
|
|
||||||
tools/Makefile
|
tools/Makefile
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@@ -2,9 +2,6 @@
|
|||||||
#if HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
#include "../libduckbox/audio_lib.h"
|
#include "../libduckbox/audio_lib.h"
|
||||||
#include "../libduckbox/audio_mixer.h"
|
#include "../libduckbox/audio_mixer.h"
|
||||||
#elif HAVE_SPARK_HARDWARE
|
|
||||||
#include "../libspark/audio_lib.h"
|
|
||||||
#include "../libspark/audio_mixer.h"
|
|
||||||
#elif HAVE_ARM_HARDWARE
|
#elif HAVE_ARM_HARDWARE
|
||||||
#include "../libarmbox/audio_lib.h"
|
#include "../libarmbox/audio_lib.h"
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#if HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
#include "../libduckbox/playback_libeplayer3.h"
|
#include "../libduckbox/playback_libeplayer3.h"
|
||||||
#elif HAVE_SPARK_HARDWARE
|
|
||||||
#include "../libspark/playback_libeplayer3.h"
|
|
||||||
#elif HAVE_ARM_HARDWARE
|
#elif HAVE_ARM_HARDWARE
|
||||||
#include "../libarmbox/playback_libeplayer3.h"
|
#include "../libarmbox/playback_libeplayer3.h"
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#if HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
#include "../libduckbox/record_lib.h"
|
#include "../libduckbox/record_lib.h"
|
||||||
#elif HAVE_SPARK_HARDWARE
|
|
||||||
#include "../libspark/record_lib.h"
|
|
||||||
#elif HAVE_ARM_HARDWARE
|
#elif HAVE_ARM_HARDWARE
|
||||||
#include "../libarmbox/record_lib.h"
|
#include "../libarmbox/record_lib.h"
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#if HAVE_DUCKBOX_HARDWARE
|
#if HAVE_DUCKBOX_HARDWARE
|
||||||
#include "../libduckbox/video_lib.h"
|
#include "../libduckbox/video_lib.h"
|
||||||
#elif HAVE_SPARK_HARDWARE
|
|
||||||
#include "../libspark/video_lib.h"
|
|
||||||
#elif HAVE_ARM_HARDWARE
|
#elif HAVE_ARM_HARDWARE
|
||||||
#include "../libarmbox/video_lib.h"
|
#include "../libarmbox/video_lib.h"
|
||||||
#include "../libarmbox/hdmi_cec.h"
|
#include "../libarmbox/hdmi_cec.h"
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
../libspark/record.cpp
|
|
398
libgeneric-pc/record.cpp
Normal file
398
libgeneric-pc/record.cpp
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <aio.h>
|
||||||
|
|
||||||
|
#include "record_lib.h"
|
||||||
|
#include "hal_debug.h"
|
||||||
|
#define hal_debug(args...) _hal_debug(HAL_DEBUG_RECORD, this, args)
|
||||||
|
#define hal_info(args...) _hal_info(HAL_DEBUG_RECORD, this, args)
|
||||||
|
|
||||||
|
/* helper function to call the cpp thread loop */
|
||||||
|
void *execute_record_thread(void *c)
|
||||||
|
{
|
||||||
|
cRecord *obj = (cRecord *)c;
|
||||||
|
obj->RecordThread();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *execute_writer_thread(void *c)
|
||||||
|
{
|
||||||
|
cRecord *obj = (cRecord *)c;
|
||||||
|
obj->WriterThread();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cRecord::cRecord(int num, int bs_dmx, int bs)
|
||||||
|
{
|
||||||
|
hal_info("%s %d\n", __func__, num);
|
||||||
|
dmx = NULL;
|
||||||
|
record_thread_running = false;
|
||||||
|
file_fd = -1;
|
||||||
|
exit_flag = RECORD_STOPPED;
|
||||||
|
dmx_num = num;
|
||||||
|
bufsize = bs;
|
||||||
|
bufsize_dmx = bs_dmx;
|
||||||
|
failureCallback = NULL;
|
||||||
|
failureData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cRecord::~cRecord()
|
||||||
|
{
|
||||||
|
hal_info("%s: calling ::Stop()\n", __func__);
|
||||||
|
Stop();
|
||||||
|
hal_info("%s: end\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecord::Open(void)
|
||||||
|
{
|
||||||
|
hal_info("%s\n", __func__);
|
||||||
|
exit_flag = RECORD_STOPPED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// unused
|
||||||
|
void cRecord::Close(void)
|
||||||
|
{
|
||||||
|
hal_info("%s: \n", __func__);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool cRecord::Start(int fd, unsigned short vpid, unsigned short *apids, int numpids, uint64_t)
|
||||||
|
{
|
||||||
|
hal_info("%s: fd %d, vpid 0x%03x\n", __func__, fd, vpid);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!dmx)
|
||||||
|
dmx = new cDemux(dmx_num);
|
||||||
|
|
||||||
|
dmx->Open(DMX_TP_CHANNEL, NULL, bufsize_dmx);
|
||||||
|
dmx->pesFilter(vpid);
|
||||||
|
|
||||||
|
for (i = 0; i < numpids; i++)
|
||||||
|
dmx->addPid(apids[i]);
|
||||||
|
|
||||||
|
file_fd = fd;
|
||||||
|
exit_flag = RECORD_RUNNING;
|
||||||
|
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
||||||
|
perror("posix_fadvise");
|
||||||
|
|
||||||
|
i = pthread_create(&record_thread, 0, execute_record_thread, this);
|
||||||
|
if (i != 0)
|
||||||
|
{
|
||||||
|
exit_flag = RECORD_FAILED_READ;
|
||||||
|
errno = i;
|
||||||
|
hal_info("%s: error creating thread! (%m)\n", __func__);
|
||||||
|
delete dmx;
|
||||||
|
dmx = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
record_thread_running = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecord::Stop(void)
|
||||||
|
{
|
||||||
|
hal_info("%s\n", __func__);
|
||||||
|
|
||||||
|
if (exit_flag != RECORD_RUNNING)
|
||||||
|
hal_info("%s: status not RUNNING? (%d)\n", __func__, exit_flag);
|
||||||
|
|
||||||
|
exit_flag = RECORD_STOPPED;
|
||||||
|
if (record_thread_running)
|
||||||
|
pthread_join(record_thread, NULL);
|
||||||
|
record_thread_running = false;
|
||||||
|
|
||||||
|
/* We should probably do that from the destructor... */
|
||||||
|
if (!dmx)
|
||||||
|
hal_info("%s: dmx == NULL?\n", __func__);
|
||||||
|
else
|
||||||
|
delete dmx;
|
||||||
|
dmx = NULL;
|
||||||
|
|
||||||
|
if (file_fd != -1)
|
||||||
|
close(file_fd);
|
||||||
|
else
|
||||||
|
hal_info("%s: file_fd not open??\n", __func__);
|
||||||
|
file_fd = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecord::ChangePids(unsigned short /*vpid*/, unsigned short *apids, int numapids)
|
||||||
|
{
|
||||||
|
std::vector<pes_pids> pids;
|
||||||
|
int j;
|
||||||
|
bool found;
|
||||||
|
unsigned short pid;
|
||||||
|
hal_info("%s\n", __func__);
|
||||||
|
if (!dmx)
|
||||||
|
{
|
||||||
|
hal_info("%s: DMX = NULL\n", __func__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pids = dmx->pesfds;
|
||||||
|
/* the first PID is the video pid, so start with the second PID... */
|
||||||
|
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i)
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
pid = (*i).pid;
|
||||||
|
for (j = 0; j < numapids; j++)
|
||||||
|
{
|
||||||
|
if (pid == apids[j])
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
dmx->removePid(pid);
|
||||||
|
}
|
||||||
|
for (j = 0; j < numapids; j++)
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i)
|
||||||
|
{
|
||||||
|
if ((*i).pid == apids[j])
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
dmx->addPid(apids[j]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecord::AddPid(unsigned short pid)
|
||||||
|
{
|
||||||
|
std::vector<pes_pids> pids;
|
||||||
|
hal_info("%s: \n", __func__);
|
||||||
|
if (!dmx)
|
||||||
|
{
|
||||||
|
hal_info("%s: DMX = NULL\n", __func__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pids = dmx->pesfds;
|
||||||
|
for (std::vector<pes_pids>::const_iterator i = pids.begin(); i != pids.end(); ++i)
|
||||||
|
{
|
||||||
|
if ((*i).pid == pid)
|
||||||
|
return true; /* or is it an error to try to add the same PID twice? */
|
||||||
|
}
|
||||||
|
return dmx->addPid(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecord::WriterThread()
|
||||||
|
{
|
||||||
|
char threadname[17];
|
||||||
|
strncpy(threadname, "WriterThread", sizeof(threadname));
|
||||||
|
threadname[16] = 0;
|
||||||
|
prctl(PR_SET_NAME, (unsigned long)&threadname);
|
||||||
|
unsigned int chunk = 0;
|
||||||
|
while (!sem_wait(&sem))
|
||||||
|
{
|
||||||
|
if (!io_len[chunk]) // empty, assume end of recording
|
||||||
|
return;
|
||||||
|
unsigned char *p_buf = io_buf[chunk];
|
||||||
|
size_t p_len = io_len[chunk];
|
||||||
|
while (p_len)
|
||||||
|
{
|
||||||
|
ssize_t written = write(file_fd, p_buf, p_len);
|
||||||
|
if (written < 0)
|
||||||
|
break;
|
||||||
|
p_len -= written;
|
||||||
|
p_buf += written;
|
||||||
|
}
|
||||||
|
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
||||||
|
perror("posix_fadvise");
|
||||||
|
chunk++;
|
||||||
|
chunk %= RECORD_WRITER_CHUNKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecord::RecordThread()
|
||||||
|
{
|
||||||
|
hal_info("%s: begin\n", __func__);
|
||||||
|
char threadname[17];
|
||||||
|
strncpy(threadname, "RecordThread", sizeof(threadname));
|
||||||
|
threadname[16] = 0;
|
||||||
|
prctl(PR_SET_NAME, (unsigned long)&threadname);
|
||||||
|
int readsize = bufsize / 16;
|
||||||
|
int buf_pos = 0;
|
||||||
|
int count = 0;
|
||||||
|
int queued = 0;
|
||||||
|
uint8_t *buf;
|
||||||
|
struct aiocb a;
|
||||||
|
|
||||||
|
buf = (uint8_t *)malloc(bufsize);
|
||||||
|
hal_info("BUFSIZE=0x%x READSIZE=0x%x\n", bufsize, readsize);
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
exit_flag = RECORD_FAILED_MEMORY;
|
||||||
|
hal_info("%s: unable to allocate buffer! (out of memory)\n", __func__);
|
||||||
|
if (failureCallback)
|
||||||
|
failureCallback(failureData);
|
||||||
|
hal_info("%s: end\n", __func__);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int val = fcntl(file_fd, F_GETFL);
|
||||||
|
if (fcntl(file_fd, F_SETFL, val | O_APPEND))
|
||||||
|
hal_info("%s: O_APPEND? (%m)\n", __func__);
|
||||||
|
|
||||||
|
memset(&a, 0, sizeof(a));
|
||||||
|
a.aio_fildes = file_fd;
|
||||||
|
a.aio_sigevent.sigev_notify = SIGEV_NONE;
|
||||||
|
|
||||||
|
dmx->Start();
|
||||||
|
int overflow_count = 0;
|
||||||
|
bool overflow = false;
|
||||||
|
int r = 0;
|
||||||
|
while (exit_flag == RECORD_RUNNING)
|
||||||
|
{
|
||||||
|
if (buf_pos < bufsize)
|
||||||
|
{
|
||||||
|
if (overflow_count)
|
||||||
|
{
|
||||||
|
hal_info("%s: Overflow cleared after %d iterations\n", __func__, overflow_count);
|
||||||
|
overflow_count = 0;
|
||||||
|
}
|
||||||
|
int toread = bufsize - buf_pos;
|
||||||
|
if (toread > readsize)
|
||||||
|
toread = readsize;
|
||||||
|
ssize_t s = dmx->Read(buf + buf_pos, toread, 50);
|
||||||
|
hal_debug("%s: buf_pos %6d s %6d / %6d\n", __func__, buf_pos, (int)s, bufsize - buf_pos);
|
||||||
|
if (s < 0)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && (errno != EOVERFLOW || !overflow))
|
||||||
|
{
|
||||||
|
hal_info("%s: read failed: %m\n", __func__);
|
||||||
|
exit_flag = RECORD_FAILED_READ;
|
||||||
|
state = REC_STATUS_OVERFLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
overflow = false;
|
||||||
|
buf_pos += s;
|
||||||
|
if (count > 100)
|
||||||
|
{
|
||||||
|
if (buf_pos < bufsize / 2)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!overflow)
|
||||||
|
overflow_count = 0;
|
||||||
|
overflow = true;
|
||||||
|
if (!(overflow_count % 10))
|
||||||
|
hal_info("%s: buffer full! Overflow? (%d)\n", __func__, ++overflow_count);
|
||||||
|
state = REC_STATUS_SLOW;
|
||||||
|
}
|
||||||
|
r = aio_error(&a);
|
||||||
|
if (r == EINPROGRESS)
|
||||||
|
{
|
||||||
|
hal_debug("%s: aio in progress, free: %d\n", __func__, bufsize - buf_pos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// not calling aio_return causes a memory leak --martii
|
||||||
|
r = aio_return(&a);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
exit_flag = RECORD_FAILED_FILE;
|
||||||
|
hal_debug("%s: aio_return = %d (%m)\n", __func__, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hal_debug("%s: aio_return = %d, free: %d\n", __func__, r, bufsize - buf_pos);
|
||||||
|
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
||||||
|
perror("posix_fadvise");
|
||||||
|
if (queued)
|
||||||
|
{
|
||||||
|
memmove(buf, buf + queued, buf_pos - queued);
|
||||||
|
buf_pos -= queued;
|
||||||
|
}
|
||||||
|
queued = buf_pos;
|
||||||
|
a.aio_buf = buf;
|
||||||
|
a.aio_nbytes = queued;
|
||||||
|
r = aio_write(&a);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
hal_info("%s: aio_write %d (%m)\n", __func__, r);
|
||||||
|
exit_flag = RECORD_FAILED_FILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dmx->Stop();
|
||||||
|
while (true) /* write out the unwritten buffer content */
|
||||||
|
{
|
||||||
|
hal_debug("%s: run-out write, buf_pos %d\n", __func__, buf_pos);
|
||||||
|
r = aio_error(&a);
|
||||||
|
if (r == EINPROGRESS)
|
||||||
|
{
|
||||||
|
usleep(50000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r = aio_return(&a);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
exit_flag = RECORD_FAILED_FILE;
|
||||||
|
hal_info("%s: aio_result: %d (%m)\n", __func__, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!queued)
|
||||||
|
break;
|
||||||
|
memmove(buf, buf + queued, buf_pos - queued);
|
||||||
|
buf_pos -= queued;
|
||||||
|
queued = buf_pos;
|
||||||
|
a.aio_buf = buf;
|
||||||
|
a.aio_nbytes = queued;
|
||||||
|
r = aio_write(&a);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO: do we need to notify neutrino about failing recording?
|
||||||
|
CEventServer eventServer;
|
||||||
|
eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock");
|
||||||
|
stream2file_status2_t s;
|
||||||
|
s.status = exit_flag;
|
||||||
|
strncpy(s.filename, basename(myfilename), 512);
|
||||||
|
s.filename[511] = '\0';
|
||||||
|
strncpy(s.dir, dirname(myfilename), 100);
|
||||||
|
s.dir[99] = '\0';
|
||||||
|
eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s));
|
||||||
|
printf("[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((exit_flag != RECORD_STOPPED) && failureCallback)
|
||||||
|
failureCallback(failureData);
|
||||||
|
hal_info("%s: end\n", __func__);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cRecord::GetStatus()
|
||||||
|
{
|
||||||
|
return (exit_flag == RECORD_STOPPED) ? REC_STATUS_STOPPED : REC_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecord::ResetStatus()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
@@ -1 +0,0 @@
|
|||||||
../libspark/record_lib.h
|
|
59
libgeneric-pc/record_lib.h
Normal file
59
libgeneric-pc/record_lib.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef __RECORD_LIB_H__
|
||||||
|
#define __RECORD_LIB_H__
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include "dmx_hal.h"
|
||||||
|
|
||||||
|
#define REC_STATUS_OK 0
|
||||||
|
#define REC_STATUS_SLOW 1
|
||||||
|
#define REC_STATUS_OVERFLOW 2
|
||||||
|
#define REC_STATUS_STOPPED 4
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RECORD_RUNNING,
|
||||||
|
RECORD_STOPPED,
|
||||||
|
RECORD_FAILED_READ, /* failed to read from DMX */
|
||||||
|
RECORD_FAILED_OVERFLOW, /* cannot write fast enough */
|
||||||
|
RECORD_FAILED_FILE, /* cannot write to file */
|
||||||
|
RECORD_FAILED_MEMORY /* out of memory */
|
||||||
|
} record_state_t;
|
||||||
|
|
||||||
|
class cRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int file_fd;
|
||||||
|
int dmx_num;
|
||||||
|
cDemux *dmx;
|
||||||
|
pthread_t record_thread;
|
||||||
|
bool record_thread_running;
|
||||||
|
record_state_t exit_flag;
|
||||||
|
int state;
|
||||||
|
int bufsize;
|
||||||
|
int bufsize_dmx;
|
||||||
|
void (*failureCallback)(void *);
|
||||||
|
void *failureData;
|
||||||
|
|
||||||
|
sem_t sem;
|
||||||
|
#define RECORD_WRITER_CHUNKS 16
|
||||||
|
unsigned char *io_buf[RECORD_WRITER_CHUNKS];
|
||||||
|
size_t io_len[RECORD_WRITER_CHUNKS];
|
||||||
|
|
||||||
|
public:
|
||||||
|
cRecord(int num = 0, int bs_dmx = 2048 * 1024, int bs = 4096 * 1024);
|
||||||
|
void setFailureCallback(void (*f)(void *), void *d) { failureCallback = f; failureData = d; }
|
||||||
|
~cRecord();
|
||||||
|
|
||||||
|
bool Open();
|
||||||
|
bool Start(int fd, unsigned short vpid, unsigned short *apids, int numapids, uint64_t ch = 0);
|
||||||
|
bool Stop(void);
|
||||||
|
bool AddPid(unsigned short pid);
|
||||||
|
int GetStatus();
|
||||||
|
void ResetStatus();
|
||||||
|
bool ChangePids(unsigned short vpid, unsigned short *apids, int numapids);
|
||||||
|
|
||||||
|
void RecordThread();
|
||||||
|
void WriterThread();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __RECORD_LIB_H__
|
@@ -1 +1 @@
|
|||||||
../libspark/record.cpp
|
../libgeneric-pc/record.cpp
|
@@ -1 +1 @@
|
|||||||
../libspark/record_lib.h
|
../libgeneric-pc/record_lib.h
|
@@ -1,27 +0,0 @@
|
|||||||
noinst_LTLIBRARIES = libspark.la
|
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir)/common \
|
|
||||||
-I$(top_srcdir)/include \
|
|
||||||
-I$(top_srcdir)/libeplayer3-sh4/include
|
|
||||||
|
|
||||||
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
|
|
||||||
AM_LDFLAGS = \
|
|
||||||
-lOpenThreads \
|
|
||||||
@AVFORMAT_LIBS@ \
|
|
||||||
@AVUTIL_LIBS@ \
|
|
||||||
@AVCODEC_LIBS@ \
|
|
||||||
@SWRESAMPLE_LIBS@ \
|
|
||||||
-lpthread -lasound -lass -lrt
|
|
||||||
|
|
||||||
libspark_la_SOURCES = \
|
|
||||||
hardware_caps.c \
|
|
||||||
dmx.cpp \
|
|
||||||
video.cpp \
|
|
||||||
audio.cpp \
|
|
||||||
audio_mixer.cpp \
|
|
||||||
init.cpp \
|
|
||||||
playback_libeplayer3.cpp \
|
|
||||||
record.cpp
|
|
||||||
|
|
||||||
AM_CPPFLAGS += -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
|
|
@@ -1,492 +0,0 @@
|
|||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <linux/dvb/audio.h>
|
|
||||||
|
|
||||||
#include <hardware_caps.h>
|
|
||||||
#include <proc_tools.h>
|
|
||||||
|
|
||||||
#include "audio_lib.h"
|
|
||||||
#include "audio_mixer.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_AUDIO, this, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_AUDIO, this, args)
|
|
||||||
|
|
||||||
#include <linux/soundcard.h>
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ENCODER,
|
|
||||||
AUX
|
|
||||||
};
|
|
||||||
|
|
||||||
cAudio *audioDecoder = NULL;
|
|
||||||
cAudio *pipAudioDecoder[3] = { NULL, NULL, NULL };
|
|
||||||
|
|
||||||
static const char *ADEV[] =
|
|
||||||
{
|
|
||||||
"/dev/dvb/adapter0/audio0",
|
|
||||||
"/dev/dvb/adapter0/audio1",
|
|
||||||
"/dev/dvb/adapter0/audio2",
|
|
||||||
"/dev/dvb/adapter0/audio3"
|
|
||||||
};
|
|
||||||
|
|
||||||
cAudio::cAudio(void *, void *, void *, unsigned int unit)
|
|
||||||
{
|
|
||||||
hw_caps_t *hwcaps = get_hwcaps();
|
|
||||||
if (unit > (unsigned int) hwcaps->pip_devs)
|
|
||||||
{
|
|
||||||
hal_info("%s: unit %d out of range, setting to 0\n", __func__, unit);
|
|
||||||
devnum = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
devnum = unit;
|
|
||||||
fd = -1;
|
|
||||||
clipfd = -1;
|
|
||||||
mixer_fd = -1;
|
|
||||||
|
|
||||||
mixerAnalog = mixerHDMI = mixerSPDIF = NULL;
|
|
||||||
volumeAnalog = volumeHDMI = volumeSPDIF = 0;
|
|
||||||
mixersMuted = false;
|
|
||||||
|
|
||||||
openDevice();
|
|
||||||
Muted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cAudio::~cAudio(void)
|
|
||||||
{
|
|
||||||
closeMixers();
|
|
||||||
closeDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::openDevice(void)
|
|
||||||
{
|
|
||||||
openMixers();
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
if ((fd = open(ADEV[devnum], O_RDWR)) < 0)
|
|
||||||
hal_info("openDevice: open failed (%m)\n");
|
|
||||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
||||||
do_mute(true, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hal_info("openDevice: already open (fd = %d)\n", fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::closeDevice(void)
|
|
||||||
{
|
|
||||||
closeMixers();
|
|
||||||
|
|
||||||
if (fd > -1)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
if (clipfd > -1)
|
|
||||||
{
|
|
||||||
close(clipfd);
|
|
||||||
clipfd = -1;
|
|
||||||
}
|
|
||||||
if (mixer_fd > -1)
|
|
||||||
{
|
|
||||||
close(mixer_fd);
|
|
||||||
mixer_fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::setAVInput(int val)
|
|
||||||
{
|
|
||||||
hal_info("%s not implemented yet - switching to: %s\n", __func__, val == AUX ? "AUX" : "ENCODER");
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::do_mute(bool enable, bool remember)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d, %d)\n", __FUNCTION__, enable, remember);
|
|
||||||
char str[4];
|
|
||||||
|
|
||||||
if (remember)
|
|
||||||
Muted = enable;
|
|
||||||
|
|
||||||
sprintf(str, "%d", Muted);
|
|
||||||
proc_put("/proc/stb/audio/j1_mute", str, strlen(str));
|
|
||||||
|
|
||||||
if (!enable)
|
|
||||||
{
|
|
||||||
int f = open("/proc/stb/avs/0/volume", O_RDWR);
|
|
||||||
read(f, str, 4);
|
|
||||||
close(f);
|
|
||||||
str[3] = '\0';
|
|
||||||
proc_put("/proc/stb/avs/0/volume", str, strlen(str));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int map_volume(const int volume)
|
|
||||||
{
|
|
||||||
unsigned char vol = volume;
|
|
||||||
if (vol > 100)
|
|
||||||
vol = 100;
|
|
||||||
|
|
||||||
vol = 63 - vol * 63 / 100;
|
|
||||||
return vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::setVolume(unsigned int left, unsigned int right)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d, %d)\n", __func__, left, right);
|
|
||||||
|
|
||||||
volume = (left + right) / 2;
|
|
||||||
int v = map_volume(volume);
|
|
||||||
#if 0
|
|
||||||
if (clipfd != -1 && mixer_fd != -1)
|
|
||||||
{
|
|
||||||
int tmp = 0;
|
|
||||||
/* not sure if left / right is correct here, but it is always the same anyways ;-) */
|
|
||||||
if (! Muted)
|
|
||||||
tmp = left << 8 | right;
|
|
||||||
int ret = ioctl(mixer_fd, MIXER_WRITE(mixer_num), &tmp);
|
|
||||||
if (ret == -1)
|
|
||||||
hal_info("%s: MIXER_WRITE(%d),%04x: %m\n", __func__, mixer_num, tmp);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char str[4];
|
|
||||||
sprintf(str, "%d", v);
|
|
||||||
|
|
||||||
proc_put("/proc/stb/avs/0/volume", str, strlen(str));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::Start(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
ret = ioctl(fd, AUDIO_PLAY);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::Stop(void)
|
|
||||||
{
|
|
||||||
return ioctl(fd, AUDIO_STOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cAudio::Pause(bool Pcm)
|
|
||||||
{
|
|
||||||
ioctl(fd, Pcm ? AUDIO_PAUSE : AUDIO_CONTINUE, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::SetSyncMode(AVSYNC_TYPE Mode)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, Mode);
|
|
||||||
ioctl(fd, AUDIO_SET_AV_SYNC, Mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::SetStreamType(int bypass)
|
|
||||||
{
|
|
||||||
StreamType = bypass;
|
|
||||||
|
|
||||||
hal_info("%s %d (0x%x)\n", __FUNCTION__, bypass, bypass);
|
|
||||||
|
|
||||||
if (ioctl(fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
|
|
||||||
hal_info("%s: AUDIO_SET_BYPASS_MODE failed (%m)\n", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::setChannel(int channel)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __FUNCTION__, channel);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::PrepareClipPlay(int ch, int srate, int bits, int little_endian)
|
|
||||||
{
|
|
||||||
int fmt;
|
|
||||||
unsigned int devmask, stereo, usable;
|
|
||||||
const char *dsp_dev = getenv("DSP_DEVICE");
|
|
||||||
const char *mix_dev = getenv("MIX_DEVICE");
|
|
||||||
hal_debug("%s ch %d srate %d bits %d le %d\n", __FUNCTION__, ch, srate, bits, little_endian);
|
|
||||||
if (clipfd > -1)
|
|
||||||
{
|
|
||||||
hal_info("%s: clipfd already opened (%d)\n", __FUNCTION__, clipfd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
mixer_num = -1;
|
|
||||||
/* a different DSP device can be given with DSP_DEVICE and MIX_DEVICE
|
|
||||||
* if this device cannot be opened, we fall back to the internal OSS device
|
|
||||||
* Example:
|
|
||||||
* modprobe snd-usb-audio
|
|
||||||
* export DSP_DEVICE=/dev/sound/dsp2
|
|
||||||
* export MIX_DEVICE=/dev/sound/mixer2
|
|
||||||
* neutrino
|
|
||||||
*/
|
|
||||||
if ((!dsp_dev) || (access(dsp_dev, W_OK)))
|
|
||||||
{
|
|
||||||
if (dsp_dev)
|
|
||||||
hal_info("%s: DSP_DEVICE is set (%s) but cannot be opened,"
|
|
||||||
" fall back to /dev/dsp1\n", __func__, dsp_dev);
|
|
||||||
dsp_dev = "/dev/dsp1";
|
|
||||||
}
|
|
||||||
hal_info("%s: dsp_dev %s mix_dev %s\n", __func__, dsp_dev, mix_dev); /* NULL mix_dev is ok */
|
|
||||||
/* the tdoss dsp driver seems to work only on the second open(). really. */
|
|
||||||
clipfd = open(dsp_dev, O_WRONLY);
|
|
||||||
if (clipfd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s open %s: %m\n", dsp_dev, __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fcntl(clipfd, F_SETFD, FD_CLOEXEC);
|
|
||||||
/* no idea if we ever get little_endian == 0 */
|
|
||||||
if (little_endian)
|
|
||||||
fmt = AFMT_S16_BE;
|
|
||||||
else
|
|
||||||
fmt = AFMT_S16_LE;
|
|
||||||
if (ioctl(clipfd, SNDCTL_DSP_SETFMT, &fmt))
|
|
||||||
perror("SNDCTL_DSP_SETFMT");
|
|
||||||
if (ioctl(clipfd, SNDCTL_DSP_CHANNELS, &ch))
|
|
||||||
perror("SNDCTL_DSP_CHANNELS");
|
|
||||||
if (ioctl(clipfd, SNDCTL_DSP_SPEED, &srate))
|
|
||||||
perror("SNDCTL_DSP_SPEED");
|
|
||||||
if (ioctl(clipfd, SNDCTL_DSP_RESET))
|
|
||||||
perror("SNDCTL_DSP_RESET");
|
|
||||||
|
|
||||||
if (!mix_dev)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mixer_fd = open(mix_dev, O_RDWR);
|
|
||||||
if (mixer_fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: open mixer %s failed (%m)\n", __func__, mix_dev);
|
|
||||||
/* not a real error */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
|
|
||||||
{
|
|
||||||
hal_info("%s: SOUND_MIXER_READ_DEVMASK %m\n", __func__);
|
|
||||||
devmask = 0;
|
|
||||||
}
|
|
||||||
if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1)
|
|
||||||
{
|
|
||||||
hal_info("%s: SOUND_MIXER_READ_STEREODEVS %m\n", __func__);
|
|
||||||
stereo = 0;
|
|
||||||
}
|
|
||||||
usable = devmask & stereo;
|
|
||||||
if (usable == 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: devmask: %08x stereo: %08x, no usable dev :-(\n",
|
|
||||||
__func__, devmask, stereo);
|
|
||||||
close(mixer_fd);
|
|
||||||
mixer_fd = -1;
|
|
||||||
return 0; /* TODO: should we treat this as error? */
|
|
||||||
}
|
|
||||||
/* __builtin_popcount needs GCC, it counts the set bits... */
|
|
||||||
if (__builtin_popcount(usable) != 1)
|
|
||||||
{
|
|
||||||
/* TODO: this code is not yet tested as I have only single-mixer devices... */
|
|
||||||
hal_info("%s: more than one mixer control: devmask %08x stereo %08x\n"
|
|
||||||
"%s: querying MIX_NUMBER environment variable...\n",
|
|
||||||
__func__, devmask, stereo, __func__);
|
|
||||||
const char *tmp = getenv("MIX_NUMBER");
|
|
||||||
if (tmp)
|
|
||||||
mixer_num = atoi(tmp);
|
|
||||||
hal_info("%s: mixer_num is %d -> device %08x\n",
|
|
||||||
__func__, mixer_num, (mixer_num >= 0) ? (1 << mixer_num) : 0);
|
|
||||||
/* no error checking, you'd better know what you are doing... */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mixer_num = 0;
|
|
||||||
while (!(usable & 0x01))
|
|
||||||
{
|
|
||||||
mixer_num++;
|
|
||||||
usable >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setVolume(volume, volume);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::WriteClip(unsigned char *buffer, int size)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
// hal_debug("cAudio::%s\n", __FUNCTION__);
|
|
||||||
if (clipfd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: clipfd not yet opened\n", __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = write(clipfd, buffer, size);
|
|
||||||
if (ret < 0)
|
|
||||||
hal_info("%s: write error (%m)\n", __FUNCTION__);
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
int cAudio::StopClip()
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __FUNCTION__);
|
|
||||||
if (clipfd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: clipfd not yet opened\n", __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(clipfd);
|
|
||||||
clipfd = -1;
|
|
||||||
if (mixer_fd > -1)
|
|
||||||
{
|
|
||||||
close(mixer_fd);
|
|
||||||
mixer_fd = -1;
|
|
||||||
}
|
|
||||||
setVolume(volume, volume);
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &mode)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __FUNCTION__);
|
|
||||||
type = 0;
|
|
||||||
layer = 0;
|
|
||||||
freq = 0;
|
|
||||||
bitrate = 0;
|
|
||||||
mode = 0;
|
|
||||||
#if 0
|
|
||||||
unsigned int atype;
|
|
||||||
static const int freq_mpg[] = {44100, 48000, 32000, 0};
|
|
||||||
static const int freq_ac3[] = {48000, 44100, 32000, 0};
|
|
||||||
scratchl2 i;
|
|
||||||
if (ioctl(fd, MPEG_AUD_GET_DECTYP, &atype) < 0)
|
|
||||||
perror("cAudio::getAudioInfo MPEG_AUD_GET_DECTYP");
|
|
||||||
if (ioctl(fd, MPEG_AUD_GET_STATUS, &i) < 0)
|
|
||||||
perror("cAudio::getAudioInfo MPEG_AUD_GET_STATUS");
|
|
||||||
|
|
||||||
type = atype;
|
|
||||||
#if 0
|
|
||||||
/* this does not work, some of the values are negative?? */
|
|
||||||
AMPEGStatus A;
|
|
||||||
memcpy(&A, &i.word00, sizeof(i.word00));
|
|
||||||
layer = A.audio_mpeg_layer;
|
|
||||||
mode = A.audio_mpeg_mode;
|
|
||||||
bitrate = A.audio_mpeg_bitrate;
|
|
||||||
switch (A.audio_mpeg_frequency)
|
|
||||||
#endif
|
|
||||||
/* layer and bitrate are not used anyway... */
|
|
||||||
layer = 0; //(i.word00 >> 17) & 3;
|
|
||||||
bitrate = 0; //(i.word00 >> 12) & 3;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case 0: /* MPEG */
|
|
||||||
mode = (i.word00 >> 6) & 3;
|
|
||||||
freq = freq_mpg[(i.word00 >> 10) & 3];
|
|
||||||
break;
|
|
||||||
case 1: /* AC3 */
|
|
||||||
mode = (i.word00 >> 28) & 7;
|
|
||||||
freq = freq_ac3[(i.word00 >> 16) & 3];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mode = 0;
|
|
||||||
freq = 0;
|
|
||||||
}
|
|
||||||
//fprintf(stderr, "type: %d layer: %d freq: %d bitrate: %d mode: %d\n", type, layer, freq, bitrate, mode);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetSRS(int /*iq_enable*/, int /*nmgr_enable*/, int /*iq_mode*/, int /*iq_level*/)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __FUNCTION__);
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetHdmiDD(bool enable)
|
|
||||||
{
|
|
||||||
const char *opt[] = { "pcm", "spdif" };
|
|
||||||
hal_debug("%s %d\n", __func__, enable);
|
|
||||||
proc_put("/proc/stb/hdmi/audio_source", opt[enable], strlen(opt[enable]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::SetSpdifDD(bool enable)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, enable);
|
|
||||||
setBypassMode(!enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::ScheduleMute(bool On)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __FUNCTION__, On);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::EnableAnalogOut(bool enable)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __FUNCTION__, enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define AUDIO_BYPASS_ON 0
|
|
||||||
#define AUDIO_BYPASS_OFF 1
|
|
||||||
void cAudio::setBypassMode(bool disable)
|
|
||||||
{
|
|
||||||
const char *opt[] = { "passthrough", "downmix" };
|
|
||||||
hal_debug("%s %d\n", __func__, disable);
|
|
||||||
proc_put("/proc/stb/audio/ac3", opt[disable], strlen(opt[disable]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::openMixers(void)
|
|
||||||
{
|
|
||||||
if (!mixerAnalog)
|
|
||||||
mixerAnalog = new mixerVolume("Analog", "1");
|
|
||||||
if (!mixerHDMI)
|
|
||||||
mixerHDMI = new mixerVolume("HDMI", "1");
|
|
||||||
if (!mixerSPDIF)
|
|
||||||
mixerSPDIF = new mixerVolume("SPDIF", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::closeMixers(void)
|
|
||||||
{
|
|
||||||
delete mixerAnalog;
|
|
||||||
delete mixerHDMI;
|
|
||||||
delete mixerSPDIF;
|
|
||||||
mixerAnalog = mixerHDMI = mixerSPDIF = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::setMixerVolume(const char *name, long value, bool remember)
|
|
||||||
{
|
|
||||||
if (!strcmp(name, "Analog"))
|
|
||||||
{
|
|
||||||
mixerAnalog->setVolume(value);
|
|
||||||
if (remember)
|
|
||||||
volumeAnalog = value;
|
|
||||||
}
|
|
||||||
if (!strcmp(name, "HDMI"))
|
|
||||||
{
|
|
||||||
mixerHDMI->setVolume(value);
|
|
||||||
if (remember)
|
|
||||||
volumeHDMI = value;
|
|
||||||
}
|
|
||||||
if (!strcmp(name, "SPDIF"))
|
|
||||||
{
|
|
||||||
mixerSPDIF->setVolume(value);
|
|
||||||
if (remember)
|
|
||||||
volumeSPDIF = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::muteMixers(bool m)
|
|
||||||
{
|
|
||||||
if (m && !mixersMuted)
|
|
||||||
{
|
|
||||||
mixersMuted = true;
|
|
||||||
setMixerVolume("Analog", 0, false);
|
|
||||||
setMixerVolume("HDMI", 0, false);
|
|
||||||
setMixerVolume("SPDIF", 0, false);
|
|
||||||
}
|
|
||||||
else if (!m && mixersMuted)
|
|
||||||
{
|
|
||||||
mixersMuted = false;
|
|
||||||
setMixerVolume("Analog", volumeAnalog, false);
|
|
||||||
setMixerVolume("HDMI", volumeHDMI, false);
|
|
||||||
setMixerVolume("SPDIF", volumeSPDIF, false);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,126 +0,0 @@
|
|||||||
/* public header file */
|
|
||||||
|
|
||||||
#ifndef __AUDIO_LIB_H__
|
|
||||||
#define __AUDIO_LIB_H__
|
|
||||||
|
|
||||||
#include "cs_types.h"
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
AUDIO_SYNC_WITH_PTS,
|
|
||||||
AUDIO_NO_SYNC,
|
|
||||||
AUDIO_SYNC_AUDIO_MASTER
|
|
||||||
} AUDIO_SYNC_MODE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
HDMI_ENCODED_OFF,
|
|
||||||
HDMI_ENCODED_AUTO,
|
|
||||||
HDMI_ENCODED_FORCED
|
|
||||||
} HDMI_ENCODED_MODE;
|
|
||||||
|
|
||||||
class mixerVolume;
|
|
||||||
|
|
||||||
class cAudio
|
|
||||||
{
|
|
||||||
friend class cPlayback;
|
|
||||||
private:
|
|
||||||
int fd;
|
|
||||||
unsigned int devnum;
|
|
||||||
bool Muted;
|
|
||||||
|
|
||||||
int clipfd; /* for pcm playback */
|
|
||||||
int mixer_fd; /* if we are using the OSS mixer */
|
|
||||||
int mixer_num; /* oss mixer to use, if any */
|
|
||||||
|
|
||||||
int StreamType;
|
|
||||||
AUDIO_SYNC_MODE SyncMode;
|
|
||||||
bool started;
|
|
||||||
|
|
||||||
int volume;
|
|
||||||
|
|
||||||
void openDevice(void);
|
|
||||||
void closeDevice(void);
|
|
||||||
|
|
||||||
int do_mute(bool enable, bool remember);
|
|
||||||
void setBypassMode(bool disable);
|
|
||||||
|
|
||||||
mixerVolume *mixerAnalog, *mixerHDMI, *mixerSPDIF;
|
|
||||||
int volumeAnalog, volumeHDMI, volumeSPDIF;
|
|
||||||
bool mixersMuted;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/* construct & destruct */
|
|
||||||
cAudio(void *, void *, void *, unsigned int unit = 0);
|
|
||||||
~cAudio(void);
|
|
||||||
|
|
||||||
void open_AVInput_Device(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
void close_AVInput_Device(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
void setAVInput(int val);
|
|
||||||
|
|
||||||
void *GetHandle()
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
};
|
|
||||||
/* shut up */
|
|
||||||
int mute(bool remember = true)
|
|
||||||
{
|
|
||||||
return do_mute(true, remember);
|
|
||||||
};
|
|
||||||
int unmute(bool remember = true)
|
|
||||||
{
|
|
||||||
return do_mute(false, remember);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* volume, min = 0, max = 255 */
|
|
||||||
int setVolume(unsigned int left, unsigned int right);
|
|
||||||
int getVolume(void)
|
|
||||||
{
|
|
||||||
return volume;
|
|
||||||
}
|
|
||||||
bool getMuteStatus(void)
|
|
||||||
{
|
|
||||||
return Muted;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* start and stop audio */
|
|
||||||
int Start(void);
|
|
||||||
int Stop(void);
|
|
||||||
bool Pause(bool Pcm = true);
|
|
||||||
void SetStreamType(int bypass);
|
|
||||||
int GetStreamType(void)
|
|
||||||
{
|
|
||||||
return StreamType;
|
|
||||||
}
|
|
||||||
void SetSyncMode(AVSYNC_TYPE Mode);
|
|
||||||
|
|
||||||
/* select channels */
|
|
||||||
int setChannel(int channel);
|
|
||||||
int PrepareClipPlay(int uNoOfChannels, int uSampleRate, int uBitsPerSample, int bLittleEndian);
|
|
||||||
int WriteClip(unsigned char *buffer, int size);
|
|
||||||
int StopClip();
|
|
||||||
void getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &mode);
|
|
||||||
void SetSRS(int iq_enable, int nmgr_enable, int iq_mode, int iq_level);
|
|
||||||
bool IsHdmiDDSupported()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
void SetHdmiDD(bool enable);
|
|
||||||
void SetSpdifDD(bool enable);
|
|
||||||
void ScheduleMute(bool On);
|
|
||||||
void EnableAnalogOut(bool enable);
|
|
||||||
|
|
||||||
void openMixers(void);
|
|
||||||
void closeMixers(void);
|
|
||||||
void setMixerVolume(const char *name, long value, bool remember = true);
|
|
||||||
void muteMixers(bool m = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __AUDIO_LIB_H__
|
|
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* audio_mixer.cpp
|
|
||||||
*
|
|
||||||
* (C) 2012 martii
|
|
||||||
*
|
|
||||||
* 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <audio_mixer.h>
|
|
||||||
|
|
||||||
mixerVolume::mixerVolume(const char *name, const char *card, long volume)
|
|
||||||
{
|
|
||||||
snd_mixer_selem_id_t *sid = NULL;
|
|
||||||
elem = NULL;
|
|
||||||
handle = NULL;
|
|
||||||
min = 0;
|
|
||||||
max = 100;
|
|
||||||
char cardId[10];
|
|
||||||
|
|
||||||
if (!name || !card)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int cx = snd_card_get_index(card);
|
|
||||||
if (cx < 0 || cx > 31)
|
|
||||||
return;
|
|
||||||
snprintf(cardId, sizeof(cardId), "hw:%i", cx);
|
|
||||||
|
|
||||||
if (0 > snd_mixer_open(&handle, 0))
|
|
||||||
return;
|
|
||||||
if (0 > snd_mixer_attach(handle, cardId))
|
|
||||||
return;
|
|
||||||
if (0 > snd_mixer_selem_register(handle, NULL, NULL))
|
|
||||||
return;
|
|
||||||
if (0 > snd_mixer_load(handle))
|
|
||||||
return;
|
|
||||||
snd_mixer_selem_id_alloca(&sid);
|
|
||||||
if (!sid)
|
|
||||||
return;
|
|
||||||
snd_mixer_selem_id_set_index(sid, 0);
|
|
||||||
snd_mixer_selem_id_set_name(sid, name);
|
|
||||||
elem = snd_mixer_find_selem(handle, sid);
|
|
||||||
if (elem)
|
|
||||||
{
|
|
||||||
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
|
|
||||||
setVolume(volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixerVolume::~mixerVolume()
|
|
||||||
{
|
|
||||||
if (handle)
|
|
||||||
snd_mixer_close(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mixerVolume::setVolume(long volume)
|
|
||||||
{
|
|
||||||
return elem
|
|
||||||
&& (volume > -1)
|
|
||||||
&& (volume < 101)
|
|
||||||
&& !snd_mixer_selem_set_playback_volume_all(elem, min + volume * (max - min) / 100);
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* audio_mixer.h
|
|
||||||
*
|
|
||||||
* (C) 2012 martii
|
|
||||||
*
|
|
||||||
* 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __AUDIO_MIXER_H__
|
|
||||||
#define __AUDIO_MIXER_H__
|
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
|
||||||
|
|
||||||
class mixerVolume
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
long min, max;
|
|
||||||
snd_mixer_t *handle;
|
|
||||||
snd_mixer_elem_t *elem;
|
|
||||||
public:
|
|
||||||
mixerVolume(const char *selem_name, const char *Card, long volume = -1);
|
|
||||||
~mixerVolume(void);
|
|
||||||
bool setVolume(long volume);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __AUDIO_MIXER_H__
|
|
660
libspark/dmx.cpp
660
libspark/dmx.cpp
@@ -1,660 +0,0 @@
|
|||||||
/*
|
|
||||||
* cDemux implementation for SH4 receivers (tested on fulan spark and
|
|
||||||
* fulan spark7162 hardware)
|
|
||||||
*
|
|
||||||
* (C) 2010-2013 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Theory of operation (or "why is this dmx_source thing so strange and
|
|
||||||
* what is the _open() good for?")
|
|
||||||
*
|
|
||||||
* the sh4 pti driver, driving the /dev/dvb/adapter0/dmxN devices, can
|
|
||||||
* apparently only map one input to on demux device at a time, so e.g.
|
|
||||||
* DMX_SOURCE_FRONT1 -> demux0
|
|
||||||
* DMX_SOURCE_FRONT2 -> demux0
|
|
||||||
* DMX_SOURCE_FRONT1 -> demux1
|
|
||||||
* does not work. The driver makes sure that a one-to-one mapping of
|
|
||||||
* DMX_SOURCE_FRONTn to demuxM is maintained, and it does by e.g changing
|
|
||||||
* the default of
|
|
||||||
* FRONT0 -> demux0
|
|
||||||
* FRONT1 -> demux1
|
|
||||||
* FRONT2 -> demux2
|
|
||||||
* to
|
|
||||||
* FRONT1 -> demux0
|
|
||||||
* FRONT0 -> demux1
|
|
||||||
* FRONT2 -> demux2
|
|
||||||
* if you do a DMX_SET_SOURCE(FRONT1) ioctl on demux0.
|
|
||||||
* This means, it also changes demux1's source on the SET_SOURCE ioctl on
|
|
||||||
* demux0, potentially disturbing any operation on demux1 (e.g. recording).
|
|
||||||
*
|
|
||||||
* In order to avoid this, I do not change the source->demuxdev mapping
|
|
||||||
* but instead just always use the demux device that is attached to the
|
|
||||||
* correct source.
|
|
||||||
*
|
|
||||||
* The tricky part is, that the source might actually be changed after
|
|
||||||
* Open() has been called, so Open() gets a dummy placeholder that just
|
|
||||||
* sets some variables while the real device open is put into _open().
|
|
||||||
* _open() gets called later, whenever the device is actually used or
|
|
||||||
* configured and -- if the source has changed -- closes the old and
|
|
||||||
* opens the correct new device node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <OpenThreads/Mutex>
|
|
||||||
#include <OpenThreads/ScopedLock>
|
|
||||||
#include "dmx_hal.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
|
|
||||||
#include "video_lib.h"
|
|
||||||
/* needed for getSTC... */
|
|
||||||
extern cVideo *videoDecoder;
|
|
||||||
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_DEMUX, this, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_DEMUX, this, args)
|
|
||||||
#define hal_debug_c(args...) _hal_debug(HAL_DEBUG_DEMUX, NULL, args)
|
|
||||||
#define hal_info_c(args...) _hal_info(HAL_DEBUG_DEMUX, NULL, args)
|
|
||||||
#define hal_info_z(args...) _hal_info(HAL_DEBUG_DEMUX, thiz, args)
|
|
||||||
#define hal_debug_z(args...) _hal_debug(HAL_DEBUG_DEMUX, thiz, args)
|
|
||||||
|
|
||||||
#define dmx_err(_errfmt, _errstr, _revents) do { \
|
|
||||||
hal_info("%s " _errfmt " fd:%d, ev:0x%x %s pid:0x%04hx flt:0x%02hx\n", \
|
|
||||||
__func__, _errstr, fd, _revents, DMX_T[dmx_type], pid, flt); \
|
|
||||||
} while(0);
|
|
||||||
|
|
||||||
cDemux *videoDemux = NULL;
|
|
||||||
cDemux *audioDemux = NULL;
|
|
||||||
//cDemux *pcrDemux = NULL;
|
|
||||||
|
|
||||||
static const char *DMX_T[] =
|
|
||||||
{
|
|
||||||
"DMX_INVALID",
|
|
||||||
"DMX_VIDEO",
|
|
||||||
"DMX_AUDIO",
|
|
||||||
"DMX_PES",
|
|
||||||
"DMX_PSI",
|
|
||||||
"DMX_PIP",
|
|
||||||
"DMX_TP",
|
|
||||||
"DMX_PCR"
|
|
||||||
};
|
|
||||||
|
|
||||||
/* this is the number of different cDemux() units, not the number of
|
|
||||||
* /dev/dvb/.../demuxX devices! */
|
|
||||||
#define NUM_DEMUX 4
|
|
||||||
/* the current source of each cDemux unit */
|
|
||||||
static int dmx_source[NUM_DEMUX] = { 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
char dmxdev[32];
|
|
||||||
static char *devname(int adapter, int demux)
|
|
||||||
{
|
|
||||||
snprintf(dmxdev, sizeof(dmxdev), "/dev/dvb/adapter%d/demux%d", adapter, demux);
|
|
||||||
return dmxdev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* map the device numbers. */
|
|
||||||
#define NUM_DEMUXDEV 3
|
|
||||||
|
|
||||||
/* did we already DMX_SET_SOURCE on that demux device? */
|
|
||||||
static bool init[NUM_DEMUXDEV] = { false, false, false };
|
|
||||||
|
|
||||||
typedef struct dmx_pdata
|
|
||||||
{
|
|
||||||
int last_source;
|
|
||||||
OpenThreads::Mutex *mutex;
|
|
||||||
} dmx_pdata;
|
|
||||||
#define P ((dmx_pdata *)pdata)
|
|
||||||
|
|
||||||
cDemux::cDemux(int n)
|
|
||||||
{
|
|
||||||
if (n < 0 || n >= NUM_DEMUX)
|
|
||||||
{
|
|
||||||
hal_info("%s ERROR: n invalid (%d)\n", __FUNCTION__, n);
|
|
||||||
num = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
num = n;
|
|
||||||
fd = -1;
|
|
||||||
pdata = (void *)calloc(1, sizeof(dmx_pdata));
|
|
||||||
P->last_source = -1;
|
|
||||||
P->mutex = new OpenThreads::Mutex;
|
|
||||||
dmx_type = DMX_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
cDemux::~cDemux()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d\n", __FUNCTION__, num, fd);
|
|
||||||
Close();
|
|
||||||
/* wait until Read() has released the mutex */
|
|
||||||
(*P->mutex).lock();
|
|
||||||
(*P->mutex).unlock();
|
|
||||||
free(P->mutex);
|
|
||||||
free(pdata);
|
|
||||||
pdata = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::Open(DMX_CHANNEL_TYPE pes_type, void * /*hVideoBuffer*/, int uBufferSize)
|
|
||||||
{
|
|
||||||
if (fd > -1)
|
|
||||||
hal_info("%s FD ALREADY OPENED? fd = %d\n", __FUNCTION__, fd);
|
|
||||||
|
|
||||||
dmx_type = pes_type;
|
|
||||||
buffersize = uBufferSize;
|
|
||||||
|
|
||||||
/* return code is unchecked anyway... */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _open(cDemux *thiz, int num, int &fd, int &last_source, DMX_CHANNEL_TYPE dmx_type, int buffersize)
|
|
||||||
{
|
|
||||||
int flags = O_RDWR | O_CLOEXEC;
|
|
||||||
int devnum = dmx_source[num];
|
|
||||||
if (last_source == devnum)
|
|
||||||
{
|
|
||||||
hal_debug_z("%s #%d: source (%d) did not change\n", __func__, num, last_source);
|
|
||||||
if (fd > -1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (fd > -1)
|
|
||||||
{
|
|
||||||
/* we changed source -> close and reopen the fd */
|
|
||||||
hal_debug_z("%s #%d: FD ALREADY OPENED fd = %d lastsource %d devnum %d\n",
|
|
||||||
__func__, num, fd, last_source, devnum);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dmx_type != DMX_PSI_CHANNEL)
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
|
|
||||||
fd = open(devname(0, devnum), flags);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info_z("%s %s: %m\n", __FUNCTION__, devname(0, devnum));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hal_debug_z("%s #%d pes_type: %s(%d), uBufferSize: %d fd: %d\n", __func__,
|
|
||||||
num, DMX_T[dmx_type], dmx_type, buffersize, fd);
|
|
||||||
|
|
||||||
/* this would actually need locking, but the worst that weill happen is, that
|
|
||||||
* we'll DMX_SET_SOURCE twice per device, so don't bother... */
|
|
||||||
if (!init[devnum])
|
|
||||||
{
|
|
||||||
/* this should not change anything... */
|
|
||||||
int n = DMX_SOURCE_FRONT0 + devnum;
|
|
||||||
hal_info_z("%s: setting %s to source %d\n", __func__, devname(0, devnum), n);
|
|
||||||
if (ioctl(fd, DMX_SET_SOURCE, &n) < 0)
|
|
||||||
hal_info_z("%s DMX_SET_SOURCE failed!\n", __func__);
|
|
||||||
else
|
|
||||||
init[devnum] = true;
|
|
||||||
}
|
|
||||||
if (buffersize == 0)
|
|
||||||
buffersize = 0xffff; // may or may not be reasonable --martii
|
|
||||||
if (buffersize > 0)
|
|
||||||
{
|
|
||||||
/* probably uBufferSize == 0 means "use default size". TODO: find a reasonable default */
|
|
||||||
if (ioctl(fd, DMX_SET_BUFFER_SIZE, buffersize) < 0)
|
|
||||||
hal_info_z("%s DMX_SET_BUFFER_SIZE failed (%m)\n", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
last_source = devnum;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::Close(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d, fd = %d\n", __FUNCTION__, num, fd);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pesfds.clear();
|
|
||||||
ioctl(fd, DMX_STOP);
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::Start(bool)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ioctl(fd, DMX_START);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::Stop(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ioctl(fd, DMX_STOP);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cDemux::Read(unsigned char *buff, int len, int timeout)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (len != 4095 && timeout != 10)
|
|
||||||
fprintf(stderr, "cDemux::%s #%d fd: %d type: %s len: %d timeout: %d\n",
|
|
||||||
__FUNCTION__, num, fd, DMX_T[dmx_type], len, timeout);
|
|
||||||
#endif
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __func__, num);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* avoid race in destructor: ~cDemux needs to wait until Read() returns */
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(*P->mutex);
|
|
||||||
int rc;
|
|
||||||
int to = timeout;
|
|
||||||
struct pollfd ufds;
|
|
||||||
ufds.fd = fd;
|
|
||||||
ufds.events = POLLIN | POLLPRI | POLLERR;
|
|
||||||
ufds.revents = 0;
|
|
||||||
|
|
||||||
/* hack: if the frontend loses and regains lock, the demuxer often will not
|
|
||||||
* return from read(), so as a "emergency exit" for e.g. NIT scan, set a (long)
|
|
||||||
* timeout here */
|
|
||||||
if (dmx_type == DMX_PSI_CHANNEL && timeout <= 0)
|
|
||||||
to = 60 * 1000;
|
|
||||||
|
|
||||||
if (to > 0)
|
|
||||||
{
|
|
||||||
retry:
|
|
||||||
rc = ::poll(&ufds, 1, to);
|
|
||||||
if (ufds.fd != fd)
|
|
||||||
{
|
|
||||||
/* Close() will set fd to -1, this is normal. Everything else is not. */
|
|
||||||
hal_info("%s:1 ========== fd has changed, %d->%d ==========\n", __func__, ufds.fd, fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!rc)
|
|
||||||
{
|
|
||||||
if (timeout == 0) /* we took the emergency exit */
|
|
||||||
{
|
|
||||||
dmx_err("timed out for timeout=0!, %s", "", 0);
|
|
||||||
return -1; /* this timeout is an error */
|
|
||||||
}
|
|
||||||
return 0; // timeout
|
|
||||||
}
|
|
||||||
else if (rc < 0)
|
|
||||||
{
|
|
||||||
dmx_err("poll: %s,", strerror(errno), 0)
|
|
||||||
//hal_info("%s poll: %m\n", __FUNCTION__);
|
|
||||||
/* happens, when running under gdb... */
|
|
||||||
if (errno == EINTR)
|
|
||||||
goto retry;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
if (ufds.revents & POLLERR) /* POLLERR means buffer error, i.e. buffer overflow */
|
|
||||||
{
|
|
||||||
dmx_err("received %s,", "POLLERR", ufds.revents);
|
|
||||||
/* this seems to happen sometimes at recording start, without bad effects */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (ufds.revents & POLLHUP) /* we get POLLHUP if e.g. a too big DMX_BUFFER_SIZE was set */
|
|
||||||
{
|
|
||||||
dmx_err("received %s,", "POLLHUP", ufds.revents);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!(ufds.revents & POLLIN)) /* we requested POLLIN but did not get it? */
|
|
||||||
{
|
|
||||||
dmx_err("received %s, please report!", "POLLIN", ufds.revents);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ufds.fd != fd) /* does this ever happen? and if, is it harmful? */
|
|
||||||
{
|
|
||||||
/* read(-1,...) will just return EBADF anyway... */
|
|
||||||
hal_info("%s:2 ========== fd has changed, %d->%d ==========\n", __func__, ufds.fd, fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ::read(fd, buff, len);
|
|
||||||
//fprintf(stderr, "fd %d ret: %d\n", fd, rc);
|
|
||||||
if (rc < 0)
|
|
||||||
dmx_err("read: %s", strerror(errno), 0);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::sectionFilter(unsigned short _pid, const unsigned char *const filter,
|
|
||||||
const unsigned char *const mask, int len, int timeout,
|
|
||||||
const unsigned char *const negmask)
|
|
||||||
{
|
|
||||||
struct dmx_sct_filter_params s_flt;
|
|
||||||
memset(&s_flt, 0, sizeof(s_flt));
|
|
||||||
pid = _pid;
|
|
||||||
|
|
||||||
_open(this, num, fd, P->last_source, dmx_type, buffersize);
|
|
||||||
|
|
||||||
if (len > DMX_FILTER_SIZE)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: len too long: %d, DMX_FILTER_SIZE %d\n", __func__, num, len, DMX_FILTER_SIZE);
|
|
||||||
len = DMX_FILTER_SIZE;
|
|
||||||
}
|
|
||||||
flt = filter[0];
|
|
||||||
s_flt.pid = pid;
|
|
||||||
s_flt.timeout = timeout;
|
|
||||||
memcpy(s_flt.filter.filter, filter, len);
|
|
||||||
memcpy(s_flt.filter.mask, mask, len);
|
|
||||||
if (negmask != NULL)
|
|
||||||
memcpy(s_flt.filter.mode, negmask, len);
|
|
||||||
|
|
||||||
s_flt.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
|
|
||||||
|
|
||||||
int to = 0;
|
|
||||||
switch (filter[0])
|
|
||||||
{
|
|
||||||
case 0x00: /* program_association_section */
|
|
||||||
to = 2000;
|
|
||||||
break;
|
|
||||||
case 0x01: /* conditional_access_section */
|
|
||||||
to = 6000;
|
|
||||||
break;
|
|
||||||
case 0x02: /* program_map_section */
|
|
||||||
to = 1500;
|
|
||||||
break;
|
|
||||||
case 0x03: /* transport_stream_description_section */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x04 - 0x3F: reserved */
|
|
||||||
case 0x40: /* network_information_section - actual_network */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
case 0x41: /* network_information_section - other_network */
|
|
||||||
to = 15000;
|
|
||||||
break;
|
|
||||||
case 0x42: /* service_description_section - actual_transport_stream */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x43 - 0x45: reserved for future use */
|
|
||||||
case 0x46: /* service_description_section - other_transport_stream */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x47 - 0x49: reserved for future use */
|
|
||||||
case 0x4A: /* bouquet_association_section */
|
|
||||||
to = 11000;
|
|
||||||
break;
|
|
||||||
/* 0x4B - 0x4D: reserved for future use */
|
|
||||||
case 0x4E: /* event_information_section - actual_transport_stream, present/following */
|
|
||||||
to = 2000;
|
|
||||||
break;
|
|
||||||
case 0x4F: /* event_information_section - other_transport_stream, present/following */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x50 - 0x5F: event_information_section - actual_transport_stream, schedule */
|
|
||||||
/* 0x60 - 0x6F: event_information_section - other_transport_stream, schedule */
|
|
||||||
case 0x70: /* time_date_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
s_flt.flags |= DMX_ONESHOT;
|
|
||||||
//s_flt.pid = 0x0014;
|
|
||||||
to = 30000;
|
|
||||||
break;
|
|
||||||
case 0x71: /* running_status_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x72: /* stuffing_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x73: /* time_offset_section */
|
|
||||||
s_flt.flags |= DMX_ONESHOT;
|
|
||||||
//s_flt.pid = 0x0014;
|
|
||||||
to = 30000;
|
|
||||||
break;
|
|
||||||
/* 0x74 - 0x7D: reserved for future use */
|
|
||||||
case 0x7E: /* discontinuity_information_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x7F: /* selection_information_section */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
/* 0x80 - 0x8F: ca_message_section */
|
|
||||||
/* 0x90 - 0xFE: user defined */
|
|
||||||
/* 0xFF: reserved */
|
|
||||||
default:
|
|
||||||
//return -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* the negmask == NULL is a hack: the users of negmask are PMT-update
|
|
||||||
* and sectionsd EIT-Version change. And they really want no timeout
|
|
||||||
* if timeout == 0 instead of "default timeout" */
|
|
||||||
if (timeout == 0 && negmask == NULL)
|
|
||||||
s_flt.timeout = to;
|
|
||||||
|
|
||||||
hal_debug("%s #%d pid:0x%04hx fd:%d type:%s len:%d to:%d flags:%x flt[0]:%02x\n", __func__, num,
|
|
||||||
pid, fd, DMX_T[dmx_type], len, s_flt.timeout, s_flt.flags, s_flt.filter.filter[0]);
|
|
||||||
|
|
||||||
if (debuglevel == 2)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "filt: ");
|
|
||||||
for (int i = 0; i < len; i++) fprintf(stderr, "%02hhx ", s_flt.filter.filter[i]);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
fprintf(stderr, "mask: ");
|
|
||||||
for (int i = 0; i < len; i++) fprintf(stderr, "%02hhx ", s_flt.filter.mask [i]);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
fprintf(stderr, "mode: ");
|
|
||||||
for (int i = 0; i < len; i++) fprintf(stderr, "%02hhx ", s_flt.filter.mode [i]);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
ioctl(fd, DMX_STOP);
|
|
||||||
if (ioctl(fd, DMX_SET_FILTER, &s_flt) < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::pesFilter(const unsigned short _pid)
|
|
||||||
{
|
|
||||||
struct dmx_pes_filter_params p_flt;
|
|
||||||
pid = _pid;
|
|
||||||
flt = 0;
|
|
||||||
/* allow PID 0 for web streaming e.g.
|
|
||||||
* this check originally is from tuxbox cvs but I'm not sure
|
|
||||||
* what it is good for...
|
|
||||||
if (pid <= 0x0001 && dmx_type != DMX_PCR_ONLY_CHANNEL)
|
|
||||||
return false;
|
|
||||||
*/
|
|
||||||
if ((pid >= 0x0002 && pid <= 0x000f) || pid >= 0x1fff)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
hal_debug("%s #%d pid: 0x%04hx fd: %d type: %s\n", __FUNCTION__, num, pid, fd, DMX_T[dmx_type]);
|
|
||||||
|
|
||||||
_open(this, num, fd, P->last_source, dmx_type, buffersize);
|
|
||||||
|
|
||||||
memset(&p_flt, 0, sizeof(p_flt));
|
|
||||||
p_flt.pid = pid;
|
|
||||||
p_flt.input = DMX_IN_FRONTEND;
|
|
||||||
p_flt.output = DMX_OUT_DECODER;
|
|
||||||
p_flt.flags = DMX_IMMEDIATE_START;
|
|
||||||
|
|
||||||
switch (dmx_type)
|
|
||||||
{
|
|
||||||
case DMX_VIDEO_CHANNEL:
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0: p_flt.pes_type = DMX_PES_VIDEO0; break;
|
|
||||||
case 1: p_flt.pes_type = DMX_PES_VIDEO1; break;
|
|
||||||
case 2: p_flt.pes_type = DMX_PES_VIDEO2; break;
|
|
||||||
case 3: p_flt.pes_type = DMX_PES_VIDEO3; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DMX_AUDIO_CHANNEL:
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0: p_flt.pes_type = DMX_PES_AUDIO0; break;
|
|
||||||
case 1: p_flt.pes_type = DMX_PES_AUDIO1; break;
|
|
||||||
case 2: p_flt.pes_type = DMX_PES_AUDIO2; break;
|
|
||||||
case 3: p_flt.pes_type = DMX_PES_AUDIO3; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DMX_PES_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_OTHER;
|
|
||||||
p_flt.output = DMX_OUT_TAP;
|
|
||||||
break;
|
|
||||||
#if 0
|
|
||||||
case DMX_PSI_CHANNEL:
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case DMX_TP_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_OTHER;
|
|
||||||
p_flt.output = DMX_OUT_TSDEMUX_TAP;
|
|
||||||
break;
|
|
||||||
case DMX_PCR_ONLY_CHANNEL:
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0: p_flt.pes_type = DMX_PES_PCR0; break;
|
|
||||||
case 1: p_flt.pes_type = DMX_PES_PCR1; break;
|
|
||||||
case 2: p_flt.pes_type = DMX_PES_PCR2; break;
|
|
||||||
case 3: p_flt.pes_type = DMX_PES_PCR3; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hal_info("%s #%d invalid dmx_type %d!\n", __func__, num, dmx_type);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (ioctl(fd, DMX_SET_PES_FILTER, &p_flt) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::SetSyncMode(AVSYNC_TYPE /*mode*/)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cDemux::getBuffer()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cDemux::getChannel()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::addPid(unsigned short Pid)
|
|
||||||
{
|
|
||||||
hal_debug("%s: pid 0x%04hx\n", __func__, Pid);
|
|
||||||
pes_pids pfd;
|
|
||||||
int ret;
|
|
||||||
if (dmx_type != DMX_TP_CHANNEL)
|
|
||||||
{
|
|
||||||
hal_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_open(this, num, fd, P->last_source, dmx_type, buffersize);
|
|
||||||
if (fd == -1)
|
|
||||||
hal_info("%s bucketfd not yet opened? pid=%hx\n", __FUNCTION__, Pid);
|
|
||||||
pfd.fd = fd; /* dummy */
|
|
||||||
pfd.pid = Pid;
|
|
||||||
pesfds.push_back(pfd);
|
|
||||||
ret = (ioctl(fd, DMX_ADD_PID, &Pid));
|
|
||||||
if (ret < 0)
|
|
||||||
hal_info("%s: DMX_ADD_PID (%m) pid=%hx\n", __func__, Pid);
|
|
||||||
return (ret != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::removePid(unsigned short Pid)
|
|
||||||
{
|
|
||||||
if (dmx_type != DMX_TP_CHANNEL)
|
|
||||||
{
|
|
||||||
hal_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (std::vector<pes_pids>::iterator i = pesfds.begin(); i != pesfds.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i).pid == Pid)
|
|
||||||
{
|
|
||||||
hal_debug("removePid: removing demux fd %d pid 0x%04x\n", fd, Pid);
|
|
||||||
if (ioctl(fd, DMX_REMOVE_PID, Pid) < 0)
|
|
||||||
hal_info("%s: (DMX_REMOVE_PID, 0x%04hx): %m\n", __func__, Pid);
|
|
||||||
pesfds.erase(i);
|
|
||||||
return; /* TODO: what if the same PID is there multiple times */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hal_info("%s pid 0x%04x not found\n", __FUNCTION__, Pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::getSTC(int64_t *STC)
|
|
||||||
{
|
|
||||||
/* apparently I can only get the PTS of the video decoder,
|
|
||||||
* but that's good enough for dvbsub */
|
|
||||||
hal_debug("%s #%d\n", __func__, num);
|
|
||||||
int64_t pts = 0;
|
|
||||||
if (videoDecoder)
|
|
||||||
pts = videoDecoder->GetPTS();
|
|
||||||
*STC = pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cDemux::getUnit(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
/* just guessed that this is the right thing to do.
|
|
||||||
right now this is only used by the CA code which is stubbed out
|
|
||||||
anyway */
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::SetSource(int unit, int source)
|
|
||||||
{
|
|
||||||
if (unit >= NUM_DEMUX || unit < 0)
|
|
||||||
{
|
|
||||||
hal_info_c("%s: unit (%d) out of range, NUM_DEMUX %d\n", __func__, unit, NUM_DEMUX);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hal_debug_c("%s(%d, %d) => %d to %d\n", __func__, unit, source, dmx_source[unit], source);
|
|
||||||
if (source < 0 || source >= NUM_DEMUXDEV)
|
|
||||||
hal_info_c("%s(%d, %d) ERROR: source %d out of range!\n", __func__, unit, source, source);
|
|
||||||
else
|
|
||||||
dmx_source[unit] = source;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cDemux::GetSource(int unit)
|
|
||||||
{
|
|
||||||
if (unit >= NUM_DEMUX || unit < 0)
|
|
||||||
{
|
|
||||||
hal_info_c("%s: unit (%d) out of range, NUM_DEMUX %d\n", __func__, unit, NUM_DEMUX);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
hal_debug_c("%s(%d) => %d\n", __func__, unit, dmx_source[unit]);
|
|
||||||
return dmx_source[unit];
|
|
||||||
}
|
|
@@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
* determine the capabilities of the hardware.
|
|
||||||
* part of libstb-hal
|
|
||||||
*
|
|
||||||
* (C) 2010-2012 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* License: GPL v2 or later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <aotom_main.h>
|
|
||||||
|
|
||||||
#include <hardware_caps.h>
|
|
||||||
|
|
||||||
#define FP_DEV "/dev/vfd"
|
|
||||||
static int initialized = 0;
|
|
||||||
static hw_caps_t caps;
|
|
||||||
|
|
||||||
hw_caps_t *get_hwcaps(void)
|
|
||||||
{
|
|
||||||
if (initialized)
|
|
||||||
return ∩︀
|
|
||||||
|
|
||||||
memset(&caps, 0, sizeof(hw_caps_t));
|
|
||||||
|
|
||||||
caps.pip_devs = 0;
|
|
||||||
if (access("/dev/dvb/adapter0/video1", F_OK) != -1) caps.pip_devs = 1;
|
|
||||||
if (access("/dev/dvb/adapter0/video2", F_OK) != -1) caps.pip_devs = 2;
|
|
||||||
if (access("/dev/dvb/adapter0/video3", F_OK) != -1) caps.pip_devs = 3;
|
|
||||||
if (caps.pip_devs > 0) caps.can_pip = 1;
|
|
||||||
|
|
||||||
caps.has_CI = 0;
|
|
||||||
caps.can_cec = 1;
|
|
||||||
caps.can_cpufreq = 1;
|
|
||||||
caps.can_shutdown = 1;
|
|
||||||
caps.display_type = HW_DISPLAY_LED_NUM;
|
|
||||||
caps.display_can_deepstandby = 0;
|
|
||||||
caps.display_can_set_brightness = 0;
|
|
||||||
caps.display_can_umlauts = 0;
|
|
||||||
caps.display_has_statusline = 0;
|
|
||||||
caps.display_has_colon = 1;
|
|
||||||
caps.has_HDMI = 1;
|
|
||||||
caps.has_SCART = 1;
|
|
||||||
caps.display_xres = 4;
|
|
||||||
strcpy(caps.boxvendor, "SPARK");
|
|
||||||
const char *tmp;
|
|
||||||
char buf[1024];
|
|
||||||
int len = -1, ret, val;
|
|
||||||
int fd = open(FP_DEV, O_RDWR);
|
|
||||||
if (fd != -1)
|
|
||||||
{
|
|
||||||
ret = ioctl(fd, VFDGETVERSION, &val);
|
|
||||||
if (ret < 0)
|
|
||||||
fprintf(stderr, "[hardware_caps] %s: VFDGETVERSION %m\n", __func__);
|
|
||||||
else if (val & 1) /* VFD = 1, DVFD = 3 */
|
|
||||||
{
|
|
||||||
caps.display_type = HW_DISPLAY_LINE_TEXT;
|
|
||||||
caps.display_can_umlauts = 0; /* need test */
|
|
||||||
caps.display_xres = 8;
|
|
||||||
caps.display_can_set_brightness = 1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
fd = open("/proc/cmdline", O_RDONLY);
|
|
||||||
if (fd != -1)
|
|
||||||
{
|
|
||||||
len = read(fd, buf, sizeof(buf) - 1);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
buf[len] = 0;
|
|
||||||
char *p = strstr(buf, "STB_ID=");
|
|
||||||
int h0, h1, h2;
|
|
||||||
if (p && sscanf(p, "STB_ID=%x:%x:%x:", &h0, &h1, &h2) == 3)
|
|
||||||
{
|
|
||||||
int sys_id = (h0 << 16) | (h1 << 8) | h2;
|
|
||||||
switch (sys_id)
|
|
||||||
{
|
|
||||||
case 0x090003:
|
|
||||||
tmp = "Truman Premier 1+";
|
|
||||||
break;
|
|
||||||
case 0x090007:
|
|
||||||
tmp = "GoldenMedia GM990";
|
|
||||||
break;
|
|
||||||
case 0x090008:
|
|
||||||
tmp = "Edision Pingulux";
|
|
||||||
if (caps.display_type == HW_DISPLAY_LINE_TEXT)
|
|
||||||
tmp = "Edision Pingulux Plus";
|
|
||||||
break;
|
|
||||||
case 0x09000a:
|
|
||||||
tmp = "Amiko Alien SDH8900";
|
|
||||||
break;
|
|
||||||
case 0x09000b:
|
|
||||||
tmp = "GalaxyInnovations S8120";
|
|
||||||
break;
|
|
||||||
case 0x09000d:
|
|
||||||
tmp = "Dynavision Spark";
|
|
||||||
break;
|
|
||||||
case 0x09000e:
|
|
||||||
tmp = "SAB Unix F+ Solo (S902)";
|
|
||||||
break;
|
|
||||||
case 0x090015:
|
|
||||||
tmp = "Superbox S 750 HD";
|
|
||||||
break;
|
|
||||||
case 0x09001d:
|
|
||||||
tmp = "Fulan Spark I+";
|
|
||||||
break;
|
|
||||||
case 0x090020:
|
|
||||||
tmp = "SAMSAT LINUX 1";
|
|
||||||
break;
|
|
||||||
case 0x090021:
|
|
||||||
tmp = "Visionnet Hammer 5400"; // or Startrack SRT 2020 HD, or Visionnet Fireball 101
|
|
||||||
break;
|
|
||||||
case 0x090043:
|
|
||||||
tmp = "Sogno Spark Revolution";
|
|
||||||
break;
|
|
||||||
case 0x0c0003:
|
|
||||||
tmp = "Truman Top Box 2";
|
|
||||||
break;
|
|
||||||
case 0x0c0004:
|
|
||||||
tmp = "Delta";
|
|
||||||
break;
|
|
||||||
case 0x0c0007:
|
|
||||||
tmp = "GoldenMedia Triplex";
|
|
||||||
break;
|
|
||||||
case 0x0c000a:
|
|
||||||
tmp = "Amiko Alien 2";
|
|
||||||
break;
|
|
||||||
case 0x0c000b:
|
|
||||||
tmp = "GalaxyInnovations Avatar 3 (8820)";
|
|
||||||
break;
|
|
||||||
case 0x0c000d:
|
|
||||||
tmp = "Dynavision 7162";
|
|
||||||
break;
|
|
||||||
case 0x0c000e:
|
|
||||||
tmp = "SAB Unix Triple HD (S903)";
|
|
||||||
break;
|
|
||||||
case 0x0c0015:
|
|
||||||
tmp = "Superbox Z500";
|
|
||||||
break;
|
|
||||||
case 0x0c001d:
|
|
||||||
tmp = "Satcom 7162";
|
|
||||||
break;
|
|
||||||
case 0x0c0020:
|
|
||||||
tmp = "Samsat 7162";
|
|
||||||
break;
|
|
||||||
case 0x0c0021:
|
|
||||||
tmp = "Visionnet Falcon";
|
|
||||||
break;
|
|
||||||
case 0x0c002b:
|
|
||||||
tmp = "Icecrypt S3700 CHD";
|
|
||||||
break;
|
|
||||||
case 0x0c0043:
|
|
||||||
tmp = "Sogno Spark Triple";
|
|
||||||
break;
|
|
||||||
case 0x0c0045:
|
|
||||||
tmp = "Interstar";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tmp = p;
|
|
||||||
}
|
|
||||||
if ((sys_id & 0xff0000) == 0x090000) {
|
|
||||||
caps.boxtype = 7111;
|
|
||||||
strcpy(caps.boxarch, "STX7111");
|
|
||||||
} else {
|
|
||||||
caps.boxtype = 7162;
|
|
||||||
strcpy(caps.boxarch, "STX7105");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tmp = "(NO STB_ID FOUND)";
|
|
||||||
strcpy(caps.boxname, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = 1;
|
|
||||||
return ∩︀
|
|
||||||
}
|
|
@@ -1,348 +0,0 @@
|
|||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <linux/dvb/dmx.h>
|
|
||||||
|
|
||||||
#include "init.h"
|
|
||||||
#include "pwrmngr.h"
|
|
||||||
|
|
||||||
#include "hal_debug.h"
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_INIT, NULL, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_INIT, NULL, args)
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define VIRTUALINPUT "/sys/devices/virtual/input"
|
|
||||||
#define DEVINPUT "/dev/input"
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
const char *desc;
|
|
||||||
int fd;
|
|
||||||
unsigned int major;
|
|
||||||
unsigned int minor;
|
|
||||||
time_t next_discovery;
|
|
||||||
} input_device_t;
|
|
||||||
|
|
||||||
static input_device_t input_device[] =
|
|
||||||
{
|
|
||||||
{ "/dev/input/nevis_ir", "lircd", -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/tdt_rc", "TDT RC event driver", -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/fulan_fp", "fulan front panel buttons", -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event0", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event1", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event2", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event3", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event4", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event5", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event6", NULL, -1, 0, 0, 0 },
|
|
||||||
{ "/dev/input/event7", NULL, -1, 0, 0, 0 },
|
|
||||||
{ NULL, NULL, -1, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
#define number_of_input_devices (sizeof(input_device)/sizeof(input_device_t) - 1)
|
|
||||||
|
|
||||||
static void do_mknod(int i, char *d_name)
|
|
||||||
{
|
|
||||||
char name[255];
|
|
||||||
int dev = -1;
|
|
||||||
// I've no idea how the event device number is actually calculated. Just loop. --martii
|
|
||||||
|
|
||||||
for (int j = 0; j < 99 && dev < 0; j++)
|
|
||||||
{
|
|
||||||
snprintf(name, sizeof(name), VIRTUALINPUT "/%s/event%d/dev", d_name, j);
|
|
||||||
dev = open(name, O_RDONLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev > -1)
|
|
||||||
{
|
|
||||||
char buf[255];
|
|
||||||
int l = read(dev, buf, sizeof(buf) - 1);
|
|
||||||
close(dev);
|
|
||||||
if (l > -1)
|
|
||||||
{
|
|
||||||
buf[l] = 0;
|
|
||||||
if (2 == sscanf(buf, "%d:%d", &input_device[i].major, &input_device[i].minor))
|
|
||||||
{
|
|
||||||
mknod(input_device[i].name, 0666 | S_IFCHR,
|
|
||||||
gnu_dev_makedev(input_device[i].major, input_device[i].minor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void create_input_devices(void)
|
|
||||||
{
|
|
||||||
DIR *d = opendir(VIRTUALINPUT);
|
|
||||||
if (d)
|
|
||||||
{
|
|
||||||
struct dirent *e;
|
|
||||||
while ((e = readdir(d)))
|
|
||||||
{
|
|
||||||
char name[255];
|
|
||||||
if (e->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
snprintf(name, sizeof(name), VIRTUALINPUT "/%s/name", e->d_name);
|
|
||||||
int n = open(name, O_RDONLY);
|
|
||||||
if (n > -1)
|
|
||||||
{
|
|
||||||
char buf[255];
|
|
||||||
int l = read(n, buf, sizeof(buf) - 1);
|
|
||||||
close(n);
|
|
||||||
if (l > 1)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
buf[l--] = 0;
|
|
||||||
while (l > 1 && buf[l] == '\n');
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < number_of_input_devices; i++)
|
|
||||||
if (input_device[i].desc && !strcmp(buf, input_device[i].desc))
|
|
||||||
{
|
|
||||||
do_mknod(i, e->d_name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
}
|
|
||||||
// remove any event* files left that point to our "well-known" inputs
|
|
||||||
d = opendir(DEVINPUT);
|
|
||||||
if (d)
|
|
||||||
{
|
|
||||||
struct dirent *e;
|
|
||||||
while ((e = readdir(d)))
|
|
||||||
{
|
|
||||||
char name[255];
|
|
||||||
if (strncmp(e->d_name, "event", 5))
|
|
||||||
continue;
|
|
||||||
snprintf(name, sizeof(name), DEVINPUT "/%s", e->d_name);
|
|
||||||
struct stat st;
|
|
||||||
if (stat(name, &st))
|
|
||||||
continue;
|
|
||||||
for (unsigned int i = 0; i < number_of_input_devices; i++)
|
|
||||||
if (input_device[i].major &&
|
|
||||||
gnu_dev_major(st.st_rdev) == input_device[i].major &&
|
|
||||||
gnu_dev_minor(st.st_rdev) == input_device[i].minor)
|
|
||||||
unlink(name);
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static pthread_t inmux_task = 0;
|
|
||||||
static int inmux_thread_running = 0;
|
|
||||||
|
|
||||||
static void open_input_devices(void)
|
|
||||||
{
|
|
||||||
time_t now = time(NULL);
|
|
||||||
for (unsigned int i = 0; i < number_of_input_devices; i++)
|
|
||||||
if ((input_device[i].fd < 0) && (input_device[i].next_discovery <= now))
|
|
||||||
{
|
|
||||||
input_device[i].next_discovery = now + 60;
|
|
||||||
input_device[i].fd = open(input_device[i].name, O_RDWR | O_NONBLOCK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reopen_input_devices(void)
|
|
||||||
{
|
|
||||||
create_input_devices();
|
|
||||||
time_t now = time(NULL);
|
|
||||||
for (unsigned int i = 0; i < number_of_input_devices; i++)
|
|
||||||
{
|
|
||||||
input_device[i].next_discovery = now + 60;
|
|
||||||
int fd = open(input_device[i].name, O_RDWR | O_NONBLOCK);
|
|
||||||
if (fd > -1)
|
|
||||||
{
|
|
||||||
if (input_device[i].fd > -1)
|
|
||||||
{
|
|
||||||
dup2(fd, input_device[i].fd);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
input_device[i].fd = fd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (input_device[i].fd > -1)
|
|
||||||
{
|
|
||||||
close(input_device[i].fd);
|
|
||||||
input_device[i].fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_input_devices(void)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < number_of_input_devices; i++)
|
|
||||||
if (input_device[i].fd > -1)
|
|
||||||
{
|
|
||||||
close(input_device[i].fd);
|
|
||||||
input_device[i].fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void poll_input_devices(void)
|
|
||||||
{
|
|
||||||
struct pollfd fds[number_of_input_devices];
|
|
||||||
input_device_t *inputs[number_of_input_devices];
|
|
||||||
int nfds = 0;
|
|
||||||
for (unsigned int i = 1; i < number_of_input_devices; i++)
|
|
||||||
if (input_device[i].fd > -1)
|
|
||||||
{
|
|
||||||
fds[nfds].fd = input_device[i].fd;
|
|
||||||
fds[nfds].events = POLLIN | POLLHUP | POLLERR;
|
|
||||||
fds[nfds].revents = 0;
|
|
||||||
inputs[nfds] = &input_device[i];
|
|
||||||
nfds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nfds == 0)
|
|
||||||
{
|
|
||||||
// Only a single input device, which happens to be our master. poll() to avoid looping too fast.
|
|
||||||
fds[0].fd = input_device[0].fd;
|
|
||||||
fds[0].events = POLLIN | POLLHUP | POLLERR;
|
|
||||||
fds[0].revents = 0;
|
|
||||||
poll(fds, 1, 60000 /* ms */);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int r = poll(fds, nfds, 60000 /* ms */);
|
|
||||||
if (r < 0)
|
|
||||||
{
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
{
|
|
||||||
hal_info("%s: poll(): %m\n", __func__);
|
|
||||||
inmux_thread_running = 0;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < nfds && r > 0; i++)
|
|
||||||
{
|
|
||||||
if (fds[i].revents & POLLIN)
|
|
||||||
{
|
|
||||||
//fprintf(stderr, "### input from fd %d (%s)\n", fds[i].fd, inputs[i]->name);
|
|
||||||
struct input_event ev;
|
|
||||||
while (sizeof(ev) == read(fds[i].fd, &ev, sizeof(ev)))
|
|
||||||
write(input_device[0].fd, &ev, sizeof(ev));
|
|
||||||
r--;
|
|
||||||
}
|
|
||||||
else if (fds[i].revents & (POLLHUP | POLLERR | POLLNVAL))
|
|
||||||
{
|
|
||||||
//fprintf(stderr, "### error on %d (%s)\n", fds[i].fd, inputs[i]->name);
|
|
||||||
close(fds[i].fd);
|
|
||||||
inputs[i]->fd = -1;
|
|
||||||
r--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *inmux_thread(void *)
|
|
||||||
{
|
|
||||||
char threadname[17];
|
|
||||||
strncpy(threadname, __func__, sizeof(threadname));
|
|
||||||
threadname[16] = 0;
|
|
||||||
prctl(PR_SET_NAME, (unsigned long)&threadname);
|
|
||||||
|
|
||||||
inmux_thread_running = 1;
|
|
||||||
while (inmux_thread_running)
|
|
||||||
{
|
|
||||||
open_input_devices();
|
|
||||||
poll_input_devices();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start_inmux_thread(void)
|
|
||||||
{
|
|
||||||
input_device[0].fd = open(input_device[0].name, O_RDWR | O_NONBLOCK); // nevis_ir. This is mandatory.
|
|
||||||
if (input_device[0].fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: open(%s): %m\n", __func__, input_device[0].name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (pthread_create(&inmux_task, 0, inmux_thread, NULL) != 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: inmux thread pthread_create: %m\n", __func__);
|
|
||||||
inmux_thread_running = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pthread_detach(inmux_task);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_inmux_thread(void)
|
|
||||||
{
|
|
||||||
inmux_thread_running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool initialized = false;
|
|
||||||
|
|
||||||
void hal_api_init()
|
|
||||||
{
|
|
||||||
if (!initialized)
|
|
||||||
hal_debug_init();
|
|
||||||
hal_info("%s begin, initialized=%d, debug=0x%02x\n", __FUNCTION__, (int)initialized, debuglevel);
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
cCpuFreqManager f;
|
|
||||||
f.SetCpuFreq(0); /* CPUFREQ == 0 is the trigger for leaving standby */
|
|
||||||
create_input_devices();
|
|
||||||
start_inmux_thread();
|
|
||||||
|
|
||||||
/* this is a strange hack: the drivers seem to only work correctly after
|
|
||||||
* demux0 has been used once. After that, we can use demux1,2,... */
|
|
||||||
struct dmx_pes_filter_params p;
|
|
||||||
int dmx = open("/dev/dvb/adapter0/demux0", O_RDWR | O_CLOEXEC);
|
|
||||||
if (dmx < 0)
|
|
||||||
hal_info("%s: ERROR open /dev/dvb/adapter0/demux0 (%m)\n", __func__);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(&p, 0, sizeof(p));
|
|
||||||
p.output = DMX_OUT_DECODER;
|
|
||||||
p.input = DMX_IN_FRONTEND;
|
|
||||||
p.flags = DMX_IMMEDIATE_START;
|
|
||||||
p.pes_type = DMX_PES_VIDEO;
|
|
||||||
ioctl(dmx, DMX_SET_PES_FILTER, &p);
|
|
||||||
ioctl(dmx, DMX_STOP);
|
|
||||||
close(dmx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reopen_input_devices();
|
|
||||||
initialized = true;
|
|
||||||
hal_info("%s end\n", __FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hal_api_exit()
|
|
||||||
{
|
|
||||||
hal_info("%s, initialized = %d\n", __FUNCTION__, (int)initialized);
|
|
||||||
if (initialized)
|
|
||||||
{
|
|
||||||
stop_inmux_thread();
|
|
||||||
close_input_devices();
|
|
||||||
}
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
4474
libspark/irmp.c
4474
libspark/irmp.c
File diff suppressed because it is too large
Load Diff
528
libspark/irmp.h
528
libspark/irmp.h
@@ -1,528 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* irmp.h
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009-2011 Frank Meyer - frank(at)fli4l.de
|
|
||||||
*
|
|
||||||
* $Id: irmp.h,v 1.70 2012/02/21 08:41:46 fm Exp $
|
|
||||||
*
|
|
||||||
* ATMEGA88 @ 8 MHz
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _WC_IRMP_H_
|
|
||||||
#define _WC_IRMP_H_
|
|
||||||
|
|
||||||
#if defined(__18CXX) // Microchip C18 declaration of missing typedef
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef unsigned int uint16_t;
|
|
||||||
#endif //Microchip C18
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* timing constants:
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
// fm 22.09.2011: may not be more than 16000L, otherwise some JVC codes will not be accepted
|
|
||||||
#define IRMP_TIMEOUT_TIME 15500.0e-6 // timeout after 15.5 ms darkness
|
|
||||||
#define IRMP_TIMEOUT_TIME_MS 15500L // timeout after 15.5 ms darkness
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_NIKON_PROTOCOL == 1
|
|
||||||
#define IRMP_TIMEOUT_NIKON_TIME 29500.0e-6 // 2nd timeout after 29.5 ms darkness (only for NIKON!)
|
|
||||||
#define IRMP_TIMEOUT_NIKON_TIME_MS 29500L // 2nd timeout after 29.5 ms darkness
|
|
||||||
typedef uint16_t PAUSE_LEN;
|
|
||||||
#define IRMP_TIMEOUT_NIKON_LEN (PAUSE_LEN)(F_INTERRUPTS * IRMP_TIMEOUT_NIKON_TIME + 0.5)
|
|
||||||
#else
|
|
||||||
#if (F_INTERRUPTS * IRMP_TIMEOUT_TIME_MS) / 1000000 >= 254
|
|
||||||
typedef uint16_t PAUSE_LEN;
|
|
||||||
#else
|
|
||||||
typedef uint8_t PAUSE_LEN;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IRMP_TIMEOUT_LEN (PAUSE_LEN)(F_INTERRUPTS * IRMP_TIMEOUT_TIME + 0.5)
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* IR protocols
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#define IRMP_SIRCS_PROTOCOL 1 // Sony
|
|
||||||
#define IRMP_NEC_PROTOCOL 2 // NEC, Pioneer, JVC, Toshiba, NoName etc.
|
|
||||||
#define IRMP_SAMSUNG_PROTOCOL 3 // Samsung
|
|
||||||
#define IRMP_MATSUSHITA_PROTOCOL 4 // Matsushita
|
|
||||||
#define IRMP_KASEIKYO_PROTOCOL 5 // Kaseikyo (Panasonic etc)
|
|
||||||
#define IRMP_RECS80_PROTOCOL 6 // Philips, Thomson, Nordmende, Telefunken, Saba
|
|
||||||
#define IRMP_RC5_PROTOCOL 7 // Philips etc
|
|
||||||
#define IRMP_DENON_PROTOCOL 8 // Denon, Sharp
|
|
||||||
#define IRMP_RC6_PROTOCOL 9 // Philips etc
|
|
||||||
#define IRMP_SAMSUNG32_PROTOCOL 10 // Samsung32: no sync pulse at bit 16, length 32 instead of 37
|
|
||||||
#define IRMP_APPLE_PROTOCOL 11 // Apple, very similar to NEC
|
|
||||||
#define IRMP_RECS80EXT_PROTOCOL 12 // Philips, Technisat, Thomson, Nordmende, Telefunken, Saba
|
|
||||||
#define IRMP_NUBERT_PROTOCOL 13 // Nubert
|
|
||||||
#define IRMP_BANG_OLUFSEN_PROTOCOL 14 // Bang & Olufsen
|
|
||||||
#define IRMP_GRUNDIG_PROTOCOL 15 // Grundig
|
|
||||||
#define IRMP_NOKIA_PROTOCOL 16 // Nokia
|
|
||||||
#define IRMP_SIEMENS_PROTOCOL 17 // Siemens, e.g. Gigaset
|
|
||||||
#define IRMP_FDC_PROTOCOL 18 // FDC keyboard
|
|
||||||
#define IRMP_RCCAR_PROTOCOL 19 // RC Car
|
|
||||||
#define IRMP_JVC_PROTOCOL 20 // JVC (NEC with 16 bits)
|
|
||||||
#define IRMP_RC6A_PROTOCOL 21 // RC6A, e.g. Kathrein, XBOX
|
|
||||||
#define IRMP_NIKON_PROTOCOL 22 // Nikon
|
|
||||||
#define IRMP_RUWIDO_PROTOCOL 23 // Ruwido, e.g. T-Home Mediareceiver
|
|
||||||
#define IRMP_IR60_PROTOCOL 24 // IR60 (SAB2008)
|
|
||||||
#define IRMP_KATHREIN_PROTOCOL 25 // Kathrein
|
|
||||||
#define IRMP_NETBOX_PROTOCOL 26 // Netbox keyboard (bitserial)
|
|
||||||
#define IRMP_NEC16_PROTOCOL 27 // NEC with 16 bits (incl. sync)
|
|
||||||
#define IRMP_NEC42_PROTOCOL 28 // NEC with 42 bits
|
|
||||||
#define IRMP_LEGO_PROTOCOL 29 // LEGO Power Functions RC
|
|
||||||
#define IRMP_THOMSON_PROTOCOL 30 // Thomson
|
|
||||||
#define IRMP_GRUNDIG2_PROTOCOL 31 // Grundig, e.g. TP400
|
|
||||||
|
|
||||||
#define IRMP_N_PROTOCOLS 31 // number of supported protocols
|
|
||||||
|
|
||||||
// some flags of struct IRMP_PARAMETER:
|
|
||||||
#define IRMP_PARAM_FLAG_IS_MANCHESTER 0x01
|
|
||||||
#define IRMP_PARAM_FLAG_1ST_PULSE_IS_1 0x02
|
|
||||||
#define IRMP_PARAM_FLAG_IS_SERIAL 0x04
|
|
||||||
|
|
||||||
#define SIRCS_START_BIT_PULSE_TIME 2400.0e-6 // 2400 usec pulse
|
|
||||||
#define SIRCS_START_BIT_PAUSE_TIME 600.0e-6 // 600 usec pause
|
|
||||||
#define SIRCS_1_PULSE_TIME 1200.0e-6 // 1200 usec pulse
|
|
||||||
#define SIRCS_0_PULSE_TIME 600.0e-6 // 600 usec pulse
|
|
||||||
#define SIRCS_PAUSE_TIME 600.0e-6 // 600 usec pause
|
|
||||||
#define SIRCS_FRAMES 3 // SIRCS sends each frame 3 times
|
|
||||||
#define SIRCS_AUTO_REPETITION_PAUSE_TIME 25.0e-3 // auto repetition after 25ms
|
|
||||||
#define SIRCS_FRAME_REPEAT_PAUSE_TIME 25.0e-3 // frame repeat after 25ms
|
|
||||||
#define SIRCS_ADDRESS_OFFSET 15 // skip 15 bits
|
|
||||||
#define SIRCS_ADDRESS_LEN 5 // read up to 5 address bits
|
|
||||||
#define SIRCS_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define SIRCS_COMMAND_LEN 15 // read 12-15 command bits
|
|
||||||
#define SIRCS_MINIMUM_DATA_LEN 12 // minimum data length
|
|
||||||
#define SIRCS_COMPLETE_DATA_LEN 20 // complete length - may be up to 20
|
|
||||||
#define SIRCS_STOP_BIT 0 // has no stop bit
|
|
||||||
#define SIRCS_LSB 1 // LSB...MSB
|
|
||||||
#define SIRCS_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define NEC_START_BIT_PULSE_TIME 9000.0e-6 // 9000 usec pulse
|
|
||||||
#define NEC_START_BIT_PAUSE_TIME 4500.0e-6 // 4500 usec pause
|
|
||||||
#define NEC_REPEAT_START_BIT_PAUSE_TIME 2250.0e-6 // 2250 usec pause
|
|
||||||
#define NEC_PULSE_TIME 560.0e-6 // 560 usec pulse
|
|
||||||
#define NEC_1_PAUSE_TIME 1690.0e-6 // 1690 usec pause
|
|
||||||
#define NEC_0_PAUSE_TIME 560.0e-6 // 560 usec pause
|
|
||||||
#define NEC_FRAME_REPEAT_PAUSE_TIME 40.0e-3 // frame repeat after 40ms
|
|
||||||
#define NEC_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NEC_ADDRESS_LEN 16 // read 16 address bits
|
|
||||||
#define NEC_COMMAND_OFFSET 16 // skip 16 bits (8 address + 8 /address)
|
|
||||||
#define NEC_COMMAND_LEN 16 // read 16 bits (8 command + 8 /command)
|
|
||||||
#define NEC_COMPLETE_DATA_LEN 32 // complete length
|
|
||||||
#define NEC_STOP_BIT 1 // has stop bit
|
|
||||||
#define NEC_LSB 1 // LSB...MSB
|
|
||||||
#define NEC_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define NEC42_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NEC42_ADDRESS_LEN 13 // read 13 address bits
|
|
||||||
#define NEC42_COMMAND_OFFSET 26 // skip 26 bits (2 x 13 address bits)
|
|
||||||
#define NEC42_COMMAND_LEN 8 // read 8 command bits
|
|
||||||
#define NEC42_COMPLETE_DATA_LEN 42 // complete length (2 x 13 + 2 x 8)
|
|
||||||
|
|
||||||
#define NEC16_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NEC16_ADDRESS_LEN 8 // read 8 address bits
|
|
||||||
#define NEC16_COMMAND_OFFSET 8 // skip 8 bits (8 address)
|
|
||||||
#define NEC16_COMMAND_LEN 8 // read 8 bits (8 command)
|
|
||||||
#define NEC16_COMPLETE_DATA_LEN 16 // complete length
|
|
||||||
|
|
||||||
#define SAMSUNG_START_BIT_PULSE_TIME 4500.0e-6 // 4500 usec pulse
|
|
||||||
#define SAMSUNG_START_BIT_PAUSE_TIME 4500.0e-6 // 4500 usec pause
|
|
||||||
#define SAMSUNG_PULSE_TIME 550.0e-6 // 550 usec pulse
|
|
||||||
#define SAMSUNG_1_PAUSE_TIME 1650.0e-6 // 1650 usec pause
|
|
||||||
#define SAMSUNG_0_PAUSE_TIME 550.0e-6 // 550 usec pause
|
|
||||||
|
|
||||||
#define SAMSUNG_FRAME_REPEAT_PAUSE_TIME 25.0e-3 // frame repeat after 25ms
|
|
||||||
#define SAMSUNG_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define SAMSUNG_ADDRESS_LEN 16 // read 16 address bits
|
|
||||||
#define SAMSUNG_ID_OFFSET 17 // skip 16 + 1 sync bit
|
|
||||||
#define SAMSUNG_ID_LEN 4 // read 4 id bits
|
|
||||||
#define SAMSUNG_COMMAND_OFFSET 21 // skip 16 + 1 sync + 4 data bits
|
|
||||||
#define SAMSUNG_COMMAND_LEN 16 // read 16 command bits
|
|
||||||
#define SAMSUNG_COMPLETE_DATA_LEN 37 // complete length
|
|
||||||
#define SAMSUNG_STOP_BIT 1 // has stop bit
|
|
||||||
#define SAMSUNG_LSB 1 // LSB...MSB?
|
|
||||||
#define SAMSUNG_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define SAMSUNG32_COMMAND_OFFSET 16 // skip 16 bits
|
|
||||||
#define SAMSUNG32_COMMAND_LEN 16 // read 16 command bits
|
|
||||||
#define SAMSUNG32_COMPLETE_DATA_LEN 32 // complete length
|
|
||||||
#define SAMSUNG32_FRAMES 1 // SAMSUNG32 sends each frame 1 times
|
|
||||||
#define SAMSUNG32_AUTO_REPETITION_PAUSE_TIME 47.0e-3 // repetition after 47 ms
|
|
||||||
#define SAMSUNG32_FRAME_REPEAT_PAUSE_TIME 47.0e-3 // frame repeat after 47ms
|
|
||||||
|
|
||||||
#define MATSUSHITA_START_BIT_PULSE_TIME 3488.0e-6 // 3488 usec pulse
|
|
||||||
#define MATSUSHITA_START_BIT_PAUSE_TIME 3488.0e-6 // 3488 usec pause
|
|
||||||
#define MATSUSHITA_PULSE_TIME 872.0e-6 // 872 usec pulse
|
|
||||||
#define MATSUSHITA_1_PAUSE_TIME 2616.0e-6 // 2616 usec pause
|
|
||||||
#define MATSUSHITA_0_PAUSE_TIME 872.0e-6 // 872 usec pause
|
|
||||||
#define MATSUSHITA_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define MATSUSHITA_ADDRESS_OFFSET 12 // skip 12 bits
|
|
||||||
#define MATSUSHITA_ADDRESS_LEN 12 // read 12 address bits
|
|
||||||
#define MATSUSHITA_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define MATSUSHITA_COMMAND_LEN 12 // read 12 bits (6 custom + 6 command)
|
|
||||||
#define MATSUSHITA_COMPLETE_DATA_LEN 24 // complete length
|
|
||||||
#define MATSUSHITA_STOP_BIT 1 // has stop bit
|
|
||||||
#define MATSUSHITA_LSB 1 // LSB...MSB?
|
|
||||||
#define MATSUSHITA_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define KASEIKYO_START_BIT_PULSE_TIME 3380.0e-6 // 3380 usec pulse
|
|
||||||
#define KASEIKYO_START_BIT_PAUSE_TIME 1690.0e-6 // 1690 usec pause
|
|
||||||
#define KASEIKYO_PULSE_TIME 423.0e-6 // 525 usec pulse
|
|
||||||
#define KASEIKYO_1_PAUSE_TIME 1269.0e-6 // 525 usec pause
|
|
||||||
#define KASEIKYO_0_PAUSE_TIME 423.0e-6 // 1690 usec pause
|
|
||||||
#define KASEIKYO_AUTO_REPETITION_PAUSE_TIME 74.0e-3 // repetition after 74 ms
|
|
||||||
#define KASEIKYO_FRAME_REPEAT_PAUSE_TIME 74.0e-3 // frame repeat after 74 ms
|
|
||||||
#define KASEIKYO_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define KASEIKYO_ADDRESS_LEN 16 // read 16 address bits
|
|
||||||
#define KASEIKYO_COMMAND_OFFSET 28 // skip 28 bits (16 manufacturer & 4 parity & 8 genre)
|
|
||||||
#define KASEIKYO_COMMAND_LEN 12 // read 12 command bits (10 real command & 2 id)
|
|
||||||
#define KASEIKYO_COMPLETE_DATA_LEN 48 // complete length
|
|
||||||
#define KASEIKYO_STOP_BIT 1 // has stop bit
|
|
||||||
#define KASEIKYO_LSB 1 // LSB...MSB?
|
|
||||||
#define KASEIKYO_FRAMES 2 // KASEIKYO sends 1st frame 2 times
|
|
||||||
#define KASEIKYO_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define RECS80_START_BIT_PULSE_TIME 158.0e-6 // 158 usec pulse
|
|
||||||
#define RECS80_START_BIT_PAUSE_TIME 7432.0e-6 // 7432 usec pause
|
|
||||||
#define RECS80_PULSE_TIME 158.0e-6 // 158 usec pulse
|
|
||||||
#define RECS80_1_PAUSE_TIME 7432.0e-6 // 7432 usec pause
|
|
||||||
#define RECS80_0_PAUSE_TIME 4902.0e-6 // 4902 usec pause
|
|
||||||
#define RECS80_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define RECS80_ADDRESS_OFFSET 1 // skip 1 bit (toggle bit)
|
|
||||||
#define RECS80_ADDRESS_LEN 3 // read 3 address bits
|
|
||||||
#define RECS80_COMMAND_OFFSET 4 // skip 4 bits (1 toggle + 3 address)
|
|
||||||
#define RECS80_COMMAND_LEN 6 // read 6 command bits
|
|
||||||
#define RECS80_COMPLETE_DATA_LEN 10 // complete length
|
|
||||||
#define RECS80_STOP_BIT 1 // has stop bit
|
|
||||||
#define RECS80_LSB 0 // MSB...LSB
|
|
||||||
#define RECS80_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define RC5_BIT_TIME 889.0e-6 // 889 usec pulse/pause
|
|
||||||
#define RC5_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
|
|
||||||
#define RC5_ADDRESS_OFFSET 1 // skip 1 bit (2nd start)
|
|
||||||
#define RC5_ADDRESS_LEN 6 // read 1 toggle bit (for key repetition detection) + 5 address bits
|
|
||||||
#define RC5_COMMAND_OFFSET 7 // skip 5 bits (2nd start + 1 toggle + 5 address)
|
|
||||||
#define RC5_COMMAND_LEN 6 // read 6 command bits
|
|
||||||
#define RC5_COMPLETE_DATA_LEN 13 // complete length
|
|
||||||
#define RC5_STOP_BIT 0 // has no stop bit
|
|
||||||
#define RC5_LSB 0 // MSB...LSB
|
|
||||||
#define RC5_FLAGS IRMP_PARAM_FLAG_IS_MANCHESTER // flags
|
|
||||||
|
|
||||||
#define DENON_PULSE_TIME 310.0e-6 // 310 usec pulse in practice, 275 in theory
|
|
||||||
#define DENON_1_PAUSE_TIME 1780.0e-6 // 1780 usec pause in practice, 1900 in theory
|
|
||||||
#define DENON_0_PAUSE_TIME 745.0e-6 // 745 usec pause in practice, 775 in theory
|
|
||||||
#define DENON_FRAMES 2 // DENON sends each frame 2 times
|
|
||||||
#define DENON_AUTO_REPETITION_PAUSE_TIME 65.0e-3 // inverted repetition after 65ms
|
|
||||||
#define DENON_FRAME_REPEAT_PAUSE_TIME 65.0e-3 // frame repeat after 65ms
|
|
||||||
#define DENON_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define DENON_ADDRESS_LEN 5 // read 5 address bits
|
|
||||||
#define DENON_COMMAND_OFFSET 5 // skip 5
|
|
||||||
#define DENON_COMMAND_LEN 10 // read 10 command bits
|
|
||||||
#define DENON_COMPLETE_DATA_LEN 15 // complete length
|
|
||||||
#define DENON_STOP_BIT 1 // has stop bit
|
|
||||||
#define DENON_LSB 0 // MSB...LSB
|
|
||||||
#define DENON_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define RC6_START_BIT_PULSE_TIME 2666.0e-6 // 2.666 msec pulse
|
|
||||||
#define RC6_START_BIT_PAUSE_TIME 889.0e-6 // 889 usec pause
|
|
||||||
#define RC6_TOGGLE_BIT_TIME 889.0e-6 // 889 msec pulse/pause
|
|
||||||
#define RC6_BIT_TIME 444.0e-6 // 889 usec pulse/pause
|
|
||||||
#define RC6_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define RC6_ADDRESS_OFFSET 5 // skip "1" + 3 mode bits + 1 toggle bit
|
|
||||||
#define RC6_ADDRESS_LEN 8 // read 8 address bits
|
|
||||||
#define RC6_COMMAND_OFFSET 13 // skip 12 bits ("1" + 3 mode + 1 toggle + 8 address)
|
|
||||||
#define RC6_COMMAND_LEN 8 // read 8 command bits
|
|
||||||
#define RC6_COMPLETE_DATA_LEN_SHORT 21 // complete length
|
|
||||||
#define RC6_COMPLETE_DATA_LEN_LONG 36 // complete length
|
|
||||||
#define RC6_STOP_BIT 0 // has no stop bit
|
|
||||||
#define RC6_LSB 0 // MSB...LSB
|
|
||||||
#define RC6_FLAGS (IRMP_PARAM_FLAG_IS_MANCHESTER | IRMP_PARAM_FLAG_1ST_PULSE_IS_1) // flags
|
|
||||||
|
|
||||||
#define RECS80EXT_START_BIT_PULSE_TIME 158.0e-6 // 158 usec pulse
|
|
||||||
#define RECS80EXT_START_BIT_PAUSE_TIME 3637.0e-6 // 3637 usec pause
|
|
||||||
#define RECS80EXT_PULSE_TIME 158.0e-6 // 158 usec pulse
|
|
||||||
#define RECS80EXT_1_PAUSE_TIME 7432.0e-6 // 7432 usec pause
|
|
||||||
#define RECS80EXT_0_PAUSE_TIME 4902.0e-6 // 4902 usec pause
|
|
||||||
#define RECS80EXT_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define RECS80EXT_ADDRESS_OFFSET 2 // skip 2 bits (2nd start + 1 toggle)
|
|
||||||
#define RECS80EXT_ADDRESS_LEN 4 // read 4 address bits
|
|
||||||
#define RECS80EXT_COMMAND_OFFSET 6 // skip 6 bits (2nd start + 1 toggle + 4 address)
|
|
||||||
#define RECS80EXT_COMMAND_LEN 6 // read 6 command bits
|
|
||||||
#define RECS80EXT_COMPLETE_DATA_LEN 12 // complete length
|
|
||||||
#define RECS80EXT_STOP_BIT 1 // has stop bit
|
|
||||||
#define RECS80EXT_LSB 0 // MSB...LSB
|
|
||||||
#define RECS80EXT_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define NUBERT_START_BIT_PULSE_TIME 1340.0e-6 // 1340 usec pulse
|
|
||||||
#define NUBERT_START_BIT_PAUSE_TIME 340.0e-6 // 340 usec pause
|
|
||||||
#define NUBERT_1_PULSE_TIME 1340.0e-6 // 1340 usec pulse
|
|
||||||
#define NUBERT_1_PAUSE_TIME 340.0e-6 // 340 usec pause
|
|
||||||
#define NUBERT_0_PULSE_TIME 500.0e-6 // 500 usec pulse
|
|
||||||
#define NUBERT_0_PAUSE_TIME 1300.0e-6 // 1300 usec pause
|
|
||||||
#define NUBERT_FRAMES 2 // Nubert sends 2 frames
|
|
||||||
#define NUBERT_AUTO_REPETITION_PAUSE_TIME 35.0e-3 // auto repetition after 35ms
|
|
||||||
#define NUBERT_FRAME_REPEAT_PAUSE_TIME 35.0e-3 // frame repeat after 45ms
|
|
||||||
#define NUBERT_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NUBERT_ADDRESS_LEN 0 // read 0 address bits
|
|
||||||
#define NUBERT_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define NUBERT_COMMAND_LEN 10 // read 10 bits
|
|
||||||
#define NUBERT_COMPLETE_DATA_LEN 10 // complete length
|
|
||||||
#define NUBERT_STOP_BIT 1 // has stop bit
|
|
||||||
#define NUBERT_LSB 0 // MSB?
|
|
||||||
#define NUBERT_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define BANG_OLUFSEN_START_BIT1_PULSE_TIME 200.0e-6 // 200 usec pulse
|
|
||||||
#define BANG_OLUFSEN_START_BIT1_PAUSE_TIME 3125.0e-6 // 3125 usec pause
|
|
||||||
#define BANG_OLUFSEN_START_BIT2_PULSE_TIME 200.0e-6 // 200 usec pulse
|
|
||||||
#define BANG_OLUFSEN_START_BIT2_PAUSE_TIME 3125.0e-6 // 3125 usec pause
|
|
||||||
#define BANG_OLUFSEN_START_BIT3_PULSE_TIME 200.0e-6 // 200 usec pulse
|
|
||||||
#define BANG_OLUFSEN_START_BIT3_PAUSE_TIME 15625.0e-6 // 15625 usec pause
|
|
||||||
#define BANG_OLUFSEN_START_BIT4_PULSE_TIME 200.0e-6 // 200 usec pulse
|
|
||||||
#define BANG_OLUFSEN_START_BIT4_PAUSE_TIME 3125.0e-6 // 3125 usec pause
|
|
||||||
#define BANG_OLUFSEN_PULSE_TIME 200.0e-6 // 200 usec pulse
|
|
||||||
#define BANG_OLUFSEN_1_PAUSE_TIME 9375.0e-6 // 9375 usec pause
|
|
||||||
#define BANG_OLUFSEN_0_PAUSE_TIME 3125.0e-6 // 3125 usec pause
|
|
||||||
#define BANG_OLUFSEN_R_PAUSE_TIME 6250.0e-6 // 6250 usec pause (repeat last bit)
|
|
||||||
#define BANG_OLUFSEN_TRAILER_BIT_PAUSE_TIME 12500.0e-6 // 12500 usec pause (trailer bit)
|
|
||||||
#define BANG_OLUFSEN_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define BANG_OLUFSEN_ADDRESS_OFFSET 0 // no address bits
|
|
||||||
#define BANG_OLUFSEN_ADDRESS_LEN 0 // no address bits
|
|
||||||
#define BANG_OLUFSEN_COMMAND_OFFSET 3 // skip startbits 2, 3, 4
|
|
||||||
#define BANG_OLUFSEN_COMMAND_LEN 16 // read 16 command bits
|
|
||||||
#define BANG_OLUFSEN_COMPLETE_DATA_LEN 20 // complete length: startbits 2, 3, 4 + 16 data bits + trailer bit
|
|
||||||
#define BANG_OLUFSEN_STOP_BIT 1 // has stop bit
|
|
||||||
#define BANG_OLUFSEN_LSB 0 // MSB...LSB
|
|
||||||
#define BANG_OLUFSEN_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define GRUNDIG_NOKIA_IR60_BIT_TIME 528.0e-6 // 528 usec pulse/pause
|
|
||||||
#define GRUNDIG_NOKIA_IR60_PRE_PAUSE_TIME 2639.0e-6 // 2639 usec pause after pre bit
|
|
||||||
#define GRUNDIG_NOKIA_IR60_FRAME_REPEAT_PAUSE_TIME 117.76e-3 // info frame repeat after 117.76 ms
|
|
||||||
#define GRUNDIG_NOKIA_IR60_STOP_BIT 0 // has no stop bit
|
|
||||||
#define GRUNDIG_NOKIA_IR60_LSB 1 // MSB...LSB
|
|
||||||
#define GRUNDIG_NOKIA_IR60_FLAGS (IRMP_PARAM_FLAG_IS_MANCHESTER | IRMP_PARAM_FLAG_1ST_PULSE_IS_1) // flags
|
|
||||||
|
|
||||||
#define GRUNDIG_FRAMES 2 // GRUNDIG sends each frame 1+1 times
|
|
||||||
#define GRUNDIG_AUTO_REPETITION_PAUSE_TIME 20.0e-3 // repetition after 20ms
|
|
||||||
#define GRUNDIG_ADDRESS_OFFSET 0 // no address
|
|
||||||
#define GRUNDIG_ADDRESS_LEN 0 // no address
|
|
||||||
#define GRUNDIG_COMMAND_OFFSET 1 // skip 1 start bit
|
|
||||||
#define GRUNDIG_COMMAND_LEN 9 // read 9 command bits
|
|
||||||
#define GRUNDIG_COMPLETE_DATA_LEN 10 // complete length: 1 start bit + 9 data bits
|
|
||||||
|
|
||||||
#define NOKIA_FRAMES 3 // NOKIA sends each frame 1 + 1 + 1 times
|
|
||||||
#define NOKIA_AUTO_REPETITION_PAUSE_TIME 20.0e-3 // repetition after 20ms
|
|
||||||
#define NOKIA_ADDRESS_OFFSET 9 // skip 9 bits (1 start bit + 8 data bits)
|
|
||||||
#define NOKIA_ADDRESS_LEN 8 // 7 address bits
|
|
||||||
#define NOKIA_COMMAND_OFFSET 1 // skip 1 bit (1 start bit)
|
|
||||||
#define NOKIA_COMMAND_LEN 8 // read 8 command bits
|
|
||||||
#define NOKIA_COMPLETE_DATA_LEN 17 // complete length: 1 start bit + 8 address bits + 8 command bits
|
|
||||||
|
|
||||||
#define IR60_TIMEOUT_TIME 5000.0e-6 // timeout grundig frame, switch to IR60
|
|
||||||
#define IR60_ADDRESS_OFFSET 0 // skip 1 bits
|
|
||||||
#define IR60_ADDRESS_LEN 0 // read 0 address bits
|
|
||||||
#define IR60_COMMAND_OFFSET 0 // skip 1 bit (start bit after pre bit, always 1)
|
|
||||||
#define IR60_COMMAND_LEN 7 // read 6 command bits
|
|
||||||
#define IR60_COMPLETE_DATA_LEN 7 // complete length
|
|
||||||
|
|
||||||
#define SIEMENS_OR_RUWIDO_START_BIT_PULSE_TIME 275.0e-6 // 275 usec pulse
|
|
||||||
#define SIEMENS_OR_RUWIDO_START_BIT_PAUSE_TIME 550.0e-6 // 550 usec pause
|
|
||||||
#define SIEMENS_OR_RUWIDO_BIT_PULSE_TIME 275.0e-6 // 275 usec short pulse
|
|
||||||
#define SIEMENS_OR_RUWIDO_BIT_PULSE_TIME_2 550.0e-6 // 550 usec long pulse
|
|
||||||
#define SIEMENS_OR_RUWIDO_BIT_PAUSE_TIME 275.0e-6 // 275 usec short pause
|
|
||||||
#define SIEMENS_OR_RUWIDO_BIT_PAUSE_TIME_2 550.0e-6 // 550 usec long pause
|
|
||||||
#define SIEMENS_OR_RUWIDO_FRAME_REPEAT_PAUSE_TIME 45.0e-3 // frame repeat after 45ms
|
|
||||||
#define SIEMENS_OR_RUWIDO_STOP_BIT 0 // has no stop bit
|
|
||||||
#define SIEMENS_OR_RUWIDO_LSB 0 // MSB...LSB
|
|
||||||
#define SIEMENS_OR_RUWIDO_FLAGS (IRMP_PARAM_FLAG_IS_MANCHESTER | IRMP_PARAM_FLAG_1ST_PULSE_IS_1) // flags
|
|
||||||
|
|
||||||
#define RUWIDO_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define RUWIDO_ADDRESS_LEN 9 // read 9 address bits
|
|
||||||
#define RUWIDO_COMMAND_OFFSET 9 // skip 9 bits
|
|
||||||
#define RUWIDO_COMMAND_LEN 8 // read 7 + 1 command bits, last bit is only check bit
|
|
||||||
#define RUWIDO_COMPLETE_DATA_LEN 17 // complete length
|
|
||||||
|
|
||||||
#define SIEMENS_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define SIEMENS_ADDRESS_LEN 11 // read 11 bits
|
|
||||||
#define SIEMENS_COMMAND_OFFSET 11 // skip 11 bits
|
|
||||||
#define SIEMENS_COMMAND_LEN 11 // read 10 + 1 command bits, last bit is only check bit
|
|
||||||
#define SIEMENS_COMPLETE_DATA_LEN 22 // complete length
|
|
||||||
|
|
||||||
#define FDC_START_BIT_PULSE_TIME 2085.0e-6 // 2085 usec pulse
|
|
||||||
#define FDC_START_BIT_PAUSE_TIME 966.0e-6 // 966 usec pause
|
|
||||||
#define FDC_PULSE_TIME 300.0e-6 // 300 usec pulse
|
|
||||||
#define FDC_1_PAUSE_TIME 715.0e-6 // 715 usec pause
|
|
||||||
#define FDC_0_PAUSE_TIME 220.0e-6 // 220 usec pause
|
|
||||||
#define FDC_FRAME_REPEAT_PAUSE_TIME 60.0e-3 // frame repeat after 60ms
|
|
||||||
#define FDC_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define FDC_ADDRESS_LEN 14 // read 14 address bits, but use only 6, shift 8 into command
|
|
||||||
#define FDC_COMMAND_OFFSET 20 // skip 20 bits
|
|
||||||
#define FDC_COMMAND_LEN 12 // read 12 bits
|
|
||||||
#define FDC_COMPLETE_DATA_LEN 40 // complete length
|
|
||||||
#define FDC_STOP_BIT 1 // has stop bit
|
|
||||||
#define FDC_LSB 1 // LSB...MSB
|
|
||||||
#define FDC_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define RCCAR_START_BIT_PULSE_TIME 2000.0e-6 // 2000 usec pulse
|
|
||||||
#define RCCAR_START_BIT_PAUSE_TIME 2000.0e-6 // 2000 usec pause
|
|
||||||
#define RCCAR_PULSE_TIME 600.0e-6 // 360 usec pulse
|
|
||||||
#define RCCAR_1_PAUSE_TIME 450.0e-6 // 650 usec pause
|
|
||||||
#define RCCAR_0_PAUSE_TIME 900.0e-6 // 180 usec pause
|
|
||||||
#define RCCAR_FRAME_REPEAT_PAUSE_TIME 40.0e-3 // frame repeat after 40ms
|
|
||||||
#define RCCAR_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define RCCAR_ADDRESS_LEN 0 // read 0 address bits
|
|
||||||
#define RCCAR_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define RCCAR_COMMAND_LEN 13 // read 13 bits
|
|
||||||
#define RCCAR_COMPLETE_DATA_LEN 13 // complete length
|
|
||||||
#define RCCAR_STOP_BIT 1 // has stop bit
|
|
||||||
#define RCCAR_LSB 1 // LSB...MSB
|
|
||||||
#define RCCAR_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define JVC_START_BIT_PULSE_TIME 9000.0e-6 // 9000 usec pulse
|
|
||||||
#define JVC_START_BIT_PAUSE_TIME 4500.0e-6 // 4500 usec pause
|
|
||||||
#define JVC_PULSE_TIME 560.0e-6 // 560 usec pulse
|
|
||||||
#define JVC_1_PAUSE_TIME 1690.0e-6 // 1690 usec pause
|
|
||||||
#define JVC_0_PAUSE_TIME 560.0e-6 // 560 usec pause
|
|
||||||
#define JVC_FRAME_REPEAT_PAUSE_TIME 22.0e-3 // frame repeat after 22ms
|
|
||||||
#define JVC_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define JVC_ADDRESS_LEN 4 // read 4 address bits
|
|
||||||
#define JVC_COMMAND_OFFSET 4 // skip 4 bits
|
|
||||||
#define JVC_COMMAND_LEN 12 // read 12 bits
|
|
||||||
#define JVC_COMPLETE_DATA_LEN 16 // complete length
|
|
||||||
#define JVC_STOP_BIT 1 // has stop bit
|
|
||||||
#define JVC_LSB 1 // LSB...MSB
|
|
||||||
#define JVC_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define NIKON_START_BIT_PULSE_TIME 2200.0e-6 // 2200 usec pulse
|
|
||||||
#define NIKON_START_BIT_PAUSE_TIME 27100.0e-6 // 27100 usec pause
|
|
||||||
#define NIKON_PULSE_TIME 500.0e-6 // 500 usec pulse
|
|
||||||
#define NIKON_1_PAUSE_TIME 3500.0e-6 // 3500 usec pause
|
|
||||||
#define NIKON_0_PAUSE_TIME 1500.0e-6 // 1500 usec pause
|
|
||||||
#define NIKON_FRAME_REPEAT_PAUSE_TIME 60.0e-3 // frame repeat after 60ms
|
|
||||||
#define NIKON_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NIKON_ADDRESS_LEN 0 // read 0 address bits
|
|
||||||
#define NIKON_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define NIKON_COMMAND_LEN 2 // read 2 bits
|
|
||||||
#define NIKON_COMPLETE_DATA_LEN 2 // complete length
|
|
||||||
#define NIKON_STOP_BIT 1 // has stop bit
|
|
||||||
#define NIKON_LSB 0 // LSB...MSB
|
|
||||||
#define NIKON_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define KATHREIN_START_BIT_PULSE_TIME 210.0e-6 // 1340 usec pulse
|
|
||||||
#define KATHREIN_START_BIT_PAUSE_TIME 6218.0e-6 // 340 usec pause
|
|
||||||
#define KATHREIN_1_PULSE_TIME 210.0e-6 // 1340 usec pulse
|
|
||||||
#define KATHREIN_1_PAUSE_TIME 3000.0e-6 // 340 usec pause
|
|
||||||
#define KATHREIN_0_PULSE_TIME 210.0e-6 // 500 usec pulse
|
|
||||||
#define KATHREIN_0_PAUSE_TIME 1400.0e-6 // 1300 usec pause
|
|
||||||
#define KATHREIN_SYNC_BIT_PAUSE_LEN_TIME 4600.0e-6 // 4600 usec sync (on 6th and/or 8th bit)
|
|
||||||
#define KATHREIN_FRAMES 1 // Kathrein sends 1 frame
|
|
||||||
#define KATHREIN_AUTO_REPETITION_PAUSE_TIME 35.0e-3 // auto repetition after 35ms
|
|
||||||
#define KATHREIN_FRAME_REPEAT_PAUSE_TIME 35.0e-3 // frame repeat after 35ms
|
|
||||||
#define KATHREIN_ADDRESS_OFFSET 1 // skip 1 bits
|
|
||||||
#define KATHREIN_ADDRESS_LEN 4 // read 4 address bits
|
|
||||||
#define KATHREIN_COMMAND_OFFSET 5 // skip 5 bits
|
|
||||||
#define KATHREIN_COMMAND_LEN 7 // read 7 bits
|
|
||||||
#define KATHREIN_COMPLETE_DATA_LEN 13 // complete length
|
|
||||||
#define KATHREIN_STOP_BIT 1 // has stop bit
|
|
||||||
#define KATHREIN_LSB 0 // MSB
|
|
||||||
#define KATHREIN_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define NETBOX_START_BIT_PULSE_TIME 2400.0e-6 // 2400 usec pulse
|
|
||||||
#define NETBOX_START_BIT_PAUSE_TIME 800.0e-6 // 800 usec pause
|
|
||||||
#define NETBOX_PULSE_TIME 800.0e-6 // 800 usec pulse
|
|
||||||
#define NETBOX_PAUSE_TIME 800.0e-6 // 800 usec pause
|
|
||||||
#define NETBOX_FRAMES 1 // Netbox sends 1 frame
|
|
||||||
#define NETBOX_AUTO_REPETITION_PAUSE_TIME 35.0e-3 // auto repetition after 35ms
|
|
||||||
#define NETBOX_FRAME_REPEAT_PAUSE_TIME 35.0e-3 // frame repeat after 35ms
|
|
||||||
#define NETBOX_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define NETBOX_ADDRESS_LEN 3 // read 3 address bits
|
|
||||||
#define NETBOX_COMMAND_OFFSET 3 // skip 3 bits
|
|
||||||
#define NETBOX_COMMAND_LEN 13 // read 13 bits
|
|
||||||
#define NETBOX_COMPLETE_DATA_LEN 16 // complete length
|
|
||||||
#define NETBOX_STOP_BIT 0 // has no stop bit
|
|
||||||
#define NETBOX_LSB 1 // LSB
|
|
||||||
#define NETBOX_FLAGS IRMP_PARAM_FLAG_IS_SERIAL // flags
|
|
||||||
|
|
||||||
#define LEGO_START_BIT_PULSE_TIME 158.0e-6 // 158 usec pulse ( 6 x 1/38kHz)
|
|
||||||
#define LEGO_START_BIT_PAUSE_TIME 1026.0e-6 // 1026 usec pause (39 x 1/38kHz)
|
|
||||||
#define LEGO_PULSE_TIME 158.0e-6 // 158 usec pulse ( 6 x 1/38kHz)
|
|
||||||
#define LEGO_1_PAUSE_TIME 553.0e-6 // 553 usec pause (21 x 1/38kHz)
|
|
||||||
#define LEGO_0_PAUSE_TIME 263.0e-6 // 263 usec pause (10 x 1/38kHz)
|
|
||||||
#define LEGO_FRAME_REPEAT_PAUSE_TIME 40.0e-3 // frame repeat after 40ms
|
|
||||||
#define LEGO_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define LEGO_ADDRESS_LEN 0 // read 0 address bits
|
|
||||||
#define LEGO_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define LEGO_COMMAND_LEN 16 // read 16 bits (12 command + 4 CRC)
|
|
||||||
#define LEGO_COMPLETE_DATA_LEN 16 // complete length
|
|
||||||
#define LEGO_STOP_BIT 1 // has stop bit
|
|
||||||
#define LEGO_LSB 0 // MSB...LSB
|
|
||||||
#define LEGO_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define THOMSON_PULSE_TIME 550.0e-6 // 550 usec pulse
|
|
||||||
#define THOMSON_1_PAUSE_TIME 4500.0e-6 // 4500 usec pause
|
|
||||||
#define THOMSON_0_PAUSE_TIME 2000.0e-6 // 2000 usec pause
|
|
||||||
#define THOMSON_FRAMES 1 // THOMSON sends 1 frame
|
|
||||||
#define THOMSON_AUTO_REPETITION_PAUSE_TIME 65.0e-3 // repetition after 65ms
|
|
||||||
#define THOMSON_FRAME_REPEAT_PAUSE_TIME 65.0e-3 // frame repeat after 65ms
|
|
||||||
#define THOMSON_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define THOMSON_ADDRESS_LEN 4 // read 4 address bits
|
|
||||||
#define THOMSON_COMMAND_OFFSET 5 // skip 4 address bits + 1 toggle bit
|
|
||||||
#define THOMSON_COMMAND_LEN 7 // read 7 command bits
|
|
||||||
#define THOMSON_COMPLETE_DATA_LEN 12 // complete length
|
|
||||||
#define THOMSON_STOP_BIT 1 // has stop bit
|
|
||||||
#define THOMSON_LSB 0 // MSB...LSB
|
|
||||||
#define THOMSON_FLAGS 0 // flags
|
|
||||||
|
|
||||||
#define GRUNDIG2_START_BIT_PULSE_TIME 550.0e-6 // 550 usec pulse
|
|
||||||
#define GRUNDIG2_START_BIT_PAUSE_TIME 2700.0e-6 // 2700 usec pause
|
|
||||||
#define GRUNDIG2_BIT_PULSE_TIME 550.0e-6 // 550 usec short pulse
|
|
||||||
#define GRUNDIG2_BIT_PAUSE_TIME 550.0e-6 // 550 usec short pause
|
|
||||||
#define GRUNDIG2_FRAME_REPEAT_PAUSE_TIME 100.0e-3 // frame repeat after 100ms
|
|
||||||
#define GRUNDIG2_STOP_BIT 0 // has no stop bit
|
|
||||||
#define GRUNDIG2_LSB 1 // MSB...LSB
|
|
||||||
#define GRUNDIG2_FLAGS (IRMP_PARAM_FLAG_IS_MANCHESTER | IRMP_PARAM_FLAG_1ST_PULSE_IS_1) // flags
|
|
||||||
#define GRUNDIG2_ADDRESS_OFFSET 0 // skip 0 bits
|
|
||||||
#define GRUNDIG2_ADDRESS_LEN 0 // read 0 bits
|
|
||||||
#define GRUNDIG2_COMMAND_OFFSET 0 // skip 0 bits
|
|
||||||
#define GRUNDIG2_COMMAND_LEN 7 // read 6 + 1 command bits, last bit is always 1
|
|
||||||
#define GRUNDIG2_COMPLETE_DATA_LEN 7 // complete length
|
|
||||||
|
|
||||||
#define AUTO_FRAME_REPETITION_TIME 80.0e-3 // SIRCS/SAMSUNG32/NUBERT: automatic repetition after 25-50ms
|
|
||||||
// KASEIKYO: automatic repetition after 75ms
|
|
||||||
|
|
||||||
#define TRUE 1
|
|
||||||
#define FALSE 0
|
|
||||||
|
|
||||||
#define IRMP_FLAG_REPETITION 0x01
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t protocol; // protocol, i.e. NEC_PROTOCOL
|
|
||||||
uint16_t address; // address
|
|
||||||
uint16_t command; // command
|
|
||||||
uint8_t flags; // flags, e.g. repetition
|
|
||||||
} IRMP_DATA;
|
|
||||||
|
|
||||||
extern void irmp_init(void);
|
|
||||||
extern uint8_t irmp_get_data(IRMP_DATA *);
|
|
||||||
extern uint8_t irmp_is_busy(void);
|
|
||||||
extern uint8_t irmp_ISR(uint8_t);
|
|
||||||
|
|
||||||
#if IRMP_PROTOCOL_NAMES == 1
|
|
||||||
extern char *irmp_protocol_names[IRMP_N_PROTOCOLS + 1];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_USE_CALLBACK == 1
|
|
||||||
extern void irmp_set_callback_ptr(void (*cb)(uint8_t));
|
|
||||||
#endif // IRSND_USE_CALLBACK == 1
|
|
||||||
|
|
||||||
#endif /* _WC_IRMP_H_ */
|
|
@@ -1,191 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* irmpconfig.h
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009-2011 Frank Meyer - frank(at)fli4l.de
|
|
||||||
*
|
|
||||||
* $Id: irmpconfig.h,v 1.80 2012/02/21 08:41:46 fm Exp $
|
|
||||||
*
|
|
||||||
* ATMEGA88 @ 8 MHz
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _IRMPCONFIG_H_
|
|
||||||
#define _IRMPCONFIG_H_
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Change F_INTERRUPTS if you change the number of interrupts per second,
|
|
||||||
* Normally, F_INTERRUPTS should be in the range from 10000 to 15000, typical is 15000
|
|
||||||
* A value above 15000 costs additional program space, absolute maximum value is 20000.
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#ifndef F_INTERRUPTS
|
|
||||||
#define F_INTERRUPTS 15000 // interrupts per second, min: 10000, max: 20000, typ: 15000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Change settings from 1 to 0 if you want to disable one or more decoders.
|
|
||||||
* This saves program space.
|
|
||||||
*
|
|
||||||
* 1 enable decoder
|
|
||||||
* 0 disable decoder
|
|
||||||
*
|
|
||||||
* The standard decoders are enabled per default.
|
|
||||||
* Less common protocols are disabled here, you need to enable them manually.
|
|
||||||
*
|
|
||||||
* If you want to use FDC or RCCAR simultaneous with RC5 protocol, additional program space is required.
|
|
||||||
* If you don't need RC5 when using FDC/RCCAR, you should disable RC5.
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
// typical protocols, disable here! Enable Remarks F_INTERRUPTS Program Space
|
|
||||||
#define IRMP_SUPPORT_SIRCS_PROTOCOL 1 // Sony SIRCS >= 10000 ~150 bytes
|
|
||||||
#define IRMP_SUPPORT_NEC_PROTOCOL 1 // NEC + APPLE >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_SAMSUNG_PROTOCOL 1 // Samsung + Samsung32 >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_MATSUSHITA_PROTOCOL 1 // Matsushita >= 10000 ~50 bytes
|
|
||||||
#define IRMP_SUPPORT_KASEIKYO_PROTOCOL 1 // Kaseikyo >= 10000 ~250 bytes
|
|
||||||
#define IRMP_SUPPORT_DENON_PROTOCOL 1 // DENON, Sharp >= 10000 ~250 bytes
|
|
||||||
|
|
||||||
// more protocols, enable here! Enable Remarks F_INTERRUPTS Program Space
|
|
||||||
#define IRMP_SUPPORT_RC5_PROTOCOL 0 // RC5 >= 10000 ~250 bytes
|
|
||||||
#define IRMP_SUPPORT_RC6_PROTOCOL 0 // RC6 & RC6A >= 10000 ~250 bytes
|
|
||||||
#define IRMP_SUPPORT_JVC_PROTOCOL 0 // JVC >= 10000 ~150 bytes
|
|
||||||
#define IRMP_SUPPORT_NEC16_PROTOCOL 0 // NEC16 >= 10000 ~100 bytes
|
|
||||||
#define IRMP_SUPPORT_NEC42_PROTOCOL 0 // NEC42 >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_IR60_PROTOCOL 0 // IR60 (SAB2008) >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_GRUNDIG_PROTOCOL 0 // Grundig >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_SIEMENS_PROTOCOL 0 // Siemens Gigaset >= 15000 ~550 bytes
|
|
||||||
#define IRMP_SUPPORT_NOKIA_PROTOCOL 0 // Nokia >= 10000 ~300 bytes
|
|
||||||
|
|
||||||
// exotic protocols, enable here! Enable Remarks F_INTERRUPTS Program Space
|
|
||||||
#define IRMP_SUPPORT_GRUNDIG2_PROTOCOL 0 // Grundig TP400 >= 10000 ~300 bytes
|
|
||||||
#define IRMP_SUPPORT_KATHREIN_PROTOCOL 0 // Kathrein >= 10000 ~200 bytes
|
|
||||||
#define IRMP_SUPPORT_NUBERT_PROTOCOL 0 // NUBERT >= 10000 ~50 bytes
|
|
||||||
#define IRMP_SUPPORT_BANG_OLUFSEN_PROTOCOL 0 // Bang & Olufsen >= 10000 ~200 bytes
|
|
||||||
#define IRMP_SUPPORT_RECS80_PROTOCOL 0 // RECS80 (SAA3004) >= 15000 ~50 bytes
|
|
||||||
#define IRMP_SUPPORT_RECS80EXT_PROTOCOL 0 // RECS80EXT (SAA3008) >= 15000 ~50 bytes
|
|
||||||
#define IRMP_SUPPORT_THOMSON_PROTOCOL 0 // Thomson >= 10000 ~250 bytes
|
|
||||||
#define IRMP_SUPPORT_NIKON_PROTOCOL 0 // NIKON camera >= 10000 ~250 bytes
|
|
||||||
#define IRMP_SUPPORT_NETBOX_PROTOCOL 0 // Netbox keyboard >= 10000 ~400 bytes (PROTOTYPE!)
|
|
||||||
#define IRMP_SUPPORT_FDC_PROTOCOL 0 // FDC3402 keyboard >= 10000 (better 15000) ~150 bytes (~400 in combination with RC5)
|
|
||||||
#define IRMP_SUPPORT_RCCAR_PROTOCOL 0 // RC Car >= 10000 (better 15000) ~150 bytes (~500 in combination with RC5)
|
|
||||||
#define IRMP_SUPPORT_RUWIDO_PROTOCOL 0 // RUWIDO, T-Home >= 15000 ~550 bytes
|
|
||||||
#define IRMP_SUPPORT_LEGO_PROTOCOL 0 // LEGO Power RC >= 20000 ~150 bytes
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Change hardware pin here:
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#if defined (PIC_C18) // Microchip C18 Compiler
|
|
||||||
#include <p18cxxx.h> // main PIC18 h file
|
|
||||||
#define IRMP_PIN PORTBbits.RB4 // use RB4 as IR input on PIC
|
|
||||||
#define input(x) (x)
|
|
||||||
|
|
||||||
#elif defined (PIC_CCS_COMPILER) // PIC CCS Compiler:
|
|
||||||
#define IRMP_PIN PIN_B4 // use PB4 as IR input on PIC
|
|
||||||
|
|
||||||
#else // AVR:
|
|
||||||
|
|
||||||
#ifndef ARDUINO
|
|
||||||
#define IRMP_PORT PORTB
|
|
||||||
#define IRMP_DDR DDRB
|
|
||||||
#define IRMP_PIN PINB
|
|
||||||
#define IRMP_BIT 6 // use PB6 as IR input on AVR
|
|
||||||
#else // ARDUINO
|
|
||||||
#define IRMP_PIN PIND // use digital pin 2 as IR input
|
|
||||||
#define IRMP_BIT 2 // on arduino
|
|
||||||
#endif // ARDUINO
|
|
||||||
|
|
||||||
#define input(x) ((x) & (1 << IRMP_BIT))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Set IRMP_LOGGING to 1 if want to log data to UART with 9600Bd
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#ifndef IRMP_LOGGING
|
|
||||||
#define IRMP_LOGGING 0 // 1: log IR signal (scan), 0: do not (default)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Use external logging routines
|
|
||||||
* If you enable external logging, you have also to enable IRMP_LOGGING above
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#ifndef IRMP_EXT_LOGGING
|
|
||||||
#define IRMP_EXT_LOGGING 0 // 1:log, 0: do not log ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Set IRMP_PROTOCOL_NAMES to 1 if want to access protocol names (for logging etc), costs ~300 bytes RAM!
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#define IRMP_PROTOCOL_NAMES 0 // 1: access protocol names, 0: do not (default),
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* Use Callbacks to indicate input signal
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#define IRMP_USE_CALLBACK 0 // flag: 0 = don't use callbacks, 1 = use callbacks, default is 0
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
* DO NOT CHANGE THE FOLLOWING LINES !
|
|
||||||
*---------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
#if IRMP_SUPPORT_SIEMENS_PROTOCOL == 1 && F_INTERRUPTS < 15000
|
|
||||||
# warning F_INTERRUPTS too low, SIEMENS protocol disabled (should be at least 15000)
|
|
||||||
# undef IRMP_SUPPORT_SIEMENS_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_SIEMENS_PROTOCOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_RUWIDO_PROTOCOL == 1 && F_INTERRUPTS < 15000
|
|
||||||
# warning F_INTERRUPTS too low, RUWIDO protocol disabled (should be at least 15000)
|
|
||||||
# undef IRMP_SUPPORT_RUWIDO_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_RUWIDO_PROTOCOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_RECS80_PROTOCOL == 1 && F_INTERRUPTS < 15000
|
|
||||||
# warning F_INTERRUPTS too low, RECS80 protocol disabled (should be at least 15000)
|
|
||||||
# undef IRMP_SUPPORT_RECS80_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_RECS80_PROTOCOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_RECS80EXT_PROTOCOL == 1 && F_INTERRUPTS < 15000
|
|
||||||
# warning F_INTERRUPTS too low, RECS80EXT protocol disabled (should be at least 15000)
|
|
||||||
# undef IRMP_SUPPORT_RECS80EXT_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_RECS80EXT_PROTOCOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_LEGO_PROTOCOL == 1 && F_INTERRUPTS < 20000
|
|
||||||
# warning F_INTERRUPTS too low, LEGO protocol disabled (should be at least 20000)
|
|
||||||
# undef IRMP_SUPPORT_LEGO_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_LEGO_PROTOCOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_JVC_PROTOCOL == 1 && IRMP_SUPPORT_NEC_PROTOCOL == 0
|
|
||||||
# warning JVC protocol needs also NEC protocol, NEC protocol enabled
|
|
||||||
# undef IRMP_SUPPORT_NEC_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_NEC_PROTOCOL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_NEC16_PROTOCOL == 1 && IRMP_SUPPORT_NEC_PROTOCOL == 0
|
|
||||||
# warning NEC16 protocol needs also NEC protocol, NEC protocol enabled
|
|
||||||
# undef IRMP_SUPPORT_NEC_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_NEC_PROTOCOL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IRMP_SUPPORT_NEC42_PROTOCOL == 1 && IRMP_SUPPORT_NEC_PROTOCOL == 0
|
|
||||||
# warning NEC42 protocol needs also NEC protocol, NEC protocol enabled
|
|
||||||
# undef IRMP_SUPPORT_NEC_PROTOCOL
|
|
||||||
# define IRMP_SUPPORT_NEC_PROTOCOL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if F_INTERRUPTS > 20000
|
|
||||||
#error F_INTERRUPTS too high (should be not greater than 20000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _WC_IRMPCONFIG_H_ */
|
|
@@ -1,456 +0,0 @@
|
|||||||
/*
|
|
||||||
* Simulate a linux input device via uinput
|
|
||||||
* Get lirc remote events, decode with IRMP and inject them via uinput
|
|
||||||
*
|
|
||||||
* (C) 2012 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* the C++ compiler did not like this code, so let's put it into a
|
|
||||||
* separate file and compile with gcc insead of g++...
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <linux/ioctl.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/uinput.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <aotom_main.h>
|
|
||||||
|
|
||||||
#include "lirmp_input.h"
|
|
||||||
extern "C" {
|
|
||||||
#include "irmp.h"
|
|
||||||
}
|
|
||||||
static uint8_t IRMP_PIN;
|
|
||||||
|
|
||||||
#include <hal_debug.h>
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_INIT, NULL, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_INIT, NULL, args)
|
|
||||||
|
|
||||||
/* same defines as in neutrino's rcinput.h */
|
|
||||||
#define KEY_TTTV KEY_FN_1
|
|
||||||
#define KEY_TTZOOM KEY_FN_2
|
|
||||||
#define KEY_REVEAL KEY_FN_D
|
|
||||||
/* only defined in newer kernels / headers... */
|
|
||||||
#ifndef KEY_ZOOMIN
|
|
||||||
#define KEY_ZOOMIN KEY_FN_E
|
|
||||||
#endif
|
|
||||||
#ifndef KEY_ZOOMOUT
|
|
||||||
#define KEY_ZOOMOUT KEY_FN_F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t ir; /* IR command */
|
|
||||||
int code; /* input key code */
|
|
||||||
} key_map_t;
|
|
||||||
|
|
||||||
static const key_map_t key_map[] =
|
|
||||||
{
|
|
||||||
{ 0x13, KEY_0 },
|
|
||||||
{ 0x1a, KEY_1 },
|
|
||||||
{ 0x1f, KEY_2 },
|
|
||||||
{ 0x58, KEY_3 },
|
|
||||||
{ 0x16, KEY_4 },
|
|
||||||
{ 0x1b, KEY_5 },
|
|
||||||
{ 0x54, KEY_6 },
|
|
||||||
{ 0x12, KEY_7 },
|
|
||||||
{ 0x17, KEY_8 },
|
|
||||||
{ 0x50, KEY_9 },
|
|
||||||
{ 0x5f, KEY_OK },
|
|
||||||
{ 0x59, KEY_TIME },
|
|
||||||
{ 0x43, KEY_FAVORITES },
|
|
||||||
{ 0x4f, KEY_SAT },
|
|
||||||
{ 0x0f, KEY_NEXT }, /* V.Format */
|
|
||||||
{ 0x1e, KEY_POWER },
|
|
||||||
{ 0x5a, KEY_MUTE },
|
|
||||||
{ 0x1c, KEY_MENU },
|
|
||||||
{ 0x5d, KEY_EPG },
|
|
||||||
{ 0x07, KEY_INFO },
|
|
||||||
{ 0x60, KEY_EXIT },
|
|
||||||
{ 0x48, KEY_PAGEUP },
|
|
||||||
{ 0x44, KEY_PAGEDOWN },
|
|
||||||
{ 0x02, KEY_LEFT },
|
|
||||||
{ 0x40, KEY_RIGHT },
|
|
||||||
{ 0x03, KEY_UP },
|
|
||||||
{ 0x5e, KEY_DOWN },
|
|
||||||
{ 0x0a, KEY_VOLUMEUP },
|
|
||||||
{ 0x06, KEY_VOLUMEDOWN },
|
|
||||||
{ 0x49, KEY_RED },
|
|
||||||
{ 0x4e, KEY_GREEN },
|
|
||||||
{ 0x11, KEY_YELLOW },
|
|
||||||
{ 0x4a, KEY_BLUE },
|
|
||||||
{ 0x4c, KEY_TV }, /* TV/Radio */
|
|
||||||
{ 0x5c, KEY_VIDEO }, /* FIND */
|
|
||||||
{ 0x19, KEY_AUDIO }, /* FOLDER */
|
|
||||||
/* KEY_AUX,
|
|
||||||
KEY_TEXT,
|
|
||||||
KEY_TTTV,
|
|
||||||
KEY_TTZOOM,
|
|
||||||
KEY_REVEAL,
|
|
||||||
*/
|
|
||||||
{ 0x01, KEY_REWIND },
|
|
||||||
{ 0x53, KEY_FORWARD },
|
|
||||||
{ 0x22, KEY_STOP },
|
|
||||||
{ 0x4d, KEY_PAUSE },
|
|
||||||
{ 0x15, KEY_PLAY },
|
|
||||||
{ 0x20, KEY_PREVIOUS },
|
|
||||||
{ 0x23, KEY_NEXT },
|
|
||||||
// KEY_EJECTCD,
|
|
||||||
{ 0x10, KEY_RECORD }
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int key_list[] =
|
|
||||||
{
|
|
||||||
KEY_0,
|
|
||||||
KEY_1,
|
|
||||||
KEY_2,
|
|
||||||
KEY_3,
|
|
||||||
KEY_4,
|
|
||||||
KEY_5,
|
|
||||||
KEY_6,
|
|
||||||
KEY_7,
|
|
||||||
KEY_8,
|
|
||||||
KEY_9,
|
|
||||||
KEY_OK,
|
|
||||||
KEY_TIME,
|
|
||||||
KEY_FAVORITES,
|
|
||||||
KEY_SAT,
|
|
||||||
KEY_ZOOMOUT,
|
|
||||||
KEY_ZOOMIN,
|
|
||||||
KEY_NEXT,
|
|
||||||
KEY_POWER,
|
|
||||||
KEY_MUTE,
|
|
||||||
KEY_MENU,
|
|
||||||
KEY_EPG,
|
|
||||||
KEY_INFO,
|
|
||||||
KEY_EXIT,
|
|
||||||
KEY_PAGEUP,
|
|
||||||
KEY_PAGEDOWN,
|
|
||||||
KEY_LEFT,
|
|
||||||
KEY_RIGHT,
|
|
||||||
KEY_UP,
|
|
||||||
KEY_DOWN,
|
|
||||||
KEY_VOLUMEUP,
|
|
||||||
KEY_VOLUMEDOWN,
|
|
||||||
KEY_RED,
|
|
||||||
KEY_GREEN,
|
|
||||||
KEY_YELLOW,
|
|
||||||
KEY_BLUE,
|
|
||||||
KEY_TV,
|
|
||||||
KEY_VIDEO,
|
|
||||||
KEY_AUDIO,
|
|
||||||
// KEY_AUX,
|
|
||||||
// KEY_TEXT,
|
|
||||||
// KEY_TTTV,
|
|
||||||
// KEY_TTZOOM,
|
|
||||||
// KEY_REVEAL,
|
|
||||||
KEY_REWIND,
|
|
||||||
KEY_STOP,
|
|
||||||
KEY_PAUSE,
|
|
||||||
KEY_PLAY,
|
|
||||||
KEY_FORWARD,
|
|
||||||
KEY_PREVIOUS,
|
|
||||||
KEY_NEXT,
|
|
||||||
// KEY_EJECTCD,
|
|
||||||
KEY_RECORD,
|
|
||||||
-1
|
|
||||||
};
|
|
||||||
|
|
||||||
static pthread_t thread;
|
|
||||||
static int thread_running;
|
|
||||||
|
|
||||||
static void *input_thread(void *)
|
|
||||||
{
|
|
||||||
int uinput;
|
|
||||||
struct input_event u;
|
|
||||||
struct uinput_user_dev ud;
|
|
||||||
FILE *f;
|
|
||||||
int lircfd;
|
|
||||||
int pulse;
|
|
||||||
int i = 0;
|
|
||||||
int last_pulse = 1;
|
|
||||||
int last_code = -1;
|
|
||||||
uint32_t lircdata; /* lirc_t to be correct... */
|
|
||||||
unsigned int count = 0; /* how many timeouts? */
|
|
||||||
unsigned int nodec = 0; /* how many timeouts since last decoded? */
|
|
||||||
int aotom_fd = -1;
|
|
||||||
IRMP_DATA d;
|
|
||||||
|
|
||||||
hal_info("LIRC/IRMP input converter thread starting...\n");
|
|
||||||
|
|
||||||
/* modprobe does not complain if the module is already loaded... */
|
|
||||||
system("/sbin/modprobe uinput");
|
|
||||||
do
|
|
||||||
{
|
|
||||||
usleep(100000); /* mdev needs some time to create the device? */
|
|
||||||
uinput = open("/dev/uinput", O_WRONLY | O_NDELAY);
|
|
||||||
}
|
|
||||||
while (uinput < 0 && ++count < 100);
|
|
||||||
|
|
||||||
if (uinput < 0)
|
|
||||||
{
|
|
||||||
hal_info("LIRC/IRMP input thread: unable to open /dev/uinput (%m)\n");
|
|
||||||
thread_running = 2;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fcntl(uinput, F_SETFD, FD_CLOEXEC);
|
|
||||||
ioctl(uinput, UI_SET_EVBIT, EV_KEY);
|
|
||||||
/* do not use kernel repeat EV_REP since neutrino will be confused by the
|
|
||||||
* generated SYN_REPORT events...
|
|
||||||
ioctl(uinput, UI_SET_EVBIT, EV_REP);
|
|
||||||
*/
|
|
||||||
/* register keys */
|
|
||||||
for (i = 0; key_list[i] != -1; i++)
|
|
||||||
ioctl(uinput, UI_SET_KEYBIT, key_list[i]);
|
|
||||||
|
|
||||||
/* configure the device */
|
|
||||||
memset(&ud, 0, sizeof(ud));
|
|
||||||
strncpy(ud.name, "Neutrino LIRC/IRMP to Input Device converter", UINPUT_MAX_NAME_SIZE);
|
|
||||||
ud.id.version = 0x42;
|
|
||||||
ud.id.vendor = 0x1234;
|
|
||||||
ud.id.product = 0x5678;
|
|
||||||
ud.id.bustype = BUS_I2C; /* ?? */
|
|
||||||
write(uinput, &ud, sizeof(ud));
|
|
||||||
|
|
||||||
if (ioctl(uinput, UI_DEV_CREATE))
|
|
||||||
{
|
|
||||||
hal_info("LIRC/IRMP input thread UI_DEV_CREATE: %m\n");
|
|
||||||
close(uinput);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this is ugly: parse the new input device from /proc/...devices
|
|
||||||
* and symlink it to /dev/input/nevis_ir... */
|
|
||||||
#define DEVLINE "I: Bus=0018 Vendor=1234 Product=5678 Version=0042"
|
|
||||||
f = fopen("/proc/bus/input/devices", "r");
|
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
int found = 0;
|
|
||||||
int evdev = -1;
|
|
||||||
size_t n = 0;
|
|
||||||
char *line = NULL;
|
|
||||||
char *p;
|
|
||||||
char newdev[20];
|
|
||||||
while (getline(&line, &n, f) != -1)
|
|
||||||
{
|
|
||||||
switch (line[0])
|
|
||||||
{
|
|
||||||
case 'I':
|
|
||||||
if (strncmp(line, DEVLINE, strlen(DEVLINE)) == 0)
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
if (! found)
|
|
||||||
break;
|
|
||||||
p = strstr(line, " event");
|
|
||||||
if (! p)
|
|
||||||
{
|
|
||||||
evdev = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
evdev = atoi(p + 6);
|
|
||||||
sprintf(newdev, "event%d", evdev);
|
|
||||||
hal_info("LIRC/IRMP input thread: symlink /dev/input/nevis_ir to %s\n", newdev);
|
|
||||||
unlink("/dev/input/nevis_ir");
|
|
||||||
symlink(newdev, "/dev/input/nevis_ir");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (evdev != -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
free(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
u.type = EV_KEY;
|
|
||||||
u.value = 0; /* initialize: first event wil be a key press */
|
|
||||||
|
|
||||||
lircfd = open("/dev/lirc", O_RDONLY);
|
|
||||||
if (lircfd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: open /dev/lirc: %m\n", __func__);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
IRMP_PIN = 0xFF;
|
|
||||||
|
|
||||||
/* 50 ms. This should be longer than the longest light pulse */
|
|
||||||
#define POLL_MS (100 * 1000)
|
|
||||||
#define LIRC_PULSE 0x01000000
|
|
||||||
#define LIRC_PULSE_MASK 0x00FFFFFF
|
|
||||||
hal_info("LIRC/IRMP input converter going into main loop...\n");
|
|
||||||
|
|
||||||
aotom_fd = open("/dev/vfd", O_RDONLY);
|
|
||||||
|
|
||||||
/* TODO: ioctl to find out if we have a compatible LIRC_MODE2 device */
|
|
||||||
thread_running = 1;
|
|
||||||
while (thread_running)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
struct timeval tv;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(lircfd, &fds);
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = POLL_MS;
|
|
||||||
/* any singal can interrupt select. we rely on the linux-only feature
|
|
||||||
* that the timeout is automatcally recalculated in this case! */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ret = select(lircfd + 1, &fds, NULL, NULL, &tv);
|
|
||||||
}
|
|
||||||
while (ret == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
/* errno != EINTR... */
|
|
||||||
hal_info("%s: lirmp: lircfd select: %m\n", __func__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
nodec++;
|
|
||||||
lircdata = POLL_MS; /* timeout */
|
|
||||||
pulse = !last_pulse; /* lirc sends data on signal change */
|
|
||||||
if (last_code != -1 && nodec > 1)
|
|
||||||
{
|
|
||||||
// fprintf(stderr, "timeout!\n");
|
|
||||||
u.code = last_code;
|
|
||||||
u.value = 0; /* release */
|
|
||||||
write(uinput, &u, sizeof(u));
|
|
||||||
last_code = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (read(lircfd, &lircdata, sizeof(lircdata)) != sizeof(lircdata))
|
|
||||||
{
|
|
||||||
perror("read");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pulse = (lircdata & LIRC_PULSE); /* we got light... */
|
|
||||||
last_pulse = pulse;
|
|
||||||
lircdata &= LIRC_PULSE_MASK; /* how long the pulse was in microseconds */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret && count)
|
|
||||||
{
|
|
||||||
if (count * POLL_MS > lircdata)
|
|
||||||
lircdata = 0;
|
|
||||||
else
|
|
||||||
lircdata -= count * POLL_MS;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
//printf("lircdata: ret:%d c:%d %d\n", ret, ch - '0', lircdata);
|
|
||||||
lircdata /= (1000000 / F_INTERRUPTS);
|
|
||||||
|
|
||||||
if (pulse)
|
|
||||||
IRMP_PIN = 0x00;
|
|
||||||
else
|
|
||||||
IRMP_PIN = 0xff;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
(void) irmp_ISR(IRMP_PIN);
|
|
||||||
if (irmp_get_data(&d))
|
|
||||||
{
|
|
||||||
nodec = 0;
|
|
||||||
hal_debug("irmp_get_data proto: %2d addr: 0x%04x cmd: 0x%04x fl: %d\n",
|
|
||||||
d.protocol, d.address, d.command, d.flags);
|
|
||||||
|
|
||||||
/* todo: do we need to complete the loop if we already
|
|
||||||
* detected the singal in this pulse? */
|
|
||||||
if (d.protocol == IRMP_NEC_PROTOCOL && d.address == 0xba45)
|
|
||||||
{
|
|
||||||
for (i = 0; i < (int)(sizeof(key_map) / sizeof(key_map_t)); i++)
|
|
||||||
{
|
|
||||||
if (key_map[i].ir == d.command)
|
|
||||||
{
|
|
||||||
if (last_code != -1 && last_code != key_map[i].code)
|
|
||||||
{
|
|
||||||
u.code = last_code;
|
|
||||||
u.value = 0;
|
|
||||||
write(uinput, &u, sizeof(u));
|
|
||||||
}
|
|
||||||
u.code = key_map[i].code;
|
|
||||||
u.value = (d.flags & 0x1) + 1;
|
|
||||||
//hal_debug("uinput write: value: %d code: %d\n", u.value, u.code);
|
|
||||||
last_code = u.code;
|
|
||||||
write(uinput, &u, sizeof(u));
|
|
||||||
if (aotom_fd > -1)
|
|
||||||
{
|
|
||||||
struct aotom_ioctl_data vfd_data;
|
|
||||||
vfd_data.u.led.led_nr = 1;
|
|
||||||
vfd_data.u.led.on = 10;
|
|
||||||
ioctl(aotom_fd, VFDSETLED, &vfd_data);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (lircdata-- > 0);
|
|
||||||
}
|
|
||||||
/* clean up */
|
|
||||||
close(lircfd);
|
|
||||||
|
|
||||||
if (aotom_fd > -1)
|
|
||||||
close(aotom_fd);
|
|
||||||
|
|
||||||
out:
|
|
||||||
ioctl(uinput, UI_DEV_DESTROY);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start_input_thread(void)
|
|
||||||
{
|
|
||||||
if (pthread_create(&thread, 0, input_thread, NULL) != 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: LIRC/IRMP input thread pthread_create: %m\n", __func__);
|
|
||||||
thread_running = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* wait until the device is created before continuing */
|
|
||||||
while (! thread_running)
|
|
||||||
usleep(1000);
|
|
||||||
if (thread_running == 2) /* failed... :-( */
|
|
||||||
thread_running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_input_thread(void)
|
|
||||||
{
|
|
||||||
if (! thread_running)
|
|
||||||
return;
|
|
||||||
thread_running = 0;
|
|
||||||
pthread_join(thread, NULL);
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
/* functions from lirmp_input.cpp */
|
|
||||||
|
|
||||||
#ifndef __LIRMP_INPUT_H_
|
|
||||||
#define __LIRMP_INPUT_H_
|
|
||||||
void start_input_thread(void);
|
|
||||||
void stop_input_thread(void);
|
|
||||||
#endif
|
|
@@ -1,509 +0,0 @@
|
|||||||
#define __USE_FILE_OFFSET64 1
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <audio_lib.h>
|
|
||||||
#include <video_lib.h>
|
|
||||||
|
|
||||||
#include "player.h"
|
|
||||||
#include "playback_libeplayer3.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_PLAYBACK, this, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_PLAYBACK, this, args)
|
|
||||||
|
|
||||||
extern cAudio *audioDecoder;
|
|
||||||
extern cVideo *videoDecoder;
|
|
||||||
|
|
||||||
//Used by Fileplay
|
|
||||||
bool cPlayback::Open(playmode_t PlayMode)
|
|
||||||
{
|
|
||||||
if (PlayMode != PLAYMODE_TS)
|
|
||||||
{
|
|
||||||
audioDecoder->closeDevice();
|
|
||||||
videoDecoder->closeDevice();
|
|
||||||
decoders_closed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pm = PlayMode;
|
|
||||||
fn_ts = "";
|
|
||||||
fn_xml = "";
|
|
||||||
last_size = 0;
|
|
||||||
nPlaybackSpeed = 0;
|
|
||||||
init_jump = -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::Close(void)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
|
|
||||||
//Dagobert: movieplayer does not call stop, it calls close ;)
|
|
||||||
Stop();
|
|
||||||
if (decoders_closed)
|
|
||||||
{
|
|
||||||
audioDecoder->openDevice();
|
|
||||||
videoDecoder->openDevice();
|
|
||||||
decoders_closed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::Start(std::string filename, std::string headers)
|
|
||||||
{
|
|
||||||
return Start((char *) filename.c_str(), 0, 0, 0, 0, 0, headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::Start(char *filename, int vpid, int vtype, int apid, int ac3, int, std::string headers)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
bool isHTTP = false;
|
|
||||||
no_probe = false;
|
|
||||||
|
|
||||||
hal_info("%s - filename=%s vpid=%u vtype=%d apid=%u ac3=%d\n", __func__, filename, vpid, vtype, apid, ac3);
|
|
||||||
|
|
||||||
init_jump = -1;
|
|
||||||
|
|
||||||
unlink("/tmp/.id3coverart");
|
|
||||||
|
|
||||||
std::string file;
|
|
||||||
if (*filename == '/')
|
|
||||||
file = "file://";
|
|
||||||
file += filename;
|
|
||||||
|
|
||||||
if ((file.find(":31339/id=") != std::string::npos) || (file.find(":10000") != std::string::npos) || (file.find(":8001/") != std::string::npos)) // for LocalTV and Entertain-TV streaming
|
|
||||||
no_probe = true;
|
|
||||||
|
|
||||||
if (file.substr(0, 7) == "file://")
|
|
||||||
{
|
|
||||||
if (file.substr(file.length() - 3) == ".ts")
|
|
||||||
{
|
|
||||||
fn_ts = file.substr(7);
|
|
||||||
fn_xml = file.substr(7, file.length() - 9);
|
|
||||||
fn_xml += "xml";
|
|
||||||
no_probe = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
isHTTP = true;
|
|
||||||
|
|
||||||
if (player->Open(file.c_str(), no_probe, headers))
|
|
||||||
{
|
|
||||||
if (pm == PLAYMODE_TS)
|
|
||||||
{
|
|
||||||
struct stat64 s;
|
|
||||||
if (!stat64(file.c_str(), &s))
|
|
||||||
last_size = s.st_size;
|
|
||||||
ret = true;
|
|
||||||
videoDecoder->Stop(false);
|
|
||||||
audioDecoder->Stop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::vector<std::string> keys, values;
|
|
||||||
int selected_program = 0;
|
|
||||||
if (vpid || apid)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else if (GetPrograms(keys, values) && (keys.size() > 1) && ProgramSelectionCallback)
|
|
||||||
{
|
|
||||||
const char *key = ProgramSelectionCallback(ProgramSelectionCallbackData, keys, values);
|
|
||||||
if (!key)
|
|
||||||
{
|
|
||||||
player->Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
selected_program = atoi(key);
|
|
||||||
}
|
|
||||||
else if (keys.size() > 0)
|
|
||||||
selected_program = atoi(keys[0].c_str());
|
|
||||||
|
|
||||||
if (!keys.size() || !player->SelectProgram(selected_program))
|
|
||||||
{
|
|
||||||
if (apid)
|
|
||||||
SetAPid(apid);
|
|
||||||
if (vpid)
|
|
||||||
SetVPid(vpid);
|
|
||||||
}
|
|
||||||
playing = true;
|
|
||||||
player->output.Open();
|
|
||||||
ret = player->Play();
|
|
||||||
if (ret && !isHTTP)
|
|
||||||
playing = ret = player->Pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::Stop(void)
|
|
||||||
{
|
|
||||||
hal_info("%s playing %d\n", __func__, playing);
|
|
||||||
|
|
||||||
player->Stop();
|
|
||||||
player->output.Close();
|
|
||||||
player->Close();
|
|
||||||
|
|
||||||
playing = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetAPid(int pid, bool /* ac3 */)
|
|
||||||
{
|
|
||||||
hal_info("%s:(%d)\n", __func__, pid);
|
|
||||||
return player->SwitchAudio(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetVPid(int pid)
|
|
||||||
{
|
|
||||||
return player->SwitchVideo(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetSubtitlePid(int pid)
|
|
||||||
{
|
|
||||||
return player->SwitchSubtitle(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetTeletextPid(int pid)
|
|
||||||
{
|
|
||||||
return player->SwitchTeletext(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetSpeed(int speed)
|
|
||||||
{
|
|
||||||
hal_info("%s playing %d speed %d\n", __func__, playing, speed);
|
|
||||||
|
|
||||||
if (!decoders_closed)
|
|
||||||
{
|
|
||||||
audioDecoder->closeDevice();
|
|
||||||
videoDecoder->closeDevice();
|
|
||||||
decoders_closed = true;
|
|
||||||
usleep(500000);
|
|
||||||
player->output.Open();
|
|
||||||
playing = player->Play();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool res = true;
|
|
||||||
|
|
||||||
nPlaybackSpeed = speed;
|
|
||||||
|
|
||||||
if (speed > 1)
|
|
||||||
{
|
|
||||||
/* direction switch ? */
|
|
||||||
if (player->isBackWard)
|
|
||||||
player->FastBackward(0);
|
|
||||||
res = player->FastForward(speed);
|
|
||||||
}
|
|
||||||
else if (speed < 0)
|
|
||||||
{
|
|
||||||
/* direction switch ? */
|
|
||||||
if (player->isForwarding)
|
|
||||||
player->Continue();
|
|
||||||
res = player->FastBackward(speed);
|
|
||||||
}
|
|
||||||
else if (speed == 0)
|
|
||||||
{
|
|
||||||
/* konfetti: hmmm accessing the member isn't very proper */
|
|
||||||
if ((player->isForwarding) || (!player->isBackWard))
|
|
||||||
/* res = */ player->Pause();
|
|
||||||
else
|
|
||||||
/* res = */ player->FastForward(0);
|
|
||||||
}
|
|
||||||
else /* speed == 1 */
|
|
||||||
{
|
|
||||||
res = player->Continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (init_jump > -1)
|
|
||||||
{
|
|
||||||
SetPosition(init_jump);
|
|
||||||
init_jump = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::GetSpeed(int &speed) const
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
speed = nPlaybackSpeed;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::GetPts(uint64_t &pts)
|
|
||||||
{
|
|
||||||
player->GetPts((int64_t &) pts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// in milliseconds
|
|
||||||
bool cPlayback::GetPosition(int &position, int &duration)
|
|
||||||
{
|
|
||||||
bool got_duration = false;
|
|
||||||
hal_debug("%s %d %d\n", __func__, position, duration);
|
|
||||||
|
|
||||||
/* hack: if the file is growing (timeshift), then determine its length
|
|
||||||
* by comparing the mtime with the mtime of the xml file */
|
|
||||||
if (pm == PLAYMODE_TS)
|
|
||||||
{
|
|
||||||
struct stat64 s;
|
|
||||||
if (!stat64(fn_ts.c_str(), &s))
|
|
||||||
{
|
|
||||||
if (!playing || last_size != s.st_size)
|
|
||||||
{
|
|
||||||
last_size = s.st_size;
|
|
||||||
time_t curr_time = s.st_mtime;
|
|
||||||
if (!stat64(fn_xml.c_str(), &s))
|
|
||||||
{
|
|
||||||
duration = (curr_time - s.st_mtime) * 1000;
|
|
||||||
if (!playing)
|
|
||||||
return true;
|
|
||||||
got_duration = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!player->isPlaying)
|
|
||||||
{
|
|
||||||
hal_info("%s !!!!EOF!!!! < -1\n", __func__);
|
|
||||||
position = duration + 1000;
|
|
||||||
// duration = 0;
|
|
||||||
// this is stupid
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t vpts = 0;
|
|
||||||
player->GetPts(vpts);
|
|
||||||
|
|
||||||
if (vpts <= 0)
|
|
||||||
{
|
|
||||||
//printf("ERROR: vpts==0");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* len is in nanoseconds. we have 90 000 pts per second. */
|
|
||||||
position = vpts / 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (got_duration)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
int64_t length = 0;
|
|
||||||
|
|
||||||
player->GetDuration(length);
|
|
||||||
|
|
||||||
if (length <= 0)
|
|
||||||
duration = position + AV_TIME_BASE / 1000;
|
|
||||||
else
|
|
||||||
duration = length * 1000 / AV_TIME_BASE;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetPosition(int position, bool absolute)
|
|
||||||
{
|
|
||||||
hal_info("%s %d\n", __func__, position);
|
|
||||||
if (!playing)
|
|
||||||
{
|
|
||||||
/* the calling sequence is:
|
|
||||||
* Start() - paused
|
|
||||||
* SetPosition() - which fails if not running
|
|
||||||
* SetSpeed() - to start playing
|
|
||||||
* so let's remember the initial jump position and later jump to it
|
|
||||||
*/
|
|
||||||
init_jump = position;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
player->Seek((int64_t)position * (AV_TIME_BASE / 1000), absolute);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::FindAllPids(int *pids, unsigned int *ac3flags, unsigned int *numpids, std::string *language)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
if (IsPlaying())
|
|
||||||
{
|
|
||||||
std::vector<Track> tracks = player->manager.getAudioTracks();
|
|
||||||
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < *numpids; ++it)
|
|
||||||
{
|
|
||||||
pids[i] = it->pid;
|
|
||||||
ac3flags[i] = it->ac3flags;
|
|
||||||
language[i] = it->title;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*numpids = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::FindAllSubtitlePids(int *pids, unsigned int *numpids, std::string *language)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
std::vector<Track> tracks = player->manager.getSubtitleTracks();
|
|
||||||
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < *numpids; ++it)
|
|
||||||
{
|
|
||||||
pids[i] = it->pid;
|
|
||||||
language[i] = it->title;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*numpids = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::FindAllTeletextsubtitlePids(int *pids, unsigned int *numpids, std::string *language, int *mags, int *pages)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
std::vector<Track> tracks = player->manager.getTeletextTracks();
|
|
||||||
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < *numpids; ++it)
|
|
||||||
{
|
|
||||||
if (it->type != 2 && it->type != 5) // return subtitles only
|
|
||||||
continue;
|
|
||||||
pids[i] = it->pid;
|
|
||||||
language[i] = it->title;
|
|
||||||
mags[i] = it->mag;
|
|
||||||
pages[i] = it->page;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*numpids = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPlayback::GetFirstTeletextPid(void)
|
|
||||||
{
|
|
||||||
std::vector<Track> tracks = player->manager.getTeletextTracks();
|
|
||||||
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->type == 1)
|
|
||||||
return it->pid;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dummy functions for subtitles */
|
|
||||||
void cPlayback::FindAllSubs(uint16_t * /*pids*/, unsigned short * /*supp*/, uint16_t *num, std::string * /*lang*/)
|
|
||||||
{
|
|
||||||
*num = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SelectSubtitles(int /*pid*/)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::GetTitles(std::vector<int> &playlists, std::vector<std::string> &titles, int ¤t)
|
|
||||||
{
|
|
||||||
playlists.clear();
|
|
||||||
titles.clear();
|
|
||||||
current = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::SetTitle(int /*title*/)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::GetChapters(std::vector<int> &positions, std::vector<std::string> &titles)
|
|
||||||
{
|
|
||||||
player->GetChapters(positions, titles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values)
|
|
||||||
{
|
|
||||||
player->input.GetMetadata(keys, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
cPlayback::cPlayback(int num __attribute__((unused)))
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
playing = false;
|
|
||||||
decoders_closed = false;
|
|
||||||
ProgramSelectionCallback = NULL;
|
|
||||||
ProgramSelectionCallbackData = NULL;
|
|
||||||
|
|
||||||
player = new Player();
|
|
||||||
}
|
|
||||||
|
|
||||||
cPlayback::~cPlayback()
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
delete player;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::RequestAbort()
|
|
||||||
{
|
|
||||||
player->RequestAbort();
|
|
||||||
while (player->isPlaying)
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::IsPlaying()
|
|
||||||
{
|
|
||||||
return player->isPlaying;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cPlayback::GetReadCount()
|
|
||||||
{
|
|
||||||
return player->readCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPlayback::GetAPid(void)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
return player->GetAudioPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPlayback::GetVPid(void)
|
|
||||||
{
|
|
||||||
return player->GetVideoPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPlayback::GetSubtitlePid(void)
|
|
||||||
{
|
|
||||||
return player->GetSubtitlePid();
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPlayback::GetTeletextPid(void)
|
|
||||||
{
|
|
||||||
return player->GetTeletextPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
AVFormatContext *cPlayback::GetAVFormatContext()
|
|
||||||
{
|
|
||||||
return player ? player->GetAVFormatContext() : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::ReleaseAVFormatContext()
|
|
||||||
{
|
|
||||||
if (player)
|
|
||||||
player->ReleaseAVFormatContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values)
|
|
||||||
{
|
|
||||||
return player->GetPrograms(keys, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SelectProgram(std::string &key)
|
|
||||||
{
|
|
||||||
return player->SelectProgram(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::SetProgramSelectionCallback(const char *(*fun)(void *, std::vector<std::string> &keys, std::vector<std::string> &values), void *opaque)
|
|
||||||
{
|
|
||||||
ProgramSelectionCallback = fun;
|
|
||||||
ProgramSelectionCallbackData = opaque;
|
|
||||||
}
|
|
@@ -1,94 +0,0 @@
|
|||||||
#ifndef __PLAYBACK_LIBEPLAYER3_H__
|
|
||||||
#define __PLAYBACK_LIBEPLAYER3_H__
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
PLAYMODE_TS = 0,
|
|
||||||
PLAYMODE_FILE
|
|
||||||
} playmode_t;
|
|
||||||
|
|
||||||
class Player;
|
|
||||||
struct AVFormatContext;
|
|
||||||
|
|
||||||
class cPlayback
|
|
||||||
{
|
|
||||||
friend class CStreamInfo2;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool enabled;
|
|
||||||
bool playing;
|
|
||||||
bool no_probe;
|
|
||||||
int nPlaybackSpeed;
|
|
||||||
bool Stop(void);
|
|
||||||
bool decoders_closed;
|
|
||||||
playmode_t pm;
|
|
||||||
std::string fn_ts;
|
|
||||||
std::string fn_xml;
|
|
||||||
off64_t last_size;
|
|
||||||
int init_jump;
|
|
||||||
Player *player;
|
|
||||||
const char *(*ProgramSelectionCallback)(void *, std::vector<std::string> &keys, std::vector<std::string> &values);
|
|
||||||
void *ProgramSelectionCallbackData;
|
|
||||||
|
|
||||||
bool GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values);
|
|
||||||
bool SelectProgram(std::string &key);
|
|
||||||
public:
|
|
||||||
cPlayback(int num = 0);
|
|
||||||
~cPlayback();
|
|
||||||
|
|
||||||
bool Open(playmode_t PlayMode);
|
|
||||||
void Close(void);
|
|
||||||
bool Start(char *filename, int vpid, int vtype, int apid, int ac3, int duration, std::string headers = "");
|
|
||||||
bool Start(std::string filename, std::string headers = "");
|
|
||||||
bool SetAPid(int pid, bool ac3 = false);
|
|
||||||
bool SetVPid(int pid);
|
|
||||||
bool SetSubtitlePid(int pid);
|
|
||||||
bool SetTeletextPid(int pid);
|
|
||||||
int GetAPid(void);
|
|
||||||
int GetVPid(void);
|
|
||||||
int GetSubtitlePid(void);
|
|
||||||
int GetTeletextPid(void);
|
|
||||||
int GetFirstTeletextPid(void);
|
|
||||||
bool SetSpeed(int speed);
|
|
||||||
bool GetSpeed(int &speed) const;
|
|
||||||
bool GetPosition(int &position, int &duration);
|
|
||||||
void GetPts(uint64_t &pts);
|
|
||||||
bool SetPosition(int position, bool absolute = false);
|
|
||||||
void FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *numpida, std::string *language);
|
|
||||||
void FindAllSubtitlePids(int *pids, unsigned int *numpids, std::string *language);
|
|
||||||
void FindAllTeletextsubtitlePids(int *pids, unsigned int *numpidt, std::string *tlanguage, int *mags, int *pages);
|
|
||||||
void RequestAbort(void);
|
|
||||||
bool IsPlaying(void);
|
|
||||||
uint64_t GetReadCount(void);
|
|
||||||
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
|
|
||||||
bool SelectSubtitles(int pid);
|
|
||||||
void GetTitles(std::vector<int> &playlists, std::vector<std::string> &titles, int ¤t);
|
|
||||||
void SetTitle(int title);
|
|
||||||
|
|
||||||
void GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
|
|
||||||
void GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
|
|
||||||
|
|
||||||
void SetProgramSelectionCallback(const char *(*fun)(void *, std::vector<std::string> &keys, std::vector<std::string> &values), void *opaque);
|
|
||||||
|
|
||||||
AVFormatContext *GetAVFormatContext();
|
|
||||||
void ReleaseAVFormatContext();
|
|
||||||
#if 0
|
|
||||||
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
|
|
||||||
bool SelectSubtitles(int pid);
|
|
||||||
|
|
||||||
// Functions that are not used by movieplayer.cpp:
|
|
||||||
bool GetOffset(off64_t &offset);
|
|
||||||
bool IsPlaying(void) const;
|
|
||||||
bool IsEnabled(void) const;
|
|
||||||
void *GetHandle(void);
|
|
||||||
void *GetDmHandle(void);
|
|
||||||
int GetCurrPlaybackSpeed(void) const;
|
|
||||||
void PlaybackNotify(int Event, void *pData, void *pTag);
|
|
||||||
void DMNotify(int Event, void *pTsBuf, void *Tag);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __PLAYBACK_LIBEPLAYER3_H__
|
|
@@ -1,398 +0,0 @@
|
|||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <aio.h>
|
|
||||||
|
|
||||||
#include "record_lib.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_RECORD, this, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_RECORD, this, args)
|
|
||||||
|
|
||||||
/* helper function to call the cpp thread loop */
|
|
||||||
void *execute_record_thread(void *c)
|
|
||||||
{
|
|
||||||
cRecord *obj = (cRecord *)c;
|
|
||||||
obj->RecordThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *execute_writer_thread(void *c)
|
|
||||||
{
|
|
||||||
cRecord *obj = (cRecord *)c;
|
|
||||||
obj->WriterThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRecord::cRecord(int num, int bs_dmx, int bs)
|
|
||||||
{
|
|
||||||
hal_info("%s %d\n", __func__, num);
|
|
||||||
dmx = NULL;
|
|
||||||
record_thread_running = false;
|
|
||||||
file_fd = -1;
|
|
||||||
exit_flag = RECORD_STOPPED;
|
|
||||||
dmx_num = num;
|
|
||||||
bufsize = bs;
|
|
||||||
bufsize_dmx = bs_dmx;
|
|
||||||
failureCallback = NULL;
|
|
||||||
failureData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRecord::~cRecord()
|
|
||||||
{
|
|
||||||
hal_info("%s: calling ::Stop()\n", __func__);
|
|
||||||
Stop();
|
|
||||||
hal_info("%s: end\n", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRecord::Open(void)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
exit_flag = RECORD_STOPPED;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// unused
|
|
||||||
void cRecord::Close(void)
|
|
||||||
{
|
|
||||||
hal_info("%s: \n", __func__);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool cRecord::Start(int fd, unsigned short vpid, unsigned short *apids, int numpids, uint64_t)
|
|
||||||
{
|
|
||||||
hal_info("%s: fd %d, vpid 0x%03x\n", __func__, fd, vpid);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!dmx)
|
|
||||||
dmx = new cDemux(dmx_num);
|
|
||||||
|
|
||||||
dmx->Open(DMX_TP_CHANNEL, NULL, bufsize_dmx);
|
|
||||||
dmx->pesFilter(vpid);
|
|
||||||
|
|
||||||
for (i = 0; i < numpids; i++)
|
|
||||||
dmx->addPid(apids[i]);
|
|
||||||
|
|
||||||
file_fd = fd;
|
|
||||||
exit_flag = RECORD_RUNNING;
|
|
||||||
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
|
||||||
perror("posix_fadvise");
|
|
||||||
|
|
||||||
i = pthread_create(&record_thread, 0, execute_record_thread, this);
|
|
||||||
if (i != 0)
|
|
||||||
{
|
|
||||||
exit_flag = RECORD_FAILED_READ;
|
|
||||||
errno = i;
|
|
||||||
hal_info("%s: error creating thread! (%m)\n", __func__);
|
|
||||||
delete dmx;
|
|
||||||
dmx = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
record_thread_running = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRecord::Stop(void)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
|
|
||||||
if (exit_flag != RECORD_RUNNING)
|
|
||||||
hal_info("%s: status not RUNNING? (%d)\n", __func__, exit_flag);
|
|
||||||
|
|
||||||
exit_flag = RECORD_STOPPED;
|
|
||||||
if (record_thread_running)
|
|
||||||
pthread_join(record_thread, NULL);
|
|
||||||
record_thread_running = false;
|
|
||||||
|
|
||||||
/* We should probably do that from the destructor... */
|
|
||||||
if (!dmx)
|
|
||||||
hal_info("%s: dmx == NULL?\n", __func__);
|
|
||||||
else
|
|
||||||
delete dmx;
|
|
||||||
dmx = NULL;
|
|
||||||
|
|
||||||
if (file_fd != -1)
|
|
||||||
close(file_fd);
|
|
||||||
else
|
|
||||||
hal_info("%s: file_fd not open??\n", __func__);
|
|
||||||
file_fd = -1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRecord::ChangePids(unsigned short /*vpid*/, unsigned short *apids, int numapids)
|
|
||||||
{
|
|
||||||
std::vector<pes_pids> pids;
|
|
||||||
int j;
|
|
||||||
bool found;
|
|
||||||
unsigned short pid;
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
if (!dmx)
|
|
||||||
{
|
|
||||||
hal_info("%s: DMX = NULL\n", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pids = dmx->pesfds;
|
|
||||||
/* the first PID is the video pid, so start with the second PID... */
|
|
||||||
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i)
|
|
||||||
{
|
|
||||||
found = false;
|
|
||||||
pid = (*i).pid;
|
|
||||||
for (j = 0; j < numapids; j++)
|
|
||||||
{
|
|
||||||
if (pid == apids[j])
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
dmx->removePid(pid);
|
|
||||||
}
|
|
||||||
for (j = 0; j < numapids; j++)
|
|
||||||
{
|
|
||||||
found = false;
|
|
||||||
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i).pid == apids[j])
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
dmx->addPid(apids[j]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRecord::AddPid(unsigned short pid)
|
|
||||||
{
|
|
||||||
std::vector<pes_pids> pids;
|
|
||||||
hal_info("%s: \n", __func__);
|
|
||||||
if (!dmx)
|
|
||||||
{
|
|
||||||
hal_info("%s: DMX = NULL\n", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pids = dmx->pesfds;
|
|
||||||
for (std::vector<pes_pids>::const_iterator i = pids.begin(); i != pids.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i).pid == pid)
|
|
||||||
return true; /* or is it an error to try to add the same PID twice? */
|
|
||||||
}
|
|
||||||
return dmx->addPid(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRecord::WriterThread()
|
|
||||||
{
|
|
||||||
char threadname[17];
|
|
||||||
strncpy(threadname, "WriterThread", sizeof(threadname));
|
|
||||||
threadname[16] = 0;
|
|
||||||
prctl(PR_SET_NAME, (unsigned long)&threadname);
|
|
||||||
unsigned int chunk = 0;
|
|
||||||
while (!sem_wait(&sem))
|
|
||||||
{
|
|
||||||
if (!io_len[chunk]) // empty, assume end of recording
|
|
||||||
return;
|
|
||||||
unsigned char *p_buf = io_buf[chunk];
|
|
||||||
size_t p_len = io_len[chunk];
|
|
||||||
while (p_len)
|
|
||||||
{
|
|
||||||
ssize_t written = write(file_fd, p_buf, p_len);
|
|
||||||
if (written < 0)
|
|
||||||
break;
|
|
||||||
p_len -= written;
|
|
||||||
p_buf += written;
|
|
||||||
}
|
|
||||||
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
|
||||||
perror("posix_fadvise");
|
|
||||||
chunk++;
|
|
||||||
chunk %= RECORD_WRITER_CHUNKS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRecord::RecordThread()
|
|
||||||
{
|
|
||||||
hal_info("%s: begin\n", __func__);
|
|
||||||
char threadname[17];
|
|
||||||
strncpy(threadname, "RecordThread", sizeof(threadname));
|
|
||||||
threadname[16] = 0;
|
|
||||||
prctl(PR_SET_NAME, (unsigned long)&threadname);
|
|
||||||
int readsize = bufsize / 16;
|
|
||||||
int buf_pos = 0;
|
|
||||||
int count = 0;
|
|
||||||
int queued = 0;
|
|
||||||
uint8_t *buf;
|
|
||||||
struct aiocb a;
|
|
||||||
|
|
||||||
buf = (uint8_t *)malloc(bufsize);
|
|
||||||
hal_info("BUFSIZE=0x%x READSIZE=0x%x\n", bufsize, readsize);
|
|
||||||
if (!buf)
|
|
||||||
{
|
|
||||||
exit_flag = RECORD_FAILED_MEMORY;
|
|
||||||
hal_info("%s: unable to allocate buffer! (out of memory)\n", __func__);
|
|
||||||
if (failureCallback)
|
|
||||||
failureCallback(failureData);
|
|
||||||
hal_info("%s: end\n", __func__);
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int val = fcntl(file_fd, F_GETFL);
|
|
||||||
if (fcntl(file_fd, F_SETFL, val | O_APPEND))
|
|
||||||
hal_info("%s: O_APPEND? (%m)\n", __func__);
|
|
||||||
|
|
||||||
memset(&a, 0, sizeof(a));
|
|
||||||
a.aio_fildes = file_fd;
|
|
||||||
a.aio_sigevent.sigev_notify = SIGEV_NONE;
|
|
||||||
|
|
||||||
dmx->Start();
|
|
||||||
int overflow_count = 0;
|
|
||||||
bool overflow = false;
|
|
||||||
int r = 0;
|
|
||||||
while (exit_flag == RECORD_RUNNING)
|
|
||||||
{
|
|
||||||
if (buf_pos < bufsize)
|
|
||||||
{
|
|
||||||
if (overflow_count)
|
|
||||||
{
|
|
||||||
hal_info("%s: Overflow cleared after %d iterations\n", __func__, overflow_count);
|
|
||||||
overflow_count = 0;
|
|
||||||
}
|
|
||||||
int toread = bufsize - buf_pos;
|
|
||||||
if (toread > readsize)
|
|
||||||
toread = readsize;
|
|
||||||
ssize_t s = dmx->Read(buf + buf_pos, toread, 50);
|
|
||||||
hal_debug("%s: buf_pos %6d s %6d / %6d\n", __func__, buf_pos, (int)s, bufsize - buf_pos);
|
|
||||||
if (s < 0)
|
|
||||||
{
|
|
||||||
if (errno != EAGAIN && (errno != EOVERFLOW || !overflow))
|
|
||||||
{
|
|
||||||
hal_info("%s: read failed: %m\n", __func__);
|
|
||||||
exit_flag = RECORD_FAILED_READ;
|
|
||||||
state = REC_STATUS_OVERFLOW;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
overflow = false;
|
|
||||||
buf_pos += s;
|
|
||||||
if (count > 100)
|
|
||||||
{
|
|
||||||
if (buf_pos < bufsize / 2)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!overflow)
|
|
||||||
overflow_count = 0;
|
|
||||||
overflow = true;
|
|
||||||
if (!(overflow_count % 10))
|
|
||||||
hal_info("%s: buffer full! Overflow? (%d)\n", __func__, ++overflow_count);
|
|
||||||
state = REC_STATUS_SLOW;
|
|
||||||
}
|
|
||||||
r = aio_error(&a);
|
|
||||||
if (r == EINPROGRESS)
|
|
||||||
{
|
|
||||||
hal_debug("%s: aio in progress, free: %d\n", __func__, bufsize - buf_pos);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// not calling aio_return causes a memory leak --martii
|
|
||||||
r = aio_return(&a);
|
|
||||||
if (r < 0)
|
|
||||||
{
|
|
||||||
exit_flag = RECORD_FAILED_FILE;
|
|
||||||
hal_debug("%s: aio_return = %d (%m)\n", __func__, r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hal_debug("%s: aio_return = %d, free: %d\n", __func__, r, bufsize - buf_pos);
|
|
||||||
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
|
|
||||||
perror("posix_fadvise");
|
|
||||||
if (queued)
|
|
||||||
{
|
|
||||||
memmove(buf, buf + queued, buf_pos - queued);
|
|
||||||
buf_pos -= queued;
|
|
||||||
}
|
|
||||||
queued = buf_pos;
|
|
||||||
a.aio_buf = buf;
|
|
||||||
a.aio_nbytes = queued;
|
|
||||||
r = aio_write(&a);
|
|
||||||
if (r)
|
|
||||||
{
|
|
||||||
hal_info("%s: aio_write %d (%m)\n", __func__, r);
|
|
||||||
exit_flag = RECORD_FAILED_FILE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dmx->Stop();
|
|
||||||
while (true) /* write out the unwritten buffer content */
|
|
||||||
{
|
|
||||||
hal_debug("%s: run-out write, buf_pos %d\n", __func__, buf_pos);
|
|
||||||
r = aio_error(&a);
|
|
||||||
if (r == EINPROGRESS)
|
|
||||||
{
|
|
||||||
usleep(50000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
r = aio_return(&a);
|
|
||||||
if (r < 0)
|
|
||||||
{
|
|
||||||
exit_flag = RECORD_FAILED_FILE;
|
|
||||||
hal_info("%s: aio_result: %d (%m)\n", __func__, r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!queued)
|
|
||||||
break;
|
|
||||||
memmove(buf, buf + queued, buf_pos - queued);
|
|
||||||
buf_pos -= queued;
|
|
||||||
queued = buf_pos;
|
|
||||||
a.aio_buf = buf;
|
|
||||||
a.aio_nbytes = queued;
|
|
||||||
r = aio_write(&a);
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// TODO: do we need to notify neutrino about failing recording?
|
|
||||||
CEventServer eventServer;
|
|
||||||
eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock");
|
|
||||||
stream2file_status2_t s;
|
|
||||||
s.status = exit_flag;
|
|
||||||
strncpy(s.filename, basename(myfilename), 512);
|
|
||||||
s.filename[511] = '\0';
|
|
||||||
strncpy(s.dir, dirname(myfilename), 100);
|
|
||||||
s.dir[99] = '\0';
|
|
||||||
eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s));
|
|
||||||
printf("[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((exit_flag != RECORD_STOPPED) && failureCallback)
|
|
||||||
failureCallback(failureData);
|
|
||||||
hal_info("%s: end\n", __func__);
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cRecord::GetStatus()
|
|
||||||
{
|
|
||||||
return (exit_flag == RECORD_STOPPED) ? REC_STATUS_STOPPED : REC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRecord::ResetStatus()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
@@ -1,59 +0,0 @@
|
|||||||
#ifndef __RECORD_LIB_H__
|
|
||||||
#define __RECORD_LIB_H__
|
|
||||||
|
|
||||||
#include <semaphore.h>
|
|
||||||
#include "dmx_hal.h"
|
|
||||||
|
|
||||||
#define REC_STATUS_OK 0
|
|
||||||
#define REC_STATUS_SLOW 1
|
|
||||||
#define REC_STATUS_OVERFLOW 2
|
|
||||||
#define REC_STATUS_STOPPED 4
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
RECORD_RUNNING,
|
|
||||||
RECORD_STOPPED,
|
|
||||||
RECORD_FAILED_READ, /* failed to read from DMX */
|
|
||||||
RECORD_FAILED_OVERFLOW, /* cannot write fast enough */
|
|
||||||
RECORD_FAILED_FILE, /* cannot write to file */
|
|
||||||
RECORD_FAILED_MEMORY /* out of memory */
|
|
||||||
} record_state_t;
|
|
||||||
|
|
||||||
class cRecord
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int file_fd;
|
|
||||||
int dmx_num;
|
|
||||||
cDemux *dmx;
|
|
||||||
pthread_t record_thread;
|
|
||||||
bool record_thread_running;
|
|
||||||
record_state_t exit_flag;
|
|
||||||
int state;
|
|
||||||
int bufsize;
|
|
||||||
int bufsize_dmx;
|
|
||||||
void (*failureCallback)(void *);
|
|
||||||
void *failureData;
|
|
||||||
|
|
||||||
sem_t sem;
|
|
||||||
#define RECORD_WRITER_CHUNKS 16
|
|
||||||
unsigned char *io_buf[RECORD_WRITER_CHUNKS];
|
|
||||||
size_t io_len[RECORD_WRITER_CHUNKS];
|
|
||||||
|
|
||||||
public:
|
|
||||||
cRecord(int num = 0, int bs_dmx = 2048 * 1024, int bs = 4096 * 1024);
|
|
||||||
void setFailureCallback(void (*f)(void *), void *d) { failureCallback = f; failureData = d; }
|
|
||||||
~cRecord();
|
|
||||||
|
|
||||||
bool Open();
|
|
||||||
bool Start(int fd, unsigned short vpid, unsigned short *apids, int numapids, uint64_t ch = 0);
|
|
||||||
bool Stop(void);
|
|
||||||
bool AddPid(unsigned short pid);
|
|
||||||
int GetStatus();
|
|
||||||
void ResetStatus();
|
|
||||||
bool ChangePids(unsigned short vpid, unsigned short *apids, int numapids);
|
|
||||||
|
|
||||||
void RecordThread();
|
|
||||||
void WriterThread();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __RECORD_LIB_H__
|
|
1835
libspark/video.cpp
1835
libspark/video.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,281 +0,0 @@
|
|||||||
#ifndef __VIDEO_LIB_H__
|
|
||||||
#define __VIDEO_LIB_H__
|
|
||||||
|
|
||||||
#include <linux/dvb/video.h>
|
|
||||||
#include "cs_types.h"
|
|
||||||
#include "dmx_hal.h"
|
|
||||||
|
|
||||||
typedef struct cs_vs_format_t
|
|
||||||
{
|
|
||||||
char format[16];
|
|
||||||
} cs_vs_format_struct_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
ANALOG_SD_RGB_CINCH = 0x00,
|
|
||||||
ANALOG_SD_YPRPB_CINCH,
|
|
||||||
ANALOG_HD_RGB_CINCH,
|
|
||||||
ANALOG_HD_YPRPB_CINCH,
|
|
||||||
ANALOG_SD_RGB_SCART = 0x10,
|
|
||||||
ANALOG_SD_YPRPB_SCART,
|
|
||||||
ANALOG_HD_RGB_SCART,
|
|
||||||
ANALOG_HD_YPRPB_SCART,
|
|
||||||
ANALOG_SCART_MASK = 0x10
|
|
||||||
} analog_mode_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
COLORFORMAT_RGB = 0x10, // keep compatible with analog_mode_t
|
|
||||||
COLORFORMAT_YUV,
|
|
||||||
COLORFORMAT_CVBS,
|
|
||||||
COLORFORMAT_SVIDEO,
|
|
||||||
COLORFORMAT_HDMI_RGB,
|
|
||||||
COLORFORMAT_HDMI_YCBCR444,
|
|
||||||
COLORFORMAT_HDMI_YCBCR422
|
|
||||||
} COLOR_FORMAT;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_FORMAT_MPEG2 = 0,
|
|
||||||
VIDEO_FORMAT_MPEG4_H264,
|
|
||||||
VIDEO_FORMAT_VC1,
|
|
||||||
VIDEO_FORMAT_JPEG,
|
|
||||||
VIDEO_FORMAT_GIF,
|
|
||||||
VIDEO_FORMAT_PNG,
|
|
||||||
VIDEO_FORMAT_MPEG4_H265,
|
|
||||||
VIDEO_FORMAT_AVS = 16
|
|
||||||
} VIDEO_FORMAT;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_SD = 0,
|
|
||||||
VIDEO_HD,
|
|
||||||
VIDEO_120x60i,
|
|
||||||
VIDEO_320x240i,
|
|
||||||
VIDEO_1440x800i,
|
|
||||||
VIDEO_360x288i
|
|
||||||
} VIDEO_DEFINITION;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_FRAME_RATE_23_976 = 0,
|
|
||||||
VIDEO_FRAME_RATE_24,
|
|
||||||
VIDEO_FRAME_RATE_25,
|
|
||||||
VIDEO_FRAME_RATE_29_97,
|
|
||||||
VIDEO_FRAME_RATE_30,
|
|
||||||
VIDEO_FRAME_RATE_50,
|
|
||||||
VIDEO_FRAME_RATE_59_94,
|
|
||||||
VIDEO_FRAME_RATE_60
|
|
||||||
} VIDEO_FRAME_RATE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DISPLAY_AR_1_1,
|
|
||||||
DISPLAY_AR_4_3,
|
|
||||||
DISPLAY_AR_14_9,
|
|
||||||
DISPLAY_AR_16_9,
|
|
||||||
DISPLAY_AR_20_9,
|
|
||||||
DISPLAY_AR_RAW
|
|
||||||
} DISPLAY_AR;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DISPLAY_AR_MODE_PANSCAN = 0,
|
|
||||||
DISPLAY_AR_MODE_LETTERBOX,
|
|
||||||
DISPLAY_AR_MODE_NONE,
|
|
||||||
DISPLAY_AR_MODE_PANSCAN2
|
|
||||||
} DISPLAY_AR_MODE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_DB_DR_NEITHER = 0,
|
|
||||||
VIDEO_DB_ON,
|
|
||||||
VIDEO_DB_DR_BOTH
|
|
||||||
} VIDEO_DB_DR;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_PLAY_STILL = 0,
|
|
||||||
VIDEO_PLAY_CLIP,
|
|
||||||
VIDEO_PLAY_TRICK,
|
|
||||||
VIDEO_PLAY_MOTION,
|
|
||||||
VIDEO_PLAY_MOTION_NO_SYNC
|
|
||||||
} VIDEO_PLAY_MODE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_STD_NTSC,
|
|
||||||
VIDEO_STD_SECAM,
|
|
||||||
VIDEO_STD_PAL,
|
|
||||||
VIDEO_STD_480P,
|
|
||||||
VIDEO_STD_576P,
|
|
||||||
VIDEO_STD_720P60,
|
|
||||||
VIDEO_STD_1080I60,
|
|
||||||
VIDEO_STD_720P50,
|
|
||||||
VIDEO_STD_1080I50,
|
|
||||||
VIDEO_STD_1080P30,
|
|
||||||
VIDEO_STD_1080P24,
|
|
||||||
VIDEO_STD_1080P25,
|
|
||||||
VIDEO_STD_AUTO,
|
|
||||||
VIDEO_STD_1080P50, /* SPARK only */
|
|
||||||
VIDEO_STD_MAX
|
|
||||||
} VIDEO_STD;
|
|
||||||
|
|
||||||
/* not used, for dummy functions */
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_HDMI_CEC_MODE_OFF = 0,
|
|
||||||
VIDEO_HDMI_CEC_MODE_TUNER,
|
|
||||||
VIDEO_HDMI_CEC_MODE_RECORDER
|
|
||||||
} VIDEO_HDMI_CEC_MODE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
VIDEO_CONTROL_BRIGHTNESS = 0,
|
|
||||||
VIDEO_CONTROL_CONTRAST,
|
|
||||||
VIDEO_CONTROL_SATURATION,
|
|
||||||
VIDEO_CONTROL_HUE,
|
|
||||||
VIDEO_CONTROL_SHARPNESS,
|
|
||||||
VIDEO_CONTROL_MAX = VIDEO_CONTROL_SHARPNESS
|
|
||||||
} VIDEO_CONTROL;
|
|
||||||
|
|
||||||
class cVideo
|
|
||||||
{
|
|
||||||
friend class cPlayback;
|
|
||||||
friend class cDemux;
|
|
||||||
private:
|
|
||||||
/* video device */
|
|
||||||
int fd;
|
|
||||||
unsigned int devnum;
|
|
||||||
/* apparently we cannot query the driver's state
|
|
||||||
=> remember it */
|
|
||||||
video_play_state_t playstate;
|
|
||||||
int /*vidDispMode_t*/ croppingMode;
|
|
||||||
int /*vidOutFmt_t*/ outputformat;
|
|
||||||
int scartvoltage;
|
|
||||||
|
|
||||||
VIDEO_FORMAT StreamType;
|
|
||||||
VIDEO_DEFINITION VideoDefinition;
|
|
||||||
DISPLAY_AR DisplayAR;
|
|
||||||
VIDEO_PLAY_MODE SyncMode;
|
|
||||||
DISPLAY_AR_MODE ARMode;
|
|
||||||
VIDEO_DB_DR eDbDr;
|
|
||||||
DISPLAY_AR PictureAR;
|
|
||||||
VIDEO_FRAME_RATE FrameRate;
|
|
||||||
int video_standby;
|
|
||||||
int64_t GetPTS(void);
|
|
||||||
|
|
||||||
int brightness, contrast, saturation, hue;
|
|
||||||
|
|
||||||
/* used internally by playback */
|
|
||||||
void openDevice(void);
|
|
||||||
void closeDevice(void);
|
|
||||||
public:
|
|
||||||
/* constructor & destructor */
|
|
||||||
cVideo(int mode, void *, void *, unsigned int unit = 0);
|
|
||||||
~cVideo(void);
|
|
||||||
|
|
||||||
void open_AVInput_Device(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}; // Dummy
|
|
||||||
void close_AVInput_Device(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}; // Dummy
|
|
||||||
|
|
||||||
void setAVInput(int val);
|
|
||||||
|
|
||||||
void *GetTVEnc()
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
};
|
|
||||||
void *GetTVEncSD()
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* aspect ratio */
|
|
||||||
int getAspectRatio(void);
|
|
||||||
void getPictureInfo(int &width, int &height, int &rate);
|
|
||||||
int setAspectRatio(int aspect, int mode);
|
|
||||||
|
|
||||||
/* cropping mode */
|
|
||||||
int setCroppingMode(int x = 0 /*vidDispMode_t x = VID_DISPMODE_NORM*/);
|
|
||||||
|
|
||||||
/* get play state */
|
|
||||||
int getPlayState(void);
|
|
||||||
|
|
||||||
/* blank on freeze */
|
|
||||||
int getBlank(void);
|
|
||||||
int setBlank(int enable);
|
|
||||||
|
|
||||||
/* change video play state. Parameters are all unused. */
|
|
||||||
int Start(void *PcrChannel = NULL, unsigned short PcrPid = 0, unsigned short VideoPid = 0, void *x = NULL);
|
|
||||||
int Stop(bool blank = true);
|
|
||||||
bool Pause(void);
|
|
||||||
|
|
||||||
/* get video system infos */
|
|
||||||
int GetVideoSystem(void);
|
|
||||||
/* when system = -1 then use current video system */
|
|
||||||
void GetVideoSystemFormatName(cs_vs_format_t *format, int system = -1);
|
|
||||||
|
|
||||||
/* set video_system */
|
|
||||||
int SetVideoSystem(int video_system, bool remember = true);
|
|
||||||
int SetStreamType(VIDEO_FORMAT type);
|
|
||||||
void SetSyncMode(AVSYNC_TYPE mode);
|
|
||||||
bool SetCECMode(VIDEO_HDMI_CEC_MODE)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
void SetCECAutoView(bool)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
void SetCECAutoStandby(bool)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
bool ShowPicture(const char *fname, const char *_destname = NULL);
|
|
||||||
void StopPicture();
|
|
||||||
void Standby(unsigned int bOn);
|
|
||||||
void ShowPig(int _x);
|
|
||||||
void Pig(int x, int y, int w, int h, int osd_w = 1064, int osd_h = 600, int startx = 0, int starty = 0, int endx = 1279, int endy = 719);
|
|
||||||
void SetControl(int, int);
|
|
||||||
void VideoParamWatchdog(void);
|
|
||||||
void setContrast(int val);
|
|
||||||
void SetVideoMode(analog_mode_t mode);
|
|
||||||
void SetDBDR(int)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
void SetAudioHandle(void *)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
void SetAutoModes(int [VIDEO_STD_MAX])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
int OpenVBI(int)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int CloseVBI(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int StartVBI(unsigned short)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int StopVBI(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
void SetDemux(cDemux *dmx);
|
|
||||||
void SetColorFormat(COLOR_FORMAT color_format);
|
|
||||||
bool GetScreenImage(unsigned char *&data, int &xres, int &yres, bool get_video = true, bool get_osd = false, bool scale_to_video = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __VIDEO_LIB_H__
|
|
@@ -1,9 +1,4 @@
|
|||||||
bin_PROGRAMS =
|
bin_PROGRAMS =
|
||||||
|
|
||||||
if BOXTYPE_SPARK
|
|
||||||
bin_PROGRAMS += spark_fp
|
|
||||||
spark_fp_SOURCES = spark_fp.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
bin_PROGRAMS += pic2m2v
|
bin_PROGRAMS += pic2m2v
|
||||||
pic2m2v_SOURCES = pic2m2v.c
|
pic2m2v_SOURCES = pic2m2v.c
|
||||||
|
319
tools/spark_fp.c
319
tools/spark_fp.c
@@ -1,319 +0,0 @@
|
|||||||
/*
|
|
||||||
* spark_fp - frontcontroller tool for SPARK boxes
|
|
||||||
*
|
|
||||||
* (C) 2012 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
|
|
||||||
*
|
|
||||||
* License: GPL v2 or later
|
|
||||||
*
|
|
||||||
* 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <aotom_main.h>
|
|
||||||
|
|
||||||
#define FP_DEV "/dev/vfd"
|
|
||||||
|
|
||||||
void usage()
|
|
||||||
{
|
|
||||||
printf("usage spark_fp <option>\n");
|
|
||||||
printf("\t-g: get wakeup reason (return code == reason)\n");
|
|
||||||
printf("\t-T: get FP display type (1 = VFD, 2 = LCD, 4 = LED, 8 = LBD)\n");
|
|
||||||
printf("\t-t: get current FP time\n");
|
|
||||||
printf("\t-s <time>: set FP time (time = 0: use current time)\n");
|
|
||||||
printf("\t-w <time>: set FP wakeup time (time = 1: no wakeup)\n");
|
|
||||||
printf("\t-P: power down\n");
|
|
||||||
printf("\t-B <n>: show blue RC code (n = 0..4 or \"all\")\n");
|
|
||||||
printf("\t-S <n>: show standby RC code (n = 0..4 or \"all\")\n");
|
|
||||||
printf("\t-B <n>:<predata><code>: set blue RC code (n = 0..4)\n");
|
|
||||||
printf("\t-S <n>:<predata><code>: set standby RC code\n");
|
|
||||||
printf("\t-p: set LED flashing period (in ms)\n");
|
|
||||||
printf("\t-l <n>: set LED <n> on\n");
|
|
||||||
printf("\t-L <n>: set LED <n> off\n");
|
|
||||||
printf("\t-i <n>: set icon <n> on\n");
|
|
||||||
printf("\t-I <n>: set icon <n> off\n");
|
|
||||||
printf("times are given in unix time (UTC, seconds since 1970-01-01 00:00:00)\n");
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
double mod_julian_date(struct tm *t)
|
|
||||||
{
|
|
||||||
double date;
|
|
||||||
int month;
|
|
||||||
int day;
|
|
||||||
int year;
|
|
||||||
|
|
||||||
year = t->tm_year + 1900;
|
|
||||||
month = t->tm_mon + 1;
|
|
||||||
day = t->tm_mday;
|
|
||||||
|
|
||||||
date = day - 32076 +
|
|
||||||
1461 * (year + 4800 + (month - 14) / 12) / 4 +
|
|
||||||
367 * (month - 2 - (month - 14) / 12 * 12) / 12 -
|
|
||||||
3 * ((year + 4900 + (month - 14) / 12) / 100) / 4;
|
|
||||||
|
|
||||||
date += (t->tm_hour + 12.0) / 24.0;
|
|
||||||
date += (t->tm_min) / 1440.0;
|
|
||||||
date += (t->tm_sec) / 86400.0;
|
|
||||||
date -= 2400000.5;
|
|
||||||
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void time_to_aotom(time_t t, char *dest)
|
|
||||||
{
|
|
||||||
/* from u-boot aotom */
|
|
||||||
struct tm *tmp;
|
|
||||||
tmp = localtime(&t);
|
|
||||||
#if 0
|
|
||||||
/* this mjd stuff is totally useless: driver only uses dest[2] and dest[3]... */
|
|
||||||
double mjd = mod_julian_date(tmp);
|
|
||||||
int mjd_int = mjd;
|
|
||||||
|
|
||||||
dest[0] = mjd_int >> 8;
|
|
||||||
dest[1] = mjd_int & 0xff;
|
|
||||||
#else
|
|
||||||
dest[0] = dest[1] = 0;
|
|
||||||
#endif
|
|
||||||
dest[2] = tmp->tm_hour;
|
|
||||||
dest[3] = tmp->tm_min;
|
|
||||||
dest[4] = tmp->tm_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_aotom_time(int fd, time_t t)
|
|
||||||
{
|
|
||||||
struct tm *tmp;
|
|
||||||
struct aotom_ioctl_data aotom;
|
|
||||||
memset(&aotom, 0, sizeof(aotom));
|
|
||||||
|
|
||||||
tmp = localtime(&t);
|
|
||||||
t += tmp->tm_gmtoff;
|
|
||||||
if (ioctl(fd, VFDSETTIME2, &t) >= 0)
|
|
||||||
return 0;
|
|
||||||
fprintf(stderr, "warning: VFDSETTIME2 failed (%m), falling back to VFDSETTIME\n");
|
|
||||||
time_to_aotom(t, aotom.u.time.time);
|
|
||||||
if (ioctl(fd, VFDSETTIME, &aotom) < 0)
|
|
||||||
{
|
|
||||||
perror("ioctl VFDSETTIME");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
const char *wakeupreason[4] = { "unknown", "poweron", "standby", "timer" };
|
|
||||||
struct aotom_ioctl_data aotom;
|
|
||||||
memset(&aotom, 0, sizeof(aotom));
|
|
||||||
int ret, c, val;
|
|
||||||
time_t t, t2, diff;
|
|
||||||
struct tm *tmp;
|
|
||||||
int period = LOG_ON;
|
|
||||||
|
|
||||||
int fd = open(FP_DEV, O_RDWR);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "error: cannot open %s: %m\n", FP_DEV);
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc == 1)
|
|
||||||
{
|
|
||||||
usage();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
while ((c = getopt(argc, argv, "gs:tw:Tl:L:P:S:B:i:I:p:")) != -1)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 'g':
|
|
||||||
ret = ioctl(fd, VFDGETSTARTUPSTATE, &val);
|
|
||||||
if (ret < 0)
|
|
||||||
perror("ioctl VFDGETSTARTUPSTATE");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s\n", wakeupreason[val & 0x03]);
|
|
||||||
ret = val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
t = atol(optarg);
|
|
||||||
if (t == 0)
|
|
||||||
t = time(NULL),
|
|
||||||
ret = set_aotom_time(fd, t);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
ret = ioctl(fd, VFDGETTIME, &t);
|
|
||||||
if (ret < 0)
|
|
||||||
perror("ioctl VFDGETTIME");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp = localtime(&t);
|
|
||||||
t -= tmp->tm_gmtoff;
|
|
||||||
printf("%ld\n", t);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
t = atol(optarg);
|
|
||||||
if (t == 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "invalid time?\n");
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* set AOTOM time to current time... */
|
|
||||||
t2 = time(NULL);
|
|
||||||
ret = set_aotom_time(fd, t2);
|
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
diff = t - t2;
|
|
||||||
if (t == 1)
|
|
||||||
t = 0; /* t = 1 is magic for "no time" -> clear... */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* green LED on */
|
|
||||||
aotom.u.led.on = LOG_ON;
|
|
||||||
aotom.u.led.led_nr = 1;
|
|
||||||
ioctl(fd, VFDSETLED, &aotom);
|
|
||||||
ret = ioctl(fd, VFDGETTIME, &t);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
perror("ioctl VFDGETTIME");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (t < t2 + 20)
|
|
||||||
diff = 20;
|
|
||||||
t += diff;
|
|
||||||
}
|
|
||||||
tmp = gmtime(&t2);
|
|
||||||
fprintf(stderr, "current time: %04d-%02d-%02d %02d:%02d:%02d\n", tmp->tm_year + 1900,
|
|
||||||
tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
||||||
tmp = gmtime(&t);
|
|
||||||
fprintf(stderr, "wakeup time: %04d-%02d-%02d %02d:%02d:%02d\n", tmp->tm_year + 1900,
|
|
||||||
tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
||||||
ret = ioctl(fd, VFDSETPOWERONTIME, &t);
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
ret = ioctl(fd, VFDPOWEROFF);
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
period = atoi(optarg) / 10;
|
|
||||||
break;
|
|
||||||
case 'l': /* LED on */
|
|
||||||
aotom.u.led.on = period;
|
|
||||||
aotom.u.led.led_nr = atoi(optarg);
|
|
||||||
ioctl(fd, VFDSETLED, &aotom);
|
|
||||||
break;
|
|
||||||
case 'L': /* LED off */
|
|
||||||
aotom.u.led.on = LOG_OFF;
|
|
||||||
aotom.u.led.led_nr = atoi(optarg);
|
|
||||||
ioctl(fd, VFDSETLED, &aotom);
|
|
||||||
break;
|
|
||||||
case 'i': /* icon on */
|
|
||||||
aotom.u.icon.on = 1;
|
|
||||||
aotom.u.icon.icon_nr = atoi(optarg);
|
|
||||||
ioctl(fd, VFDICONDISPLAYONOFF, &aotom);
|
|
||||||
break;
|
|
||||||
case 'I': /* icon off */
|
|
||||||
aotom.u.icon.on = 0;
|
|
||||||
aotom.u.icon.icon_nr = atoi(optarg);
|
|
||||||
ioctl(fd, VFDICONDISPLAYONOFF, &aotom);
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
ret = ioctl(fd, VFDGETVERSION, &val);
|
|
||||||
if (ret < 0)
|
|
||||||
perror("ioctl VFDGETVERSION");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%d\n", val);
|
|
||||||
ret = val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Reminder to myself, here's a semi-sane default for Pingulux boxes:
|
|
||||||
// spark_fp -S 0:9966da25 -S 1:11eeda25 -S 2:cc33ba45 -S 3:dd227887 -S 4:aa557887 -B 0:996640bf -B 1:11ee40bf -B 2:cc33b847 -B 3:dd2228d7 -B 4:aa5528d7
|
|
||||||
// Not sure whether these are the original settings. --martii
|
|
||||||
|
|
||||||
case 'S':
|
|
||||||
if (2 == sscanf(optarg, "%d:%lx", &aotom.u.key.key_nr, (long unsigned int *) &aotom.u.key.key))
|
|
||||||
ioctl(fd, VFDSETSTBYKEY, &aotom);
|
|
||||||
if (1 == sscanf(optarg, "%d", &aotom.u.key.key_nr))
|
|
||||||
{
|
|
||||||
ret = ioctl(fd, VFDGETSTBYKEY, &aotom);
|
|
||||||
if (ret)
|
|
||||||
perror("ioctl VFDGETSTBYKEY");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "stby key %d = %.8x\n", aotom.u.key.key_nr, aotom.u.key.key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aotom.u.key.key_nr = 0;
|
|
||||||
while (aotom.u.key.key_nr < 5)
|
|
||||||
{
|
|
||||||
ret = ioctl(fd, VFDGETSTBYKEY, &aotom);
|
|
||||||
if (ret)
|
|
||||||
perror("ioctl VFDGETSTBYKEY");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "stby key %d = %.8x\n", aotom.u.key.key_nr, aotom.u.key.key);
|
|
||||||
aotom.u.key.key_nr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
if (2 == sscanf(optarg, "%d:%lx", &aotom.u.key.key_nr, (long unsigned int *) &aotom.u.key.key))
|
|
||||||
ioctl(fd, VFDSETBLUEKEY, &aotom);
|
|
||||||
if (1 == sscanf(optarg, "%d", &aotom.u.key.key_nr))
|
|
||||||
{
|
|
||||||
ret = ioctl(fd, VFDGETBLUEKEY, &aotom);
|
|
||||||
if (ret)
|
|
||||||
perror("ioctl VFDGETBLUEKEY");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "blue key %d = %.8x\n", aotom.u.key.key_nr, aotom.u.key.key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aotom.u.key.key_nr = 0;
|
|
||||||
while (aotom.u.key.key_nr < 5)
|
|
||||||
{
|
|
||||||
ret = ioctl(fd, VFDGETBLUEKEY, &aotom);
|
|
||||||
if (ret)
|
|
||||||
perror("ioctl VFDGETBLUEKEY");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "blue key %d = %.8x\n", aotom.u.key.key_nr, aotom.u.key.key);
|
|
||||||
aotom.u.key.key_nr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
Reference in New Issue
Block a user