Page 1 of 1

esp-matter LoadProhibited error when updating attribute

Posted: Tue Aug 01, 2023 5:59 pm
by Okywan
Trying to implement an AC controller with an ESP32 and IR transmitter. Everything seems to be working fine until adding matter (which is crucial at this point), when I control the status of the AC which should send the IR command, the system crashes with LoadProhibited error.

I've narrowed the problem to be when trying to send the IR command. But can't wrap my head around where or what might be causing the issue.

A brief explanation:
There's an `IRTransceiver` class that handles the rmt driver initialisation and interfaces with it in order to send the IR command. This is passed to an `AirConditioner` object that is intended to hold the state of the AC unit as selected on the controller APP. At the moment it is only a placeholder as `state` is not being updated anywhere in the code, and it always sends the same state value. `State` is not being modified anywhere in the code. Just sent whenever the `power` property is changed.

With this in mind, this seems to point to the root of the problem. When initialised, `state` is this as shown on log with `ESP_LOG` calls:

Code: Select all

I (934) AirConditioner: State is init here, contents:
I (944) AirConditioner: ==========================
I (944) AirConditioner: ==========================
I (954) AirConditioner: ==========================
I (954) AirConditioner: ========= STATE ==========
I (964) AirConditioner: 131 
I (964) AirConditioner: 6 
I (974) AirConditioner: 4 
I (974) AirConditioner: 114 
I (974) AirConditioner: 0 
I (984) AirConditioner: 0 
I (984) AirConditioner: 148 
I (984) AirConditioner: 56 
I (994) AirConditioner: 0 
I (994) AirConditioner: 0 
I (994) AirConditioner: 0 
I (1004) AirConditioner: 128 
I (1004) AirConditioner: 25 
I (1004) AirConditioner: 67 
I (1014) AirConditioner: 0 
I (1014) AirConditioner: 1 
I (1014) AirConditioner: 0 
I (1024) AirConditioner: 0 
I (1024) AirConditioner: 0 
I (1024) AirConditioner: 0 
I (1034) AirConditioner: 1 
I (1034) AirConditioner: ======= END STATE ========
I (1044) AirConditioner: ==========================
I (1044) AirConditioner: ==========================
I (1054) AirConditioner: ==========================
However, when accessing it in the `sendState` method, `state` has somehow changed:

Code: Select all

I (13244) AirConditioner: SetPower called
I (13244) AirConditioner: Setting new power value
I (13254) AirConditioner: Sending new state...
I (13254) AirConditioner: passing state for sending.
I (13264) AirConditioner: ==========================
I (13264) AirConditioner: ==========================
I (13274) AirConditioner: ==========================
I (13274) AirConditioner: ========= STATE ==========
I (13274) AirConditioner: 0 
I (13294) AirConditioner: 0 
I (13294) AirConditioner: 0 
I (13294) AirConditioner: 0 
I (13304) AirConditioner: 0 
I (13304) AirConditioner: 0 
I (13304) AirConditioner: 0 
I (13304) AirConditioner: 0 
I (13314) AirConditioner: 0 
I (13314) AirConditioner: 60 
I (13314) AirConditioner: 55 
I (13314) AirConditioner: 64 
I (13324) AirConditioner: 63 
I (13334) AirConditioner: 48 
I (13334) AirConditioner: 188 
I (13334) AirConditioner: 251 
I (13344) AirConditioner: 63 
I (13344) AirConditioner: 16 
I (13344) AirConditioner: 188 
I (13354) AirConditioner: 251 
I (13354) AirConditioner: 63 
I (13354) AirConditioner: ======= END STATE ========
I (13374) AirConditioner: ==========================
I (13374) AirConditioner: ==========================
I (13374) AirConditioner: ==========================
I figured a workaround would be to use a local variable, while finding out why of a method and not accessing the value of `state` but the code crashes anyway. So, something is "moving" the memory locations or something like this. But I don't know what and how can I find it out.


Matter requires for a series of callbacks to be implemented and the `AirConditioner` object is passed as a reference as priv_data so it can be recalled afterwards on the callback:

Code: Select all

esp_err_t matterDriverInit(AirConditioner ac) {
    node::config_t nodeConfig;
    node_t *node = node::create(&nodeConfig, handleAttributeUpdate, handleIdentification);

    on_off_plugin_unit::config_t acConfig;
    acConfig.on_off.on_off = false;

    endpoint_t *endpoint = on_off_plugin_unit::create(node, &acConfig, ENDPOINT_FLAG_NONE, &ac);

//other stuff

}
[code]

then on the callback used for attribute update handling it is casted back to `AirConditioner`:

[code]
esp_err_t handleAttributeUpdate(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) {
    
    esp_err_t err = ESP_OK;
    if(endpoint_id == acEndpointId) {
        AirConditioner* ac = (AirConditioner*)priv_data;
        if (cluster_id == OnOff::Id) {
            if(attribute_id == OnOff::Attributes::OnOff::Id) {
                ac->setPower(val->val.b); // this calls for sendstate afterwards.
            }
        }
    }     
}
//else for error if needed...
return err;

This might be the start of the issue but I believe from examples I've seen this is what should be done and don't know how to check if this is the root cause or not.



Then `sendState()`simply passes the `state` property to the `IRTransceiver` so it can be sent through the IR transmitter.

Code: Select all

void AirConditioner::sendState() {
    
#ifdef DEBUG
    ESP_LOGI(TAG_AC, "passing state for sending.");
    ESP_LOGI(TAG_AC, "==========================");
    ESP_LOGI(TAG_AC, "==========================");
    ESP_LOGI(TAG_AC, "==========================");
    ESP_LOGI(TAG_AC, "========= STATE ==========");

    for (int i=0; i<21; i++) {
        ESP_LOGI(TAG_AC, "%d ", this->state[i] );
    }

    ESP_LOGI(TAG_AC, "======= END STATE ========");
    ESP_LOGI(TAG_AC, "==========================");
    ESP_LOGI(TAG_AC, "==========================");
    ESP_LOGI(TAG_AC, "==========================");
#endif 

    //this->transceiver.sendIRCommand(this->state); 
    this->transceiver.sendDefaultState();//workaround
    
    
}
then both `sendIRCommand`and `sendDefaultState` work similarly:

Code: Select all


size_t IRTransceiver::sendIRCommand(uint8_t state[21]){

    #ifdef DEBUG
    ESP_LOGI(TAG, "State received:");
    ESP_LOGI(TAG, "==========================");
    ESP_LOGI(TAG, "==========================");
    ESP_LOGI(TAG, "==========================");
    ESP_LOGI(TAG, "========= STATE ==========");

    for (int i=0; i<21; i++) {
        ESP_LOGI(TAG, "%d ", state[i] );
    }

    ESP_LOGI(TAG, "======= END STATE ========");
    ESP_LOGI(TAG, "==========================");
    ESP_LOGI(TAG, "==========================");
    ESP_LOGI(TAG, "==========================");
#endif 
    ESP_LOGI(TAG, "Sending IR Command");
    return rmt_transmit(this->txChannel, this->encoder, &state, sizeof(&state), &this->txConfig);
 
}

size_t IRTransceiver::sendDefaultState(){

    ESP_LOGI(TAG, "Sending IR Command for default state");
    uint8_t defaultState[21] = {0x83, 0x06, 0x04, 0x72, 0x00, 0x00, 0x94, 0x38, 0x00, 0x00, 0x00, 0x80, 0x19, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01};
    return rmt_transmit(this->txChannel, this->encoder, &defaultState, sizeof(&defaultState), &this->txConfig);
    ESP_LOGI(TAG, "Sent IR Command");
    
}

But both crash when called from the esp-matter callback.

However, when using it from a debug main directly without involving callbacks, they work as expected, the command is sent and the system doesn't crash which point to proper implementation on `IRTransceiver` and `AirConditioner`

Code: Select all

extern "C" void app_main() {

    std::string protocol = "KELON168";
    
    //Initialize IR TX
    IRTransceiver transceiver(IR_TX_PIN,protocol);


    esp_err_t res = transceiver.enableTx();

    if (res == ESP_OK) {
        ESP_LOGI("DEBUG_IR", "sucessfully enabled IR transmission");
    }
    else {
        ESP_LOGI("DEBUG_IR", "error enabling IR transmission");
    }

    AirConditioner ac(25,1,1,false,transceiver);

    if (res == ESP_OK) {
        ESP_LOGI("DEBUG_IR", "sucessfully enabled IR transmission");
    }
    else {
        ESP_LOGI("DEBUG_IR", "error enabling IR transmission");
    }

    ESP_LOGI("DEBUG_IR", "Updating power to true");
    ac.setPower(true);
    ESP_LOGI("DEBUG_IR", "Updating power to false");
    ac.setPower(false);
    ESP_LOGI("DEBUG_IR", "did not crash :o");
    
}

Any ideas?

Re: esp-matter LoadProhibited error when updating attribute

Posted: Tue Aug 01, 2023 10:19 pm
by ESP_igrr
Are you sure you aren't overflowing the stack of the task where Matter callbacks are dispatched? Perhaps you could try to send a notification to another task from matter callback, and invoke IR related functions from that other task?

Re: esp-matter LoadProhibited error when updating attribute

Posted: Wed Aug 02, 2023 3:39 pm
by Okywan
I'm sorry but I'm don't understand your answer. Anyway the problem is now solved. I was initialising IRTransceiver and AirConditioner objects on app_main() which ended up returning and then the objects were being deallocated. After making them global vars everything works fine.