Sending passthrough command // problems in structural understanding

prokkuez
Posts: 3
Joined: Thu Nov 12, 2020 7:33 pm

Sending passthrough command // problems in structural understanding

Postby prokkuez » Thu Nov 12, 2020 7:50 pm

Hello there,
Just went from Arduino to esp-idf framework. My goal is to send bt-commands for audio control (next track, etc.) to a mobile phone when a pin is high.

I took the a2dp sink demo as basis and reprogrammed some parts. As well set up the sdkconfig.
I commented out the whole part about a2d since I dont rly need it in the end of main.c and can connect to the esp but if i send a command
BT_BTC: Function btc_avrc_ct_send_passthrough_cmd() called when RC is not connected
When I comment it back in the result is it sends the command and causes guru meditation error
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x4013f382 PS : 0x00060730 A0 : 0x800d2d50 A1 : 0x3ffdd920
A2 : 0x00000000 A3 : 0x3ffdb5b4 A4 : 0x00001000 A5 : 0x3ffdd954
A6 : 0xffffffff A7 : 0x00000000 A8 : 0x3ffd1328 A9 : 0x3ffdd8d0
A10 : 0x00000001 A11 : 0x00000000 A12 : 0x00000001 A13 : 0x00000002
A14 : 0xffffffff A15 : 0x0000143a SAR : 0x00000000 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000018 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000

ELF file SHA256: 45d5f21bfd551b14

Backtrace: 0x4013f37f:0x3ffdd920 0x400d2d4d:0x3ffdd950 0x4008e5ad:0x3ffdd980

Rebooting...
main.c:

Code: Select all

// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"

#include "esp_bt.h"
#include "bt_app_core.h"
#include "bt_app_av.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
#include "esp_a2dp_api.h"
#include "esp_avrc_api.h"
#include "driver/gpio.h"

// OUTPUT Pins
#define GPIO_OUTPUT_IO_0 34
#define GPIO_OUTPUT_IO_1 12
#define GPIO_OUTPUT_PIN_SEL ((1ULL << GPIO_OUTPUT_IO_0) | (1ULL << GPIO_OUTPUT_IO_1))

// INPUT Pins
#define GPIO_INPUT_IO_0 4
#define GPIO_INPUT_IO_1 5
#define GPIO_INPUT_PIN_SEL ((1ULL << GPIO_INPUT_IO_0) | (1ULL << GPIO_INPUT_IO_1))
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL;

// Fügt isr event dem queue hinzu
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    // Interrupt sollte keine Funktionen ausführen die nicht im Ram sind!
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

/* event for handler "bt_av_hdl_stack_up */
enum
{
    BT_APP_EVT_STACK_UP = 0,
};

/* handler for bluetooth stack enabled events */
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);

// Fragt queue nach (isr-)events ab
static void testPinActive(void *arg)
{
    uint32_t io_num;
    for (;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {
            printf("pin %d aktiv", io_num);
            // Siehe sdkconfig.CONFIG_FREERTOS_HZ für portTICK_RATE_MS
            vTaskDelay(portTICK_RATE_MS);

            esp_err_t err;
            if (io_num == 4 || io_num == 5)
            {
                err = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_PRESSED);
                err = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_RELEASED);
            }
            else
            {
                err = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_PRESSED);
                err = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_RELEASED);
            }

            if (err == ESP_OK)
            {
                printf("cmd send");
            }
            else
            {
                printf("cmd not send: %i", err);
            }
        }
    }
}

void app_main(void)
{
    /* Initialize NVS — it is used to store PHY calibration data */
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));

    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK)
    {
        ESP_LOGE(BT_AV_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }

    if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK)
    {
        ESP_LOGE(BT_AV_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }

    if ((err = esp_bluedroid_init()) != ESP_OK)
    {
        ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }

    if ((err = esp_bluedroid_enable()) != ESP_OK)
    {
        ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }

    /* create application task */
    bt_app_task_start_up();

    /* Bluetooth device name, connection mode and profile set up */
    bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);

#if (CONFIG_BT_SSP_ENABLED == true)
    /* Set default parameters for Secure Simple Pairing */
    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif

    /*
     * Set default parameters for Legacy Pairing
     * Use fixed pin code
     */
    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
    esp_bt_pin_code_t pin_code;
    pin_code[0] = '1';
    pin_code[1] = '2';
    pin_code[2] = '3';
    pin_code[3] = '4';
    esp_bt_gap_set_pin(pin_type, 4, pin_code);

    //GPIO
    gpio_config_t io_conf;
    //interrupt of rising edge
    io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
    //bit mask of the pins, use GPIO4/5/TEST here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode
    io_conf.mode = GPIO_MODE_INPUT;

    //enable pull-down mode
    io_conf.pull_down_en = 1;
    //enable pull-up mode
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);

    //change gpio intrrupt type for one pin
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_POSEDGE);
    gpio_set_intr_type(GPIO_INPUT_IO_1, GPIO_INTR_POSEDGE);

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    //start gpio task
    //xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
    xTaskCreate(testPinActive, "testPinActive", 2048, NULL, 10, NULL);

    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    //gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void *)GPIO_INPUT_IO_1);

    //remove isr handler for gpio number.
    //gpio_isr_handler_remove(GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin again
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *)GPIO_INPUT_IO_0);

    // loop
    while (1)
    {
        vTaskDelay(10 / portTICK_RATE_MS);
    };
}

void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
    switch (event)
    {
    case ESP_BT_GAP_AUTH_CMPL_EVT:
    {
        if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS)
        {
            ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
            esp_log_buffer_hex(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
        }
        else
        {
            ESP_LOGE(BT_AV_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
        }
        break;
    }

#if (CONFIG_BT_SSP_ENABLED == true)
    case ESP_BT_GAP_CFM_REQ_EVT:
        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
        esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
        break;
    case ESP_BT_GAP_KEY_NOTIF_EVT:
        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
        break;
    case ESP_BT_GAP_KEY_REQ_EVT:
        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
        break;
#endif

    default:
    {
        ESP_LOGI(BT_AV_TAG, "event: %d", event);
        break;
    }
    }
    return;
}
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
{
    ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
    switch (event)
    {
    case BT_APP_EVT_STACK_UP:
    {
        /* set up device name */
        char *dev_name = "TestBla";
        esp_bt_dev_set_device_name(dev_name);

        esp_bt_gap_register_callback(bt_app_gap_cb);

        /* initialize AVRCP controller */
        esp_avrc_ct_init();
        esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
        /* initialize AVRCP target */
        assert(esp_avrc_tg_init() == ESP_OK);
        esp_avrc_tg_register_callback(bt_app_rc_tg_cb);

        esp_avrc_rn_evt_cap_mask_t evt_set = {0};
        esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
        assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
        
        /* initialize A2DP sink */
       /*  esp_a2d_register_callback(&bt_app_a2d_cb);
        esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
        esp_a2d_sink_init(); */

        /* set discoverable and connectable mode, wait to be connected */
        esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
        break;
    }
    default:
        ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
        break;
    }
}
sdkconfig:
https://pastebin.com/nxNM2aRC

Coming from the java/webapp backend realm I have a hard time understand the concepts of esp-idf and about the bt-world of it. As well, the documentation is lacking in terms of learning it from scratch.
So pls feel free to explain me a bit it you may spare some time.

Cheers :)

PeterR
Posts: 621
Joined: Mon Jun 04, 2018 2:47 pm

Re: Sending passthrough command // problems in structural understanding

Postby PeterR » Fri Nov 13, 2020 5:02 pm

Embedded is hard and so even more fun than Java! Not sure why embedded gets paid less though*. BT is quite a hard starting point IMHO. Its a big fat stack with quite a few things to learn.

Anyway - I am not an expert on core dumps. I can tell you though that typically core dumps which (as yours) do not show a procedure call chain are the result of corrupt stack or use of an uninitialised pointer. That works for me enough not to research the core dump. You say that you cut some code. Step back and confirm if the ESP baseline works first. Next remove code in stages.
Another simple approach is max all your stacks. Don't hold back. You can reduce latter when you know where the stress points are.
There are also some memory checking options under menuconfig. make menuconfig and poke around.

* EDIT: Actually I am. The Java programmer is typically closer to the money! Also our work is more fun.
& I also believe that IDF CAN should be fixed.

prokkuez
Posts: 3
Joined: Thu Nov 12, 2020 7:33 pm

Re: Sending passthrough command // problems in structural understanding

Postby prokkuez » Fri Nov 13, 2020 7:39 pm

PeterR wrote:
Fri Nov 13, 2020 5:02 pm
. Step back and confirm if the ESP baseline works first. Next remove code in stages.
Another simple approach is max all your stacks. Don't hold back. You can reduce latter when you know where the stress points are.
There are also some memory checking options under menuconfig. make menuconfig and poke around.
Hi there and thanks for the reply!

Well, the baseline itself is what I'm already lacking to understand.
I just can't find a decent description of esps architecture and representation of the code which has to be called when.
I found some pdf of the esps bluetooth architecture but Im quiet confused about the codeside.

Sry, here is the decoded stack, should have posted it right away:

Code: Select all

PC: 0x4013f382: i2s_write at C:\Users\Marcel\.platformio\packages\framework-espidf\components\driver\i2s.c line 1003
EXCVADDR: 0x00000018

Decoding stack results
0x4013f37f: i2s_write at C:\Users\xxx\.platformio\packages\framework-espidf\components\driver\i2s.c line 1003
0x400d2d4d: bt_i2s_task_handler at main\bt_app_core.c line 128
0x4008e5ad: vPortTaskWrapper at C:\Users\xxx\.platformio\packages\framework-espidf\components\freertos\port.c line 143
When I understood you right, I may try out the single functions one after one, adding up?
Sry Im not noative speaker therefore things may take a little more time for me to understand as well ;)
So if you feel like sharing any info I'd be interested and thankful!

PS:
My first apprenticeship was electrician for robots, so yes, I totally agree, all the mcu stuff is way more interesting, so lately, lik for two years I got into arduino and esp and now digging deeper :)

Tho I like java a lot for what it is, but the funz for me is to grasp how things REALLY work and therefore I love digging around the esp!

prokkuez
Posts: 3
Joined: Thu Nov 12, 2020 7:33 pm

Re: Sending passthrough command // problems in structural understanding

Postby prokkuez » Wed Nov 18, 2020 8:23 am

Just a quick addition:

After researching:
In esp it is NOT possible to use avrcp without a2dp.

So question is wether to use another board/module/chip for this or if there may be a possibility to not make it appear as a remote speaker.

Who is online

Users browsing this forum: No registered users and 130 guests