remove SPARK_HARDWARE

Origin commit data
------------------
Branch: master
Commit: ec2a0cd262
Author: vanhofen <vanhofen@gmx.de>
Date: 2021-11-07 (Sun, 07 Nov 2021)

Origin message was:
------------------
- remove SPARK_HARDWARE

------------------
No further description and justification available within origin commit message!

------------------
This commit was generated by Migit
This commit is contained in:
vanhofen
2021-11-07 00:57:01 +01:00
parent a727a4f78f
commit 93276b745e
33 changed files with 463 additions and 11151 deletions

View File

@@ -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

View File

@@ -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])

View File

@@ -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");

View File

@@ -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
]) ])

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -1 +0,0 @@
../libspark/record.cpp

398
libgeneric-pc/record.cpp Normal file
View 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;
}

View File

@@ -1 +0,0 @@
../libspark/record_lib.h

View 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__

View File

@@ -1 +1 @@
../libspark/record.cpp ../libgeneric-pc/record.cpp

View File

@@ -1 +1 @@
../libspark/record_lib.h ../libgeneric-pc/record_lib.h

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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__

View File

@@ -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);
}

View File

@@ -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__

View File

@@ -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];
}

View File

@@ -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 &caps;
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 &caps;
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 &current)
{
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;
}

View File

@@ -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 &current);
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__

View File

@@ -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;
}

View File

@@ -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__

File diff suppressed because it is too large Load Diff

View File

@@ -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__

View File

@@ -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

View File

@@ -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;
}