390 lines
8.8 KiB
C
390 lines
8.8 KiB
C
|
|
#define MODULE_LOG_PREFIX "led"
|
||
|
|
|
||
|
|
#include "globals.h"
|
||
|
|
|
||
|
|
#ifdef LEDSUPPORT
|
||
|
|
|
||
|
|
#include "module-led.h"
|
||
|
|
#include "oscam-string.h"
|
||
|
|
#include "oscam-time.h"
|
||
|
|
|
||
|
|
#if defined(__arm__)
|
||
|
|
struct s_arm_led
|
||
|
|
{
|
||
|
|
int32_t led;
|
||
|
|
int32_t action;
|
||
|
|
time_t start_time;
|
||
|
|
};
|
||
|
|
|
||
|
|
static pthread_t arm_led_thread;
|
||
|
|
static LLIST *arm_led_actions;
|
||
|
|
|
||
|
|
#define ARM_LED_TYPES 3
|
||
|
|
#define ARM_LED_FILES 4
|
||
|
|
|
||
|
|
struct arm_leds
|
||
|
|
{
|
||
|
|
char *machine;
|
||
|
|
struct led_file
|
||
|
|
{
|
||
|
|
uint8_t id;
|
||
|
|
char *file;
|
||
|
|
} leds[ARM_LED_FILES];
|
||
|
|
};
|
||
|
|
|
||
|
|
static const struct arm_leds arm_leds[ARM_LED_TYPES] =
|
||
|
|
{
|
||
|
|
{
|
||
|
|
"nslu2", {
|
||
|
|
{ LED1A, "red:status" },
|
||
|
|
{ LED1B, "green:ready" },
|
||
|
|
{ LED2, "green:disk-1" },
|
||
|
|
{ LED3, "green:disk-2" }
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"dockstar", {
|
||
|
|
{ LED1A, "orange:misc" },
|
||
|
|
{ LED1B, "green:health" },
|
||
|
|
{ LED2, "green:health" },
|
||
|
|
{ LED3, "orange:misc" }
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"wrt350nv2", {
|
||
|
|
{ LED1A, "orange:power" },
|
||
|
|
{ LED1B, "green:power" },
|
||
|
|
{ LED2, "green:wireless" },
|
||
|
|
{ LED3, "green:security" }
|
||
|
|
},
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
static int32_t arm_init_led_file(uint8_t led_type, uint8_t led_no, char *buf, int32_t buflen)
|
||
|
|
{
|
||
|
|
uint8_t i;
|
||
|
|
if(led_type >= ARM_LED_TYPES) { return 0; }
|
||
|
|
if(led_no >= ARM_LED_FILES) { return 0; }
|
||
|
|
for(i = 0; i < ARM_LED_FILES; i++)
|
||
|
|
{
|
||
|
|
if(arm_leds[led_type].leds[i].id == led_no)
|
||
|
|
{
|
||
|
|
return snprintf(buf, buflen, "/sys/class/leds/%s:%s/brightness",
|
||
|
|
arm_leds[led_type].machine, arm_leds[led_type].leds[i].file);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#define LED_TYPE_UNKNOWN 0xff
|
||
|
|
static uint8_t arm_led_type = LED_TYPE_UNKNOWN;
|
||
|
|
|
||
|
|
static void arm_detect_led_type(void)
|
||
|
|
{
|
||
|
|
uint8_t i;
|
||
|
|
char led_file[256];
|
||
|
|
for(i = 0; i < ARM_LED_TYPES; i++)
|
||
|
|
{
|
||
|
|
if(!arm_init_led_file(i, 0, led_file, sizeof(led_file)))
|
||
|
|
{ break; }
|
||
|
|
if(access(led_file, W_OK) == 0)
|
||
|
|
{
|
||
|
|
arm_led_type = i;
|
||
|
|
cs_log("LED support for %s is activated.", arm_leds[arm_led_type].machine);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(arm_led_type == LED_TYPE_UNKNOWN)
|
||
|
|
{ cs_log("LED support is not active. Can't detect machine type."); }
|
||
|
|
}
|
||
|
|
|
||
|
|
static void arm_switch_led_from_thread(int32_t led, int32_t action)
|
||
|
|
{
|
||
|
|
if(action < 2) // only LED_ON and LED_OFF
|
||
|
|
{
|
||
|
|
char led_file[256];
|
||
|
|
if(!arm_init_led_file(arm_led_type, led, led_file, sizeof(led_file)))
|
||
|
|
{ return; }
|
||
|
|
FILE *f = fopen(led_file, "w");
|
||
|
|
if(!f)
|
||
|
|
{ return; }
|
||
|
|
fprintf(f, "%d", action);
|
||
|
|
fclose(f);
|
||
|
|
}
|
||
|
|
else // LED Macros
|
||
|
|
{
|
||
|
|
switch(action)
|
||
|
|
{
|
||
|
|
case LED_DEFAULT:
|
||
|
|
arm_switch_led_from_thread(LED1A, LED_OFF);
|
||
|
|
arm_switch_led_from_thread(LED1B, LED_OFF);
|
||
|
|
arm_switch_led_from_thread(LED2, LED_ON);
|
||
|
|
arm_switch_led_from_thread(LED3, LED_OFF);
|
||
|
|
break;
|
||
|
|
case LED_BLINK_OFF:
|
||
|
|
arm_switch_led_from_thread(led, LED_OFF);
|
||
|
|
cs_sleepms(100);
|
||
|
|
arm_switch_led_from_thread(led, LED_ON);
|
||
|
|
break;
|
||
|
|
case LED_BLINK_ON:
|
||
|
|
arm_switch_led_from_thread(led, LED_ON);
|
||
|
|
cs_sleepms(300);
|
||
|
|
arm_switch_led_from_thread(led, LED_OFF);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void *arm_led_thread_main(void *UNUSED(thread_data))
|
||
|
|
{
|
||
|
|
uint8_t running = 1;
|
||
|
|
set_thread_name(__func__);
|
||
|
|
while(running)
|
||
|
|
{
|
||
|
|
LL_ITER iter = ll_iter_create(arm_led_actions);
|
||
|
|
struct s_arm_led *arm_led;
|
||
|
|
while((arm_led = ll_iter_next(&iter)))
|
||
|
|
{
|
||
|
|
int32_t led, action;
|
||
|
|
time_t now, start;
|
||
|
|
led = arm_led->led;
|
||
|
|
action = arm_led->action;
|
||
|
|
now = time(0);
|
||
|
|
start = arm_led->start_time;
|
||
|
|
ll_iter_remove_data(&iter);
|
||
|
|
if(action == LED_STOP_THREAD)
|
||
|
|
{
|
||
|
|
running = 0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if(now - start < ARM_LED_TIMEOUT)
|
||
|
|
{
|
||
|
|
arm_switch_led_from_thread(led, action);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(running)
|
||
|
|
{
|
||
|
|
sleep(60);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ll_clear_data(arm_led_actions);
|
||
|
|
pthread_exit(NULL);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void arm_led_start_thread(void)
|
||
|
|
{
|
||
|
|
arm_detect_led_type();
|
||
|
|
if(!cfg.enableled || arm_led_type == LED_TYPE_UNKNOWN)
|
||
|
|
{ return; }
|
||
|
|
// call this after signal handling is done
|
||
|
|
if(!arm_led_actions)
|
||
|
|
{
|
||
|
|
arm_led_actions = ll_create("arm_led_actions");
|
||
|
|
}
|
||
|
|
|
||
|
|
start_thread("arm led", arm_led_thread_main, NULL, &arm_led_thread, 1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void arm_led(int32_t led, int32_t action)
|
||
|
|
{
|
||
|
|
struct s_arm_led *data;
|
||
|
|
if(!cfg.enableled || arm_led_type == LED_TYPE_UNKNOWN)
|
||
|
|
{ return; }
|
||
|
|
if(!arm_led_actions)
|
||
|
|
{
|
||
|
|
arm_led_actions = ll_create("arm_led_actions");
|
||
|
|
}
|
||
|
|
if(cs_malloc(&data, sizeof(struct s_arm_led)))
|
||
|
|
{
|
||
|
|
data->start_time = time(0);
|
||
|
|
data->led = led;
|
||
|
|
data->action = action;
|
||
|
|
ll_append(arm_led_actions, (void *)data);
|
||
|
|
}
|
||
|
|
if(arm_led_thread)
|
||
|
|
{
|
||
|
|
// arm_led_thread_main is not started at oscam startup
|
||
|
|
// when first arm_led calls happen
|
||
|
|
pthread_kill(arm_led_thread, OSCAM_SIGNAL_WAKEUP);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void arm_led_stop_thread(void)
|
||
|
|
{
|
||
|
|
if(!cfg.enableled || arm_led_type == LED_TYPE_UNKNOWN)
|
||
|
|
{ return; }
|
||
|
|
arm_led(0, LED_STOP_THREAD);
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
static inline void arm_led_start_thread(void) { }
|
||
|
|
static inline void arm_led_stop_thread(void) { }
|
||
|
|
static inline void arm_led(int32_t UNUSED(led), int32_t UNUSED(action)) { }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
#ifdef QBOXHD
|
||
|
|
static void qboxhd_led_blink(int32_t color, int32_t duration)
|
||
|
|
{
|
||
|
|
int32_t f;
|
||
|
|
if(cfg.enableled != 2)
|
||
|
|
{ return; }
|
||
|
|
// try QboxHD-MINI first
|
||
|
|
if((f = open(QBOXHDMINI_LED_DEVICE, O_RDWR | O_NONBLOCK)) > -1)
|
||
|
|
{
|
||
|
|
qboxhdmini_led_color_struct qbminiled;
|
||
|
|
uint32_t qboxhdmini_color = 0x000000;
|
||
|
|
if(color != QBOXHD_LED_COLOR_OFF)
|
||
|
|
{
|
||
|
|
switch(color)
|
||
|
|
{
|
||
|
|
case QBOXHD_LED_COLOR_RED:
|
||
|
|
qboxhdmini_color = QBOXHDMINI_LED_COLOR_RED;
|
||
|
|
break;
|
||
|
|
case QBOXHD_LED_COLOR_GREEN:
|
||
|
|
qboxhdmini_color = QBOXHDMINI_LED_COLOR_GREEN;
|
||
|
|
break;
|
||
|
|
case QBOXHD_LED_COLOR_BLUE:
|
||
|
|
qboxhdmini_color = QBOXHDMINI_LED_COLOR_BLUE;
|
||
|
|
break;
|
||
|
|
case QBOXHD_LED_COLOR_YELLOW:
|
||
|
|
qboxhdmini_color = QBOXHDMINI_LED_COLOR_YELLOW;
|
||
|
|
break;
|
||
|
|
case QBOXHD_LED_COLOR_MAGENTA:
|
||
|
|
qboxhdmini_color = QBOXHDMINI_LED_COLOR_MAGENTA;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// set LED on with color
|
||
|
|
qbminiled.red = (uint8_t)((qboxhdmini_color & 0xFF0000) >> 16); // R
|
||
|
|
qbminiled.green = (uint8_t)((qboxhdmini_color & 0x00FF00) >> 8); // G
|
||
|
|
qbminiled.blue = (uint8_t)(qboxhdmini_color & 0x0000FF); // B
|
||
|
|
ioctl(f, QBOXHDMINI_IOSET_RGB, &qbminiled);
|
||
|
|
cs_sleepms(duration);
|
||
|
|
}
|
||
|
|
// set LED off
|
||
|
|
qbminiled.red = 0;
|
||
|
|
qbminiled.green = 0;
|
||
|
|
qbminiled.blue = 0;
|
||
|
|
ioctl(f, QBOXHDMINI_IOSET_RGB, &qbminiled);
|
||
|
|
close(f);
|
||
|
|
}
|
||
|
|
else if((f = open(QBOXHD_LED_DEVICE, O_RDWR | O_NONBLOCK)) > -1)
|
||
|
|
{
|
||
|
|
qboxhd_led_color_struct qbled;
|
||
|
|
if(color != QBOXHD_LED_COLOR_OFF)
|
||
|
|
{
|
||
|
|
// set LED on with color
|
||
|
|
qbled.H = color;
|
||
|
|
qbled.S = 99;
|
||
|
|
qbled.V = 99;
|
||
|
|
ioctl(f, QBOXHD_SET_LED_ALL_PANEL_COLOR, &qbled);
|
||
|
|
cs_sleepms(duration);
|
||
|
|
}
|
||
|
|
// set LED off
|
||
|
|
qbled.H = 0;
|
||
|
|
qbled.S = 0;
|
||
|
|
qbled.V = 0;
|
||
|
|
ioctl(f, QBOXHD_SET_LED_ALL_PANEL_COLOR, &qbled);
|
||
|
|
close(f);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
static inline void qboxhd_led_blink(int32_t UNUSED(color), int32_t UNUSED(duration)) { }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void led_status_stopping(void)
|
||
|
|
{
|
||
|
|
if(cfg.enableled == 1)
|
||
|
|
{
|
||
|
|
arm_led(LED1B, LED_OFF);
|
||
|
|
arm_led(LED2, LED_OFF);
|
||
|
|
arm_led(LED3, LED_OFF);
|
||
|
|
arm_led(LED1A, LED_ON);
|
||
|
|
}
|
||
|
|
if(cfg.enableled == 2)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_YELLOW, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_RED, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_GREEN, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_BLUE, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_MAGENTA, QBOXHD_LED_BLINK_FAST);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_cw_not_found(ECM_REQUEST *er)
|
||
|
|
{
|
||
|
|
if(!er->rc)
|
||
|
|
{ arm_led(LED2, LED_BLINK_OFF); }
|
||
|
|
if(er->rc < E_NOTFOUND)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_GREEN, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
else if(er->rc <= E_STOPPED)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_RED, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_default(void)
|
||
|
|
{
|
||
|
|
arm_led(LED1A, LED_DEFAULT);
|
||
|
|
arm_led(LED1A, LED_ON);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_starting(void)
|
||
|
|
{
|
||
|
|
arm_led(LED1A, LED_OFF);
|
||
|
|
arm_led(LED1B, LED_ON);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_YELLOW, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_RED, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_GREEN, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_BLUE, QBOXHD_LED_BLINK_FAST);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_MAGENTA, QBOXHD_LED_BLINK_FAST);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_card_activation_error(void)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_MAGENTA, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_found_cardsystem(void)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_YELLOW, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_GREEN, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_YELLOW, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_GREEN, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_unsupported_card_system(void)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_MAGENTA, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_card_detected(void)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_YELLOW, QBOXHD_LED_BLINK_SLOW);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_card_ejected(void)
|
||
|
|
{
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_RED, QBOXHD_LED_BLINK_SLOW);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_status_emm_ok(void)
|
||
|
|
{
|
||
|
|
arm_led(LED3, LED_BLINK_ON);
|
||
|
|
qboxhd_led_blink(QBOXHD_LED_COLOR_BLUE, QBOXHD_LED_BLINK_MEDIUM);
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_init(void)
|
||
|
|
{
|
||
|
|
arm_led_start_thread();
|
||
|
|
}
|
||
|
|
|
||
|
|
void led_stop(void)
|
||
|
|
{
|
||
|
|
arm_led_stop_thread();
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|