Использование виджета в стиле Qt делает мой USB / BLE-сбор данных постоянно быстрее ... почему? - PullRequest
0 голосов
/ 28 февраля 2019

Я использую плату скандинавского разработчика (PCA10040, nRF52832) с модифицированной прошивкой "Nordic_HRM", отправляющую пакеты по 20 байтов при 100 Гц по Bluetooth с низким энергопотреблением.

Я использую пример Nordic heart_rate_collector для получения данныхна компьютере под управлением Windows 10 с использованием USB-ключа Nordic USB BLE (PCA10031).Я протестировал обе версии 2.2.1 и 4.0.0 pc-ble-драйвера.Я изменил пример кода, чтобы сообщать частоту данных за последнюю секунду (первоначально она сообщает среднюю частоту данных за весь сеанс)

То, что я испытываю, очень странно:

  • Пример heart_rate_collector (консольное приложение win32) извлекает данные только при частоте 65 Гц.Похоже, что 35% данных теряются.Первоначально я полагал, что частота дискретизации 100 Гц была слишком высокой для соединения BLE ... enter image description here

  • Но забавно то, что если я добавлю очень простой графический интерфейс(QApplication и QDialog), затем программа в конечном итоге сможет получать данные с частотой 100 Гц ... но это зависит от активности мыши!Когда мышь находится над кнопкой, частота переходит на 100 Гц, когда нет, она падает до 65 Гц.Я знаю, в это трудно поверить, поэтому я снял видео ;-) enter image description here

  • И, что еще более забавно, если я удалю плагин стиля Qt qwindowsvistastyle.dll из моей установочной папки, то графический интерфейс ужасен, и тогда вы не сможете получить 100 Гц больше, вы застряли на 65 Гц.Я знаю, в это тоже трудно поверить, поэтому я сделал еще одно видео ;-) enter image description here

Когда вы используете стиль отображения Vista, когда мышь находится надкнопка, вы видите, Qt делает некоторые перерисовки, чтобы нарисовать фокус кнопки.И мне интересно, если это, вероятно, сообщает Windows, что процесс требует большего внимания и, наконец, заставляет ОС уделять больше внимания этому процессу, а затем теряет меньше данных?

Обратите внимание, что я пытался изменить приоритет процесса«Высокий» в диспетчере задач, но это, по-видимому, не имеет никакого эффекта.

Вопрос:

  • Кто-нибудь может объяснить, что здесь происходит?
  • Iне обязательно беспокоиться о том, чтобы консольное приложение win32 могло получать данные с частотой 100 Гц.Но я действительно обеспокоен тем, чтобы мое приложение Qt могло это делать, не требуя, чтобы пользователь постоянно перемещал свою мышь вокруг кнопки ... есть ли что-нибудь, что можно сделать (на уровне QApplication, уровне Windows, Nordic?)уровень драйвера ....)?

Код MCVE:

mydialog.h:

#pragma once

#include <QApplication>
#include <QDialog>
#include <QPushButton>
#include <QVBoxLayout>
#include <QShowEvent>
#include <QLabel>

class MyDialog : public QDialog
{
    Q_OBJECT

public:
    MyDialog();
    ~MyDialog();

    void showEvent( QShowEvent* event ) override;

public slots:
    void toggle();
    void notify( uint32_t count, float freq );

private:
    int run();
    uint8_t cccd_value;
    uint32_t close();

    QLabel* label;
};

main.cpp (модификация main.c) Nordic, полностью доступна в pastbin

...

static MyDialog* notify_dialog = NULL;
static void on_hvx(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    clock_t now = clock();

    if (!m_hvx_start) {
        m_hvx_start = now;
    }

    m_hvx_count++;

    float seconds = (float)(now - m_hvx_start) / CLOCKS_PER_SEC;

    if ( seconds >= 1 )
    {
        float pkt_per_sec = m_hvx_count / seconds;

        if ( notify_dialog )
            notify_dialog->notify( m_hvx_count, pkt_per_sec );

        printf("pkts: %06d, pkt/s: %f\n", m_hvx_count, pkt_per_sec);

        fflush(stdout);

        // reset counters
        m_hvx_start = clock();
        m_hvx_count = 0;
    }
}

...

MyDialog::MyDialog() 
{
    setLayout( new QVBoxLayout() );
    QPushButton* button = new QPushButton( "Toggle", this );
    connect( button, SIGNAL(clicked()), this, SLOT(toggle()) );

    layout()->addWidget( button );
    layout()->addWidget( label = new QLabel( this ) );

    notify_dialog = this;
}

MyDialog::~MyDialog()
{
    notify_dialog = NULL;
    close();
}

void MyDialog::showEvent( QShowEvent* event )
{
    QDialog::showEvent( event );
    run();
}

int MyDialog::run()
{
    uint32_t error_code;
    char* serial_port;
    physical_layer_t * phy;
    data_link_layer_t * data_link_layer;
    transport_layer_t * transport_layer;

        cccd_value = 0;

    serial_port = UART_PORT_NAME;

    printf("Serial port used: %s\n", serial_port); fflush(stdout);

    phy = sd_rpc_physical_layer_create_uart(serial_port, 1000000, SD_RPC_FLOW_CONTROL_NONE, SD_RPC_PARITY_NONE);

    data_link_layer = sd_rpc_data_link_layer_create_bt_three_wire(phy, 100);

    transport_layer = sd_rpc_transport_layer_create(data_link_layer, 100);

    m_adapter = sd_rpc_adapter_create(transport_layer);

    //sd_rpc_log_handler_severity_filter_set(adapter, SD_RPC_LOG_INFO);

    error_code = sd_rpc_open(m_adapter, status_handler, ble_evt_dispatch, log_handler);

    if (error_code != NRF_SUCCESS)
    {
        printf("Failed to open the nRF5 BLE Driver. Error code: 0x%02X\n", error_code);
        fflush(stdout);
        return error_code;
    }

    error_code = ble_stack_init();

    if (error_code != NRF_SUCCESS)
    {
        return error_code;
    }

    error_code = ble_options_set();

    if (error_code != NRF_SUCCESS)
    {
        return error_code;
    }

    scan_start();
}

void MyDialog::toggle()
{
    cccd_value ^= CCCD_NOTIFY;
    hrm_cccd_set(cccd_value);
}

uint32_t MyDialog::close()
{
    uint32_t error_code = sd_rpc_close(m_adapter);

    if (error_code != NRF_SUCCESS)
    {
        printf("Failed to close the nRF5 BLE Driver. Error code: 0x%02X\n", error_code);
        fflush(stdout);
        return error_code;
    }

    printf("Closed\n"); fflush(stdout);

    return error_code;
}

void MyDialog::notify( uint32_t count, float freq )
{
    std::stringstream str;
    str << "During the last second, received " << count << " packets, frequency is " << freq << "Hz";
    label->setText( str.str().c_str() );
}

int main(int argc, char *argv[])
{
    QApplication app( argc, argv );
    MyDialog frame;
    frame.show();
    return app.exec();
}

Правки

  1. Я понимаю, что проблема не воспроизводится на 100%,Иногда консольное программное обеспечение также может получать данные на частоте 100 Гц на моем компьютере, иногда нет.Я чувствую, что после того, как ПК был включен в течение некоторого времени, и я провел много тестов, он начинает работать на частоте 100 Гц.Когда я выключаю компьютер и снова включаю его, он всегда возвращается к скорости передачи данных 65 Гц ....

  2. Я добавил дополнительный контроль скорости передачи данных в самом коде pc-ble-driver и перекомпилировалЭто.Один в потоке чтения (SerializationTransport::readHandler), другой в коде, получающий данные от USB-соединения (UartBoost::readHandler), для которого я отслеживаю количество пакетов и количество полученных байтов.Вот что я наблюдаю:

Когда данные принимаются на частоте 100 Гц, я вижу:

UartBoost::readHandler: 000213, pkt/s: 212.362900
UartBoost::readHandler: 004315, bytes/s: 4302.093750
SerializationTransport::readHandler: 000103, pkt/s: 102.385681
pkts: 000102, pkt/s: 102.000000

Когда данные принимаются на частоте 65 Гц, я вижу:

UartBoost::readHandler: 000061, pkt/s: 60.157787
UartBoost::readHandler: 002570, bytes/s: 2534.516602
SerializationTransport::readHandler: 000061, pkt/s: 60.157787
pkts: 000061, pkt/s: 60.157787

Удивительно, что UartBoost::readHandler скорость передачи данных (байт / с) снижена с 4302 до 2534 (такое же отношение уменьшено на ~ 40%, как и конечная частота дискретизации), тогда как количество пакетов в секунду (pkt /s) гораздо больше снижается на 71% (с 212 до 60).Ключ BLE отправляет на 35% меньше данных, но использует на 71% меньше пакетов ... Я не знаю, что делать.

Добавлен этот фрагмент кода в UartBoost :: readHandler:

Добавлен этот код:

std::cout << std::hex; 
for ( size_t pos = 0; pos != bytesTransferred; ++pos ) 
    std::cout << (unsigned) readBufferData[pos] << " "; 
std::cout << std::endl;

Как видите, пакеты разбиты.На частоте 65 Гц каждый пакет является полным уведомлением.На частоте 100 Гц пакеты разделяются, что означает, что для получения полного уведомления необходимо много чтений.Это объясняет, почему на частоте 65 Гц мы получаем немного меньше байтов, но гораздо меньше пакетов.

Если я использую notpad для очистки пакетов 100 Гц, чтобы сгруппировать их c0 ... c0, я получаю: https://pastebin.com/FyFwR0yJ

очень похоже на ситуацию, когда у нас 65 Гц, но с ~ 35 линиями.Это ожидаемо.

Похоже, что Windows или драйвер в некоторых точках предпочитает отправлять меньше данных, но более чистым способом (без разделения пакетов) .... опять же, я не понимаю, почему.

...