mirror of https://github.com/arendst/Tasmota.git
473 lines
14 KiB
C++
473 lines
14 KiB
C++
/*
|
|
xdrv_53_projector_ctrl.ino - LCD/DLP Projector Serial Control support for Tasmota
|
|
|
|
Copyright (C) 2021 Jan Bubík <jbubik@centrum.cz>
|
|
Written with the gifts I got from Jesus.
|
|
|
|
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 3 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/>.
|
|
*/
|
|
|
|
#ifdef USE_PROJECTOR_CTRL
|
|
/*********************************************************************************************\
|
|
* LCD/DLP Projector Control via serial interface
|
|
* https://www.sharpnecdisplays.eu/p/download/v/5e14a015e26cacae3ae64a422f7f8af4/cp/Products/Projectors/Shared/CommandLists/PDF-ExternalControlManual-english.pdf#page=5
|
|
* https://www.optoma.co.uk/uploads/manuals/hd36-m-en-gb.pdf#page=56
|
|
\*********************************************************************************************/
|
|
|
|
#define XDRV_53 53
|
|
|
|
#if !defined(USE_PROJECTOR_CTRL_NEC) && !defined(USE_PROJECTOR_CTRL_OPTOMA)
|
|
#define USE_PROJECTOR_CTRL_NEC // Use at least one projector
|
|
#endif
|
|
|
|
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
|
#define xxstr(s) xstr(s)
|
|
#define xstr(s) #s
|
|
|
|
enum projector_ctrl_dev_state_e : uint8_t {
|
|
PROJECTOR_CTRL_DEV_UNKNOWN=0,
|
|
PROJECTOR_CTRL_DEV_PWR_OFF,
|
|
PROJECTOR_CTRL_DEV_PWR_ON
|
|
};
|
|
|
|
enum projector_ctrl_serial_state_e : uint8_t {
|
|
PROJECTOR_CTRL_S_UNCONNECTED=0,
|
|
PROJECTOR_CTRL_S_QRY_PWR,
|
|
PROJECTOR_CTRL_S_QRY_TYPE,
|
|
PROJECTOR_CTRL_S_IDLE,
|
|
PROJECTOR_CTRL_S_PWR_ON,
|
|
PROJECTOR_CTRL_S_PWR_OFF
|
|
};
|
|
|
|
enum projector_ctrl_serial_result_e : uint8_t {
|
|
PROJECTOR_CTRL_R_UNKNOWN=0,
|
|
PROJECTOR_CTRL_R_PASS,
|
|
PROJECTOR_CTRL_R_FAIL
|
|
};
|
|
|
|
struct projector_ctrl_command_info_s {
|
|
const enum projector_ctrl_serial_state_e command;
|
|
const uint8_t *send_codes;
|
|
const uint8_t send_len;
|
|
const uint8_t timeout_ticks;
|
|
const uint8_t pass_first_byte;
|
|
const uint8_t pass_len;
|
|
const uint8_t pass_value_offset;
|
|
const uint8_t pass_value_bytes;
|
|
const uint8_t fail_first_byte;
|
|
const uint8_t fail_len;
|
|
const uint8_t fail_value_offset;
|
|
const uint8_t fail_value_bytes;
|
|
} __packed;
|
|
|
|
#include "xdrv_53_projector_ctrl.h"
|
|
|
|
struct projector_ctrl_softc_s {
|
|
TasmotaSerial *sc_serial;
|
|
uint8_t sc_device;
|
|
uint8_t sc_ticks;
|
|
enum projector_ctrl_dev_state_e sc_dev_state;
|
|
enum projector_ctrl_serial_state_e sc_ser_state;
|
|
enum projector_ctrl_serial_result_e sc_ser_result;
|
|
enum projector_ctrl_serial_state_e sc_ser_next_cmd;
|
|
const struct projector_ctrl_command_info_s *sc_cmd_info;
|
|
uint8_t sc_ser_sum;
|
|
uint8_t sc_ser_len;
|
|
uint32_t sc_ser_value;
|
|
} __packed;
|
|
|
|
static struct projector_ctrl_softc_s *projector_ctrl_sc = nullptr;
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_pre_init(void)
|
|
{
|
|
struct projector_ctrl_softc_s *sc;
|
|
int baudrate = PROJECTOR_CTRL_SERIAL_BAUDRATE;
|
|
|
|
if (!PinUsed(GPIO_PROJECTOR_CTRL_TX) || !PinUsed(GPIO_PROJECTOR_CTRL_RX))
|
|
return;
|
|
|
|
sc = (struct projector_ctrl_softc_s *)malloc(sizeof(*sc));
|
|
if (sc == NULL) {
|
|
AddLog_P(LOG_LEVEL_ERROR, PSTR(PROJECTOR_CTRL_LOGNAME ": unable to allocate state"));
|
|
return;
|
|
}
|
|
|
|
memset(sc, 0, sizeof(*sc));
|
|
|
|
sc->sc_serial = new TasmotaSerial(Pin(GPIO_PROJECTOR_CTRL_RX),
|
|
Pin(GPIO_PROJECTOR_CTRL_TX), 2);
|
|
|
|
if (!sc->sc_serial->begin(baudrate, 2)) {
|
|
AddLog_P(LOG_LEVEL_ERROR, PSTR(PROJECTOR_CTRL_LOGNAME ": unable to begin serial "
|
|
"(baudrate %d)"), baudrate);
|
|
goto del;
|
|
}
|
|
|
|
if (sc->sc_serial->hardwareSerial()) {
|
|
ClaimSerial();
|
|
SetSerial(baudrate, TS_SERIAL_8N1);
|
|
}
|
|
|
|
sc->sc_device = ++(TasmotaGlobal.devices_present); /* claim a POWER device slot */
|
|
|
|
AddLog_P(LOG_LEVEL_INFO, PSTR(PROJECTOR_CTRL_LOGNAME ": new RELAY%d, polling serial for Projector status"), sc->sc_device);
|
|
|
|
projector_ctrl_sc = sc;
|
|
return;
|
|
del:
|
|
delete sc->sc_serial;
|
|
free:
|
|
free(sc);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_write(struct projector_ctrl_softc_s *sc, const uint8_t *bytes, const size_t len)
|
|
{
|
|
TasmotaSerial *serial;
|
|
uint8_t cksum;
|
|
size_t i;
|
|
|
|
cksum = 0;
|
|
serial = sc->sc_serial;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
uint8_t b = bytes[i];
|
|
serial->write(b);
|
|
cksum += b;
|
|
}
|
|
#ifdef USE_PROJECTOR_CTRL_NEC
|
|
serial->write(cksum);
|
|
#endif
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
char hex_b[(len + 1) * 2];
|
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR(PROJECTOR_CTRL_LOGNAME ": RAW bytes %s %02x"),
|
|
ToHex_P((uint8_t *)bytes, len, hex_b, sizeof(hex_b)), cksum);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
|
|
serial->flush();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_request(struct projector_ctrl_softc_s *sc, const uint8_t command)
|
|
{
|
|
const struct projector_ctrl_command_info_s *e;
|
|
size_t i;
|
|
|
|
if ((sc->sc_dev_state!=PROJECTOR_CTRL_DEV_UNKNOWN)&&(sc->sc_ser_state!=PROJECTOR_CTRL_S_IDLE)) {
|
|
if ((command!=PROJECTOR_CTRL_S_QRY_PWR)&&(command!=PROJECTOR_CTRL_S_QRY_TYPE)) {
|
|
sc->sc_ser_next_cmd=(projector_ctrl_serial_state_e)command;
|
|
AddLog_P(LOG_LEVEL_INFO, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Serial CMD %02x already running, enqueueing next (%02x)"), sc->sc_ser_state, command);
|
|
};
|
|
return;
|
|
};
|
|
|
|
for (i = 0; i < nitems(projector_ctrl_commands); i++) {
|
|
e = &projector_ctrl_commands[i];
|
|
if (command == e->command){
|
|
sc->sc_cmd_info=e;
|
|
sc->sc_ser_len=0;
|
|
sc->sc_ser_result=PROJECTOR_CTRL_R_UNKNOWN;
|
|
sc->sc_ser_state=(projector_ctrl_serial_state_e)command;
|
|
sc->sc_ser_sum=0;
|
|
sc->sc_ser_next_cmd=PROJECTOR_CTRL_S_UNCONNECTED;
|
|
sc->sc_ticks=0;
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Sending CMD %02x"), command);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
projector_ctrl_write(sc,e->send_codes,e->send_len);
|
|
return;
|
|
}
|
|
};
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Undefined serial command %02x"), command);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
static uint8_t
|
|
projector_ctrl_parse(struct projector_ctrl_softc_s *sc, const uint8_t byte)
|
|
{
|
|
enum projector_ctrl_serial_state_e nstate;
|
|
const struct projector_ctrl_command_info_s *cmd;
|
|
|
|
nstate = sc->sc_ser_state;
|
|
|
|
switch (nstate) {
|
|
case PROJECTOR_CTRL_S_IDLE:
|
|
case PROJECTOR_CTRL_S_UNCONNECTED:
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Spurious input in state %02x, got %02x, going UNCONNECTED"), nstate, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
return(PROJECTOR_CTRL_S_UNCONNECTED);
|
|
|
|
default:
|
|
cmd=sc->sc_cmd_info;
|
|
sc->sc_ser_len++;
|
|
if (sc->sc_ser_len==1) {
|
|
if (byte==cmd->pass_first_byte){
|
|
sc->sc_ser_result=PROJECTOR_CTRL_R_PASS;
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": CMD %02x PASS, 1st byte %02x"), nstate, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
}else if (byte==cmd->fail_first_byte){
|
|
sc->sc_ser_result=PROJECTOR_CTRL_R_FAIL;
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": CMD %02x FAIL, 1st byte %02x"), nstate, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
}else{
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": CMD %02x UNKNOWN, 1st byte %02x, going UNCONNECTED"), nstate, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
return(PROJECTOR_CTRL_S_UNCONNECTED);
|
|
};
|
|
};
|
|
if (sc->sc_ser_result==PROJECTOR_CTRL_R_PASS){
|
|
if (sc->sc_ser_len==(cmd->pass_value_offset+1))
|
|
sc->sc_ser_value=byte;
|
|
if ((sc->sc_ser_len>(cmd->pass_value_offset+1))&&(sc->sc_ser_len<=(cmd->pass_value_offset+cmd->pass_value_bytes)))
|
|
sc->sc_ser_value=(sc->sc_ser_value<<8)|byte;
|
|
if (sc->sc_ser_len==cmd->pass_len){
|
|
#ifdef USE_PROJECTOR_CTRL_NEC
|
|
if(sc->sc_ser_sum!=byte){
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Failed cksum for CMD %02x. Got %02x bytes, computed cksum: %02x, recevied cksum: %02x, going UNCONNECTED"),
|
|
nstate, sc->sc_ser_len, sc->sc_ser_sum, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
nstate=PROJECTOR_CTRL_S_UNCONNECTED;
|
|
} else
|
|
#endif //USE_PROJECTOR_CTRL_NEC
|
|
{
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": CMD %02x PASS, got %02x bytes, retval %02x, going IDLE"), nstate, sc->sc_ser_len, sc->sc_ser_value);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
nstate=PROJECTOR_CTRL_S_IDLE;
|
|
};
|
|
};
|
|
};
|
|
|
|
if (sc->sc_ser_result==PROJECTOR_CTRL_R_FAIL) {
|
|
if (sc->sc_ser_len==(cmd->fail_value_offset+1))
|
|
sc->sc_ser_value=byte;
|
|
if ((sc->sc_ser_len>(cmd->fail_value_offset+1))&&(sc->sc_ser_len<=(cmd->fail_value_offset+cmd->fail_value_bytes)))
|
|
sc->sc_ser_value=(sc->sc_ser_value<<8)|byte;
|
|
if(sc->sc_ser_len==cmd->fail_len){
|
|
#ifdef USE_PROJECTOR_CTRL_NEC
|
|
if(sc->sc_ser_sum!=byte){
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": Failed cksum for CMD %02x. Got %02x bytes, computed cksum: %02x, receied cksum: %02x, going UNCONNECTED"),
|
|
nstate, sc->sc_ser_len, sc->sc_ser_sum, byte);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
nstate=PROJECTOR_CTRL_S_UNCONNECTED;
|
|
} else
|
|
#endif //USE_PROJECTOR_CTRL_NEC
|
|
{
|
|
#ifdef DEBUG_PROJECTOR_CTRL
|
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
|
|
": CMD %02x FAIL, got %02x bytes, retval %02x, going idle"), nstate, sc->sc_ser_len, sc->sc_ser_value);
|
|
#endif //DEBUG_PROJECTOR_CTRL
|
|
nstate=PROJECTOR_CTRL_S_IDLE;
|
|
};
|
|
};
|
|
};
|
|
|
|
#ifdef USE_PROJECTOR_CTRL_NEC
|
|
sc->sc_ser_sum += byte;
|
|
#endif //USE_PROJECTOR_CTRL_NEC
|
|
|
|
break;
|
|
}
|
|
return (nstate);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_loop(struct projector_ctrl_softc_s *sc)
|
|
{
|
|
TasmotaSerial *serial;
|
|
uint8_t oldstate;
|
|
serial = sc->sc_serial;
|
|
|
|
while (serial->available()) {
|
|
yield();
|
|
oldstate = sc->sc_ser_state;
|
|
switch (sc->sc_ser_state = (projector_ctrl_serial_state_e)projector_ctrl_parse(sc, serial->read())) {
|
|
case PROJECTOR_CTRL_S_UNCONNECTED:
|
|
if (sc->sc_dev_state!=PROJECTOR_CTRL_DEV_UNKNOWN){
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_UNKNOWN;
|
|
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": DISCONNECTED(unexpected input)"));
|
|
}
|
|
break;
|
|
case PROJECTOR_CTRL_S_IDLE:
|
|
if ((oldstate==PROJECTOR_CTRL_S_QRY_PWR)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS)){
|
|
if(sc->sc_dev_state==PROJECTOR_CTRL_DEV_UNKNOWN){
|
|
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": CONNECTED"));
|
|
};
|
|
if(( (sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_ON)
|
|
||(sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_COOLING)
|
|
||(sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_STARTING)
|
|
||(sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_WARMING)
|
|
)&&(sc->sc_dev_state!=PROJECTOR_CTRL_DEV_PWR_ON)){
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_ON;
|
|
ExecuteCommandPower(sc->sc_device, POWER_ON, SRC_IGNORE);
|
|
};
|
|
if(( (sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_ON)
|
|
&&(sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_COOLING)
|
|
&&(sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_STARTING)
|
|
&&(sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_WARMING)
|
|
)&&(sc->sc_dev_state!=PROJECTOR_CTRL_DEV_PWR_OFF)){
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_OFF;
|
|
ExecuteCommandPower(sc->sc_device, POWER_OFF, SRC_IGNORE);
|
|
};
|
|
};
|
|
if ((oldstate==PROJECTOR_CTRL_S_PWR_ON)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS))
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_ON;
|
|
if ((oldstate==PROJECTOR_CTRL_S_PWR_OFF)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS))
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_OFF;
|
|
if(sc->sc_ser_next_cmd!=PROJECTOR_CTRL_S_UNCONNECTED){
|
|
oldstate=sc->sc_ser_next_cmd;
|
|
sc->sc_ser_next_cmd=PROJECTOR_CTRL_S_UNCONNECTED;
|
|
projector_ctrl_request(sc,oldstate);
|
|
};
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_connect(struct projector_ctrl_softc_s *sc)
|
|
{
|
|
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_PWR);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
projector_ctrl_tick(struct projector_ctrl_softc_s *sc)
|
|
{
|
|
if(sc->sc_ser_state==PROJECTOR_CTRL_S_IDLE){
|
|
switch (TasmotaGlobal.uptime&0xf) {
|
|
case 0:
|
|
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_PWR);
|
|
break;
|
|
case 8:
|
|
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_TYPE);
|
|
break;
|
|
};
|
|
}else if(sc->sc_ticks > sc->sc_cmd_info->timeout_ticks){
|
|
//current CMD has ran out of time, drop connection
|
|
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": DISCONNECTED(timeout)"));
|
|
sc->sc_dev_state=PROJECTOR_CTRL_DEV_UNKNOWN;
|
|
sc->sc_ser_state=PROJECTOR_CTRL_S_UNCONNECTED;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
projector_ctrl_set_power(struct projector_ctrl_softc_s *sc)
|
|
{
|
|
if (TasmotaGlobal.active_device==PROJECTOR_CTRL_PWR_BY_RELAY){
|
|
if ((sc->sc_dev_state == PROJECTOR_CTRL_DEV_PWR_ON) && (0==bitRead(XdrvMailbox.index, PROJECTOR_CTRL_PWR_BY_RELAY -1))) {
|
|
TasmotaGlobal.power = bitSet(TasmotaGlobal.power,PROJECTOR_CTRL_PWR_BY_RELAY -1);
|
|
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": Keep RELAY" xxstr(PROJECTOR_CTRL_PWR_BY_RELAY) " ON"));
|
|
} else {
|
|
return(false);
|
|
};
|
|
} else if (TasmotaGlobal.active_device==sc->sc_device){
|
|
if (bitRead(XdrvMailbox.index, sc->sc_device -1)) {
|
|
switch (sc->sc_dev_state) {
|
|
case PROJECTOR_CTRL_DEV_UNKNOWN:
|
|
TasmotaGlobal.power = bitClear(TasmotaGlobal.power,sc->sc_device -1);
|
|
break;
|
|
case PROJECTOR_CTRL_DEV_PWR_OFF:
|
|
projector_ctrl_request(sc,PROJECTOR_CTRL_S_PWR_ON);
|
|
break;
|
|
};
|
|
}else{
|
|
if (sc->sc_dev_state == PROJECTOR_CTRL_DEV_PWR_ON)
|
|
projector_ctrl_request(sc,PROJECTOR_CTRL_S_PWR_OFF);
|
|
};
|
|
} else {
|
|
return(false);
|
|
};
|
|
return (true);
|
|
}
|
|
|
|
|
|
/*********************************************************************************************\
|
|
* Interface
|
|
\*********************************************************************************************/
|
|
|
|
bool Xdrv53(uint8_t function) {
|
|
bool result;
|
|
struct projector_ctrl_softc_s *sc;
|
|
|
|
result = false;
|
|
sc = projector_ctrl_sc;
|
|
|
|
switch (function) {
|
|
case FUNC_PRE_INIT:
|
|
projector_ctrl_pre_init();
|
|
return (false);
|
|
}
|
|
|
|
if (sc == NULL)
|
|
return (false);
|
|
|
|
switch (function) {
|
|
case FUNC_LOOP:
|
|
projector_ctrl_loop(sc);
|
|
break;
|
|
|
|
case FUNC_EVERY_SECOND:
|
|
sc->sc_ticks++;
|
|
if (sc->sc_dev_state!=PROJECTOR_CTRL_DEV_UNKNOWN)
|
|
projector_ctrl_tick(sc);
|
|
else if ((TasmotaGlobal.uptime&0x7)==0) //each 8 seconds
|
|
projector_ctrl_connect(sc);
|
|
break;
|
|
|
|
case FUNC_SET_DEVICE_POWER:
|
|
result = projector_ctrl_set_power(sc);
|
|
break;
|
|
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
#endif // USE_PROJECTOR_CTRL
|