Open pavel808 opened 1 month ago
I don't know the protocol used by the EliteScreens, but in your code, I see
sendGeneric(0, 0, // No header.
kEliteScreensOne, kEliteScreensZero,
kEliteScreensZero, kEliteScreensOne,
0, kEliteScreensGap, data, nbits, 38000, true, repeat, 50);
The comment "No header" seems like that protocol doesn't need a leading symbol as used in the NEC protocol. So I guess this nec_encoder->nec_leading_symbol
is not needed at all.
If you can find a datasheet about the EliteScreen protocol, it can be helpful.
I don't know the protocol used by the EliteScreens, but in your code, I see
sendGeneric(0, 0, // No header. kEliteScreensOne, kEliteScreensZero, kEliteScreensZero, kEliteScreensOne, 0, kEliteScreensGap, data, nbits, 38000, true, repeat, 50);
The comment "No header" seems like that protocol doesn't need a leading symbol as used in the NEC protocol. So I guess this
nec_encoder->nec_leading_symbol
is not needed at all.If you can find a datasheet about the EliteScreen protocol, it can be helpful.
Hello @suda-morris . Thanks for your reply. I tried removing the nec_leading_symbol
. I also tried removing both nec_leading_symbol
and nec_ending_symbol
but in either case nothing gets transmitted then.
Also, where would kEliteScreensGap
come into this?
I can't find a datasheet anywhere about the EliteScreen protocol :-/
I think you should also rewrite the rmt_encode_ir_nec
function, that's all the magic happens for controlling what and how to transmit the RMT symbols.
BYTW, A "gap" can be made up by using a "copy encoder". We also use this approach in the led_strip protocol: https://github.com/espressif/esp-idf/blob/master/examples/peripherals/rmt/led_strip/main/led_strip_encoder.c#L102
@suda-morris Thanks for the replies. I have implemented separate functions now to try and encode for the EliteScreens IR protocol.
Using as a reference the Arduino application which sends EliteScreens IR commands as follows:
// values in us
uint16_t kEliteScreensOne = 470;
uint16_t kEliteScreensZero = 1214;
uint16_t kEliteScreensGap = 29200;
sendGeneric(0, 0, // No header.
kEliteScreensOne, kEliteScreensZero,
kEliteScreensZero, kEliteScreensOne,
0, kEliteScreensGap, data, nbits, 38000, true, repeat, 50);
// Parameters description :
void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace,
const uint16_t onemark, const uint32_t onespace,
const uint16_t zeromark, const uint32_t zerospace,
const uint16_t footermark, const uint32_t gap,
const uint64_t data, const uint16_t nbits,
const uint16_t frequency, const bool MSBfirst,
const uint16_t repeat, const uint8_t dutycycle) {
sendGeneric(headermark, headerspace, onemark, onespace, zeromark, zerospace,
footermark, gap, 0U, data, nbits, frequency, MSBfirst, repeat,
dutycycle);
}
Here is what I have implemented in my IR transceiver, but still getting garbage on the receiver. Do you see anything wrong with this? Thanks in advance.
static size_t rmt_encode_ir_elitescreens(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_ir_encoder_t *elite_encoder = __containerof(encoder, rmt_ir_encoder_t, base);
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
rmt_encode_state_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
ir_nec_scan_code_t *scan_code = (ir_nec_scan_code_t *)primary_data;
rmt_encoder_handle_t copy_encoder = elite_encoder->copy_encoder;
rmt_encoder_handle_t bytes_encoder = elite_encoder->bytes_encoder;
switch (elite_encoder->state) {
case 0: // send leading code
// No leading code in the case for EliteScreens
elite_encoder->state = 1;
// fall-through
case 1: // send address
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &scan_code->address, sizeof(uint16_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
elite_encoder->state = 2; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
// fall-through
case 2: // send command
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &scan_code->command, sizeof(uint16_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
elite_encoder->state = 3; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts-
}
// fall-through
case 3: // No ending code, but send GAP of 29200 us
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &elite_encoder->reset_code,
sizeof(elite_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
elite_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_ir_elitescreens_encoder(rmt_encoder_t *encoder)
{
rmt_ir_encoder_t *elite_encoder = __containerof(encoder, rmt_ir_encoder_t, base);
rmt_del_encoder(elite_encoder->copy_encoder);
rmt_del_encoder(elite_encoder->bytes_encoder);
free(elite_encoder);
return ESP_OK;
}
static esp_err_t rmt_ir_nec_elitescreens_reset(rmt_encoder_t *encoder)
{
rmt_ir_encoder_t *elite_encoder = __containerof(encoder, rmt_ir_encoder_t, base);
rmt_encoder_reset(elite_encoder->copy_encoder);
rmt_encoder_reset(elite_encoder->bytes_encoder);
elite_encoder->state = RMT_ENCODING_RESET;
return ESP_OK;
}
esp_err_t rmt_new_ir_elitescreen_encoder(const ir_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_ir_encoder_t *elite_encoder = NULL;
ESP_GOTO_ON_FALSE(config && elite_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
elite_encoder = rmt_alloc_encoder_mem(sizeof(rmt_ir_encoder_t));
ESP_GOTO_ON_FALSE(elite_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for ir nec encoder");
elite_encoder->base.encode = rmt_encode_ir_elitescreens;
elite_encoder->base.del = rmt_del_ir_elitescreens_encoder;
elite_encoder->base.reset = rmt_ir_nec_elitescreens_reset;
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &elite_encoder->copy_encoder), err, TAG, "create copy encoder failed");
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 470 * config->resolution / 1000000, // T0H=470us
.level1 = 0,
.duration1 = 1214 * config->resolution / 1000000, // T0L=1214us
},
.bit1 = {
.level0 = 1,
.duration0 = 1214 * config->resolution / 1000000, // T1H=1214us
.level1 = 0,
.duration1 = 470 * config->resolution / 1000000, // T1L=470us
},
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &elite_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
// GAP
uint32_t reset_ticks = config->resolution / 1000000 * 29200 / 2; // reset code duration defaults to 29200 us
elite_encoder->reset_code = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = reset_ticks,
.level1 = 0,
.duration1 = reset_ticks,
};
*ret_encoder = &elite_encoder->base;
return ESP_OK;
err:
if (elite_encoder) {
if (elite_encoder->bytes_encoder) {
rmt_del_encoder(elite_encoder->bytes_encoder);
}
if (elite_encoder->copy_encoder) {
rmt_del_encoder(elite_encoder->copy_encoder);
}
free(elite_encoder);
}
return ret;
}
Answers checklist.
General issue report
I am struggling to adapt the the rmt/ir_nec_transceiver example code to be able to send IR commands to my EliteScreens wall controller.
There is support for this wall controller in the Arduino IRremoteESP8266 library which works well:
Having reverse-engineered the code as best I can. The carrier frequency appears the same. However, we can see that the timings are different : onemark is 470us, onespace is 1214us and vice-versa for zeromark and zerospace. The duty cycle is 50% and not 33% like in NEC. :
I created a new function for this in
ir_nec_encoder.c
to try and create the correct encoder for the wall controller as follows:Then inside
ir_nec_transceiver_main.c
, I try to send the data as follows :Unfortunately I am receiving inconsistent garbage on my IR receiver.
I'd appreciate any help in trying to solve this. Thanks.