Я слежу за этим вопросом здесь и пытаюсь вернуть содержимое DataLogger, на который я подписан для Meas / HR.
Я делаю это, используя Sensor Simulator , работающий на моем Windows 10 P C.
. Я настраиваю DataLogger и запрашиваю "Measure / HR" следующим образом:
WB_RES::DataEntry entry;
entry.path = "/Meas/HR";
WB_RES::DataLoggerConfig logConfig;
logConfig.dataEntries.dataEntry = {entry};
whiteboard::Result result = asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_CONFIG(), AsyncRequestOptions::Empty, logConfig);
if (result == whiteboard::HTTP_CODE_OK) {
this->asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_STATE(), AsyncRequestOptions::Empty,
WB_RES::DataLoggerStateValues::Type::DATALOGGER_LOGGING);
} else {
DEBUGLOG("asyncPut::datalogger config threw error: %u", result);
}
И я получаю, как и ожидалось, код результата 200, а затем объект конфигурации регистратора данных с 1 записью в функции onPutResult (...).
Затем, используя функцию onTimer (только для целей тестирования), я пытаюсь чтобы получить записи журнала, используя следующий код:
this->asyncGet(WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES(), AsyncRequestOptions::Empty);
Он запускается и входит в
onGetResult(wb::RequestId requestId, wb::ResourceId resourceId, wb::Result resultCode,
const wb::Value &result)
функцию обратного вызова, где я получаю resultCode HTTP_CODE_OK (200), но значение результата всегда возвращается как:
result = {mDataTypeId=13313 mSenderDataType=1 '\x1' mReceiverDataType=1 '\x1' ..., mpData = 0x0456f8ac}
Почему он всегда возвращается как MEM_LOGBOOK_ISFULL_LID = 13313 и никогда не MEM_LOGBOOK_ENTRIES_LID = 13312?
Это потому, что я бегу, это режим симулятора? Я также выполнил эту команду на случай, если необходимо заполнить DataLogger:
wbcmd.exe --port TCP127.0.0.1:7044 --path Meas/HR --op SUBSCRIBE
Но она все равно не работает ....
У меня нет JIG, поэтому мне нужно чтобы убедиться, что это работает на симуляторе P C, следующим шагом для меня будет использование датчика movesense для регистрации результатов за несколько дней ДО того, как я отправлю результаты обратно с помощью GATT. Я стараюсь не использовать доску и мобильное программное обеспечение android.
Есть ли какой-нибудь способ, которым я могу правильно проверить это с помощью симулятора, потому что это будет чертовски неприятно, даже пытаться сделать это любым другим способом? путь. Нужно ли вручную вводить данные в DataLogger?
ПОМОГИТЕ! Я потратил так много времени на это, и это сводит меня с ума ...
Спасибо! Хели c
@ Мортен: Вот минимальный рабочий образец. Большое спасибо!:
. cpp файл
#include "movesense.h"
#include "DataLoggerClient.h"
#include "common/core/debug.h"
#include "ui_ind/resources.h"
#include "mem_datalogger/resources.h"
#include "mem_logbook/resources.h"
#include "whiteboard/Value.h"
#include <string>
const size_t BLINK_PERIOD_MS = 3500;
const char *const DataLoggerClient::LAUNCHABLE_NAME = "DataLogger";
DataLoggerClient::DataLoggerClient()
: ResourceClient(WBDEBUG_NAME(__FUNCTION__), WB_EXEC_CTX_APPLICATION),
LaunchableModule(LAUNCHABLE_NAME, WB_EXEC_CTX_APPLICATION),
mTimer(wb::ID_INVALID_TIMER) {
}
DataLoggerClient::~DataLoggerClient() {
}
bool DataLoggerClient::initModule() {
mModuleState = WB_RES::ModuleStateValues::INITIALIZED;
return true;
}
void DataLoggerClient::deinitModule() {
mModuleState = WB_RES::ModuleStateValues::UNINITIALIZED;
}
bool DataLoggerClient::startModule() {
mModuleState = WB_RES::ModuleStateValues::STARTED;
// Configure the DataLogger to start recording the data on startup
startDataLogger();
mTimer = startTimer(BLINK_PERIOD_MS, true); // Start LED timer. true = trigger repeatedly
return true;
}
// Use the Datalogger to store movesense device data (in this case the HeartRate information)
// Look here for more details on DataLogger and Logbook: http://www.movesense.com/docs/mobile/android/datalogger_logbook/
void DataLoggerClient::startDataLogger() {
// We want to record the heart rate measurement - using the API
WB_RES::DataEntry entry;
entry.path = "/Meas/HR";
//DataLoggerConfig contains the current configuration of the logger (what data to log)
WB_RES::DataLoggerConfig logConfig;
logConfig.dataEntries.dataEntry = whiteboard::MakeArray<WB_RES::DataEntry>(&entry, 1);
whiteboard::Result result = this->asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_CONFIG(), AsyncRequestOptions::Empty,
logConfig);
if (result == whiteboard::HTTP_CODE_OK) {
//To start logging, PUT value DATALOGGER_LOGGING (=3) to Mem/DataLogger/State resource
this->asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_STATE(), AsyncRequestOptions::Empty,
WB_RES::DataLoggerStateValues::Type::DATALOGGER_LOGGING);
} else {
DEBUGLOG("asyncPut::datalogger config threw error: %u", result);
}
}
void DataLoggerClient::stopModule() {
stopTimer(mTimer); // Stop LED timer
mTimer = wb::ID_INVALID_TIMER;
// stop the DataLogger as we are shutting down the service
stopDataLogger();
mModuleState = WB_RES::ModuleStateValues::STOPPED;
}
void DataLoggerClient::stopDataLogger() {
//To stop logging, PUT value DATALOGGER_READY (=2) to Mem/DataLogger/State resource
asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_STATE(), AsyncRequestOptions::Empty,
WB_RES::DataLoggerStateValues::Type::DATALOGGER_READY);
}
void DataLoggerClient::onTimer(wb::TimerId) {
// todo: if only one timer started, no need to check the ID
const WB_RES::VisualIndType type = WB_RES::VisualIndTypeValues::SHORT_VISUAL_INDICATION; // defined in ui/ind.yaml
asyncPut(WB_RES::LOCAL::UI_IND_VISUAL(), AsyncRequestOptions::Empty, type); // PUT request to trigger led blink
// ignore the immediate and asynchronous Results as this is not critical
//Fetch all entries / logs from the device
getLogbookEntries();
}
// Use the Logbook to retrieve all the data we have stored using the Datalogger
// Look here for more details on DataLogger and Logbook: http://www.movesense.com/docs/mobile/android/datalogger_logbook/
void DataLoggerClient::getLogbookEntries() {
//Get all the entries stored by data logger using the logbook, Use Empty because (or null) so the list of the items starts from beginning
whiteboard::Result result = this->asyncGet(WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES(), AsyncRequestOptions::Empty);
DEBUGLOG("asyncGet::logbook get entries result: %u", result);
}
// Use the Logbook to retrieve 1 set of entries we have stored using the Datalogger
void DataLoggerClient::getLogbookEntry() {
//Get one set of entries stored by data logger using the logbook,
//this is not working...
// const uint32 p1 = 1;
// const uint32 p2 = 0;
// const whiteboard::ParameterList parameterList;
// parameterList[0].convertTo<p1>();
// parameterList[1].convertTo<p2>();
// whiteboard::Result result = this->asyncGet(WB_RES::LOCAL::MEM_LOGBOOK_BYID_LOGID_DATA(), AsyncRequestOptions::Empty, parameterList);
// DEBUGLOG("asyncGet::logbook get entry result: %u", result);
}
void DataLoggerClient::deleteLogbookEntries() {
//Delete all the entries stored by data logger using the logbook
whiteboard::Result result = this->asyncDelete(WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES(), AsyncRequestOptions::Empty);
DEBUGLOG("asyncDelete::logbook delete all entries result: %u", result);
}
void
DataLoggerClient::onNotify(wb::ResourceId resourceId, const wb::Value &value, const wb::ParameterList ¶meters) {
switch (resourceId.localResourceId) {
case WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES::LID: {
DEBUGLOG("onSubscribeResult success resource: %u, value: %u, parameter list: %u",
resourceId.localResourceId, &value, ¶meters);
break;
}
default: {
//do nothing
}
}
}
void DataLoggerClient::onSubscribeResult(wb::RequestId requestId, wb::ResourceId resourceId, wb::Result resultCode,
const wb::Value &result) {
// If error result, just log and do nothing
if (wb::IsErrorResult(resultCode)) {
DEBUGLOG("onSubscribeResult error: resource: %u, resultCode: %u", resourceId.localResourceId, resultCode);
return;
}
switch (resourceId.localResourceId) {
case WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES::LID:
case WB_RES::LOCAL::MEM_DATALOGGER_CONFIG::LID: {
DEBUGLOG("onSubscribeResult success requestId: %u, resource: %u, resultCode: %u, result addr: %u",
requestId, resourceId.localResourceId, resultCode, &result);
break;
}
default: {
//do nothing
}
}
}
void DataLoggerClient::onGetResult(wb::RequestId requestId, wb::ResourceId resourceId, wb::Result resultCode,
const wb::Value &result) {
if (wb::IsErrorResult(resultCode)) {
DEBUGLOG("onGetResult failed! resource: %u, result: %u", resourceId.localResourceId, resultCode);
return;
}
switch (resourceId.localResourceId) {
case WB_RES::LOCAL::MEM_DATALOGGER_CONFIG::LID: {
DEBUGLOG("onGetResult success requestId: %u, resource: %u, resultCode: %u, result addr: %u", requestId,
resourceId.localResourceId, resultCode, &result);
break;
}
case WB_RES::LOCAL::MEM_LOGBOOK_ENTRIES::LID: {
DEBUGLOG("onGetResult success requestId: %u, resource: %u, resultCode: %u, result addr: %u", requestId,
resourceId.localResourceId, resultCode, &result);
const WB_RES::LogEntries &logEntries = result.convertTo<const WB_RES::LogEntries &>();
// DEBUGLOG("HRValue: %f", hrValue.average);
DEBUGLOG("LE: %u", logEntries.elements.size());
break;
}
default: {
DEBUGLOG("resource id: %u", resourceId.localResourceId);
//do nothing
}
}
}
void DataLoggerClient::onPutResult(wb::RequestId requestId,
wb::ResourceId resourceId,
wb::Result resultCode,
const wb::Value &result) {
if (wb::IsErrorResult(resultCode)) {
DEBUGLOG("onPutResult failed! resource: %u, result: %u", resourceId.localResourceId, resultCode);
return;
}
switch (resourceId.localResourceId) {
case WB_RES::LOCAL::MEM_DATALOGGER_CONFIG::LID: {
const WB_RES::DataLoggerConfig &dataLoggerConfig = result.convertTo<const WB_RES::DataLoggerConfig &>();
DEBUGLOG("LE: %u", dataLoggerConfig.dataEntries.dataEntry.size());
}
case WB_RES::LOCAL::MEM_DATALOGGER_STATE::LID:
case WB_RES::LOCAL::UI_IND_VISUAL::LID: {
DEBUGLOG("onPutResult success requestId: %u, resource: %u, resultCode: %u, result addr: %u", requestId,
resourceId.localResourceId, resultCode, &result);
break;
}
default: {
//do nothing
}
}
}
void DataLoggerClient::onDeleteResult(whiteboard::RequestId requestId, whiteboard::ResourceId resourceId,
whiteboard::Result resultCode, const whiteboard::Value &rResultData) {
if (wb::IsErrorResult(resultCode)) {
DEBUGLOG("onPutResult failed! resource: %u, result: %u", resourceId.localResourceId, resultCode);
return;
}
}
и файл .h:
#pragma once
#include <whiteboard/LaunchableModule.h>
#include <whiteboard/ResourceClient.h>
class DataLoggerClient FINAL : private wb::ResourceClient, public wb::LaunchableModule {
public:
/** Name of this class. Used in StartupProvider list. */
static const char *const LAUNCHABLE_NAME;
DataLoggerClient();
~DataLoggerClient();
private:
/** @see whiteboard::ILaunchableModule::initModule */
virtual bool initModule() OVERRIDE;
/** @see whiteboard::ILaunchableModule::deinitModule */
virtual void deinitModule() OVERRIDE;
/** @see whiteboard::ILaunchableModule::startModule */
virtual bool startModule() OVERRIDE;
/** @see whiteboard::ILaunchableModule::stopModule */
virtual void stopModule() OVERRIDE;
protected:
/** @see whiteboard::ResourceClient::onTimer */
virtual void onTimer(wb::TimerId timerId) OVERRIDE;
/** @see whiteboard::ResourceClient::onGetResult */
virtual void onGetResult(wb::RequestId requestId,
wb::ResourceId resourceId,
wb::Result resultCode,
const wb::Value &result) OVERRIDE;
/** @see whiteboard::ResourceClient::onPutResult */
virtual void onPutResult(wb::RequestId requestId,
wb::ResourceId resourceId,
wb::Result resultCode,
const wb::Value &result) OVERRIDE;
/** @see whiteboard::ResourceClient::onSubscribeResult */
virtual void onSubscribeResult(wb::RequestId requestId,
wb::ResourceId resourceId,
wb::Result resultCode,
const wb::Value &result) OVERRIDE;
/** @see whiteboard::ResourceClient::onNotify */
virtual void onNotify(wb::ResourceId resourceId,
const wb::Value &value,
const wb::ParameterList ¶meters) OVERRIDE;
private:
void startDataLogger();
void getLogbookEntries();
wb::TimerId mTimer;
void stopDataLogger();
void deleteLogbookEntries();
void onDeleteResult(whiteboard::RequestId requestId, whiteboard::ResourceId resourceId, whiteboard::Result resultCode,
const whiteboard::Value &rResultData) override;
void getLogbookEntry();
};
и файл приложения. cpp:
#include "DataLoggerClient.h"
#include "movesense.h"
MOVESENSE_APPLICATION_STACKSIZE(1024)
MOVESENSE_PROVIDERS_BEGIN(1)
MOVESENSE_PROVIDER_DEF(DataLoggerClient)
MOVESENSE_PROVIDERS_END(1)
MOVESENSE_FEATURES_BEGIN()
// Explicitly enable or disable Movesense framework core modules.
// List of modules and their default state is found in documentation
OPTIONAL_CORE_MODULE(DataLogger, true)
OPTIONAL_CORE_MODULE(Logbook, true)
OPTIONAL_CORE_MODULE(LedService, true)
OPTIONAL_CORE_MODULE(IndicationService, true)
OPTIONAL_CORE_MODULE(BleService, true)
OPTIONAL_CORE_MODULE(EepromService, true)
OPTIONAL_CORE_MODULE(BypassService, false)
OPTIONAL_CORE_MODULE(SystemMemoryService, true)
OPTIONAL_CORE_MODULE(DebugService, true)
OPTIONAL_CORE_MODULE(BleStandardHRS, false)
OPTIONAL_CORE_MODULE(BleNordicUART, false)
OPTIONAL_CORE_MODULE(CustomGattService, false)
// NOTE: It is inadvisable to enable both Logbook/DataLogger and EepromService without
// explicit definition of Logbook memory area (see LOGBOOK_MEMORY_AREA macro in movesense.h and eeprom_logbook_app).
// Default setting is for Logbook to use the whole EEPROM memory area.
// NOTE: If building a simulator build, these macros are obligatory!
DEBUGSERVICE_BUFFER_SIZE(6, 120); // 6 lines, 120 characters total
DEBUG_EEPROM_MEMORY_AREA(true, 0, 16384)
// Rest of the EEPROM is for Logbook
LOGBOOK_MEMORY_AREA(16384, (384 * 1024)-16384);
APPINFO_NAME("DataLogger");
APPINFO_VERSION("1.1.0");
APPINFO_COMPANY("Movesense");
// NOTE: SERIAL_COMMUNICATION macro has been DEPRECATED
BLE_COMMUNICATION(true)
MOVESENSE_FEATURES_END()