Verbatim copy from the SDK[1]'s sample/cceleromater_app directory [1] git@bitbucket.org:suunto/movesense-device-lib.gitmaster
parent
5ae9e4ff61
commit
db9dcbed36
@ -0,0 +1,252 @@
|
||||
#include "AccelerometerSampleService.h"
|
||||
#include "app-resources/resources.h"
|
||||
#include "common/core/debug.h"
|
||||
#include "meas_acc/resources.h"
|
||||
#include "whiteboard/builtinTypes/UnknownStructure.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
const char* const AccelerometerSampleService::LAUNCHABLE_NAME = "SampleA";
|
||||
#define SAMPLE_RATE 13
|
||||
static const whiteboard::ExecutionContextId sExecutionContextId =
|
||||
WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA::EXECUTION_CONTEXT;
|
||||
|
||||
static const whiteboard::LocalResourceId sProviderResources[] = {
|
||||
WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA::LID,
|
||||
};
|
||||
|
||||
AccelerometerSampleService::AccelerometerSampleService()
|
||||
: ResourceClient(WBDEBUG_NAME(__FUNCTION__), sExecutionContextId),
|
||||
ResourceProvider(WBDEBUG_NAME(__FUNCTION__), sExecutionContextId),
|
||||
LaunchableModule(LAUNCHABLE_NAME, sExecutionContextId),
|
||||
isRunning(false)
|
||||
{
|
||||
}
|
||||
|
||||
AccelerometerSampleService::~AccelerometerSampleService()
|
||||
{
|
||||
}
|
||||
|
||||
bool AccelerometerSampleService::initModule()
|
||||
{
|
||||
if (registerProviderResources(sProviderResources) != whiteboard::HTTP_CODE_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mModuleState = WB_RES::ModuleStateValues::INITIALIZED;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::deinitModule()
|
||||
{
|
||||
unregisterProviderResources(sProviderResources);
|
||||
mModuleState = WB_RES::ModuleStateValues::UNINITIALIZED;
|
||||
}
|
||||
|
||||
/** @see whiteboard::ILaunchableModule::startModule */
|
||||
bool AccelerometerSampleService::startModule()
|
||||
{
|
||||
mModuleState = WB_RES::ModuleStateValues::STARTED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onUnsubscribeResult(whiteboard::RequestId requestId,
|
||||
whiteboard::ResourceId resourceId,
|
||||
whiteboard::Result resultCode,
|
||||
const whiteboard::Value& rResultData)
|
||||
{
|
||||
DEBUGLOG("AccelerometerSampleService::onUnsubscribeResult() called.");
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onSubscribeResult(whiteboard::RequestId requestId,
|
||||
whiteboard::ResourceId resourceId,
|
||||
whiteboard::Result resultCode,
|
||||
const whiteboard::Value& rResultData)
|
||||
{
|
||||
DEBUGLOG("AccelerometerSampleService::onSubscribeResult() called. resourceId: %u, result: %d", resourceId.localResourceId, (uint32_t)resultCode);
|
||||
|
||||
whiteboard::Request relatedIncomingRequest;
|
||||
bool relatedRequestFound = mOngoingRequests.get(requestId, relatedIncomingRequest);
|
||||
|
||||
if (relatedRequestFound)
|
||||
{
|
||||
returnResult(relatedIncomingRequest, wb::HTTP_CODE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
whiteboard::Result AccelerometerSampleService::startRunning(whiteboard::RequestId& remoteRequestId)
|
||||
{
|
||||
if (isRunning)
|
||||
{
|
||||
return whiteboard::HTTP_CODE_OK;
|
||||
}
|
||||
|
||||
DEBUGLOG("AccelerometerSampleService::startRunning()");
|
||||
|
||||
// Reset max acceleration members
|
||||
mMaxAccelerationSq = FLT_MIN;
|
||||
mSamplesIncluded = 0;
|
||||
|
||||
wb::Result result = getResource("Meas/Acc/13", mMeasAccResourceId);
|
||||
if (!wb::RETURN_OKC(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = asyncSubscribe(mMeasAccResourceId, AsyncRequestOptions(&remoteRequestId, 0, true));
|
||||
|
||||
if (!wb::RETURN_OKC(result))
|
||||
{
|
||||
DEBUGLOG("asyncSubscribe threw error: %u", result);
|
||||
return whiteboard::HTTP_CODE_BAD_REQUEST;
|
||||
}
|
||||
isRunning = true;
|
||||
|
||||
return whiteboard::HTTP_CODE_OK;
|
||||
}
|
||||
|
||||
whiteboard::Result AccelerometerSampleService::stopRunning()
|
||||
{
|
||||
if (!isRunning)
|
||||
{
|
||||
return whiteboard::HTTP_CODE_OK;
|
||||
}
|
||||
|
||||
if (isResourceSubscribed(WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA::ID) == wb::HTTP_CODE_OK)
|
||||
{
|
||||
DEBUGLOG("AccelerometerSampleService::stopRunning() skipping. Subscribers still exist.");
|
||||
return whiteboard::HTTP_CODE_OK;
|
||||
}
|
||||
|
||||
DEBUGLOG("AccelerometerSampleService::stopRunning()");
|
||||
|
||||
// Unsubscribe the LinearAcceleration resource, when unsubscribe is done, we get callback
|
||||
wb::Result result = asyncUnsubscribe(mMeasAccResourceId, NULL);
|
||||
if (!wb::RETURN_OKC(result))
|
||||
{
|
||||
DEBUGLOG("asyncUnsubscribe threw error: %u", result);
|
||||
}
|
||||
isRunning = false;
|
||||
releaseResource(mMeasAccResourceId);
|
||||
|
||||
return whiteboard::HTTP_CODE_OK;
|
||||
}
|
||||
|
||||
// This callback is called when the resource we have subscribed notifies us
|
||||
void AccelerometerSampleService::onNotify(whiteboard::ResourceId resourceId, const whiteboard::Value& value,
|
||||
const whiteboard::ParameterList& parameters)
|
||||
{
|
||||
DEBUGLOG("onNotify() called.");
|
||||
|
||||
// Confirm that it is the correct resource
|
||||
switch (resourceId.localResourceId)
|
||||
{
|
||||
case WB_RES::LOCAL::MEAS_ACC_SAMPLERATE::LID:
|
||||
{
|
||||
const WB_RES::AccData& linearAccelerationValue =
|
||||
value.convertTo<const WB_RES::AccData&>();
|
||||
|
||||
if (linearAccelerationValue.arrayAcc.size() <= 0)
|
||||
{
|
||||
// No value, do nothing...
|
||||
return;
|
||||
}
|
||||
|
||||
const whiteboard::Array<whiteboard::FloatVector3D>& arrayData = linearAccelerationValue.arrayAcc;
|
||||
|
||||
uint32_t relativeTime = linearAccelerationValue.timestamp;
|
||||
|
||||
for (size_t i = 0; i < arrayData.size(); i++)
|
||||
{
|
||||
mSamplesIncluded++;
|
||||
|
||||
whiteboard::FloatVector3D accValue = arrayData[i];
|
||||
float accelerationSq = accValue.mX * accValue.mX +
|
||||
accValue.mY * accValue.mY +
|
||||
accValue.mZ * accValue.mZ;
|
||||
|
||||
if (mMaxAccelerationSq < accelerationSq)
|
||||
mMaxAccelerationSq = accelerationSq;
|
||||
}
|
||||
|
||||
// 13Hz 5sec
|
||||
if (mSamplesIncluded > 5 * 13)
|
||||
{
|
||||
// Reset counter and notify our subscribers
|
||||
WB_RES::SampleDataValue sampleDataValue;
|
||||
sampleDataValue.relativeTime = relativeTime;
|
||||
sampleDataValue.value = sqrtf(mMaxAccelerationSq);
|
||||
|
||||
// Reset members
|
||||
mSamplesIncluded = 0;
|
||||
mMaxAccelerationSq = FLT_MIN;
|
||||
|
||||
// and update our WB resource. This causes notification to be fired to our subscribers
|
||||
updateResource(WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA(),
|
||||
ResponseOptions::Empty, sampleDataValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onSubscribe(const whiteboard::Request& request,
|
||||
const whiteboard::ParameterList& parameters)
|
||||
{
|
||||
switch (request.getResourceConstId())
|
||||
{
|
||||
case WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA::ID:
|
||||
{
|
||||
// Someone subscribed to our service. Start collecting data and notifying when our service changes state (every 10 seconds)
|
||||
whiteboard::RequestId remoteRequestId;
|
||||
whiteboard::Result result = startRunning(remoteRequestId);
|
||||
|
||||
if (isRunning)
|
||||
{
|
||||
return returnResult(request, whiteboard::HTTP_CODE_OK);
|
||||
}
|
||||
|
||||
if (!whiteboard::RETURN_OK(result))
|
||||
{
|
||||
return returnResult(request, result);
|
||||
}
|
||||
bool queueResult = mOngoingRequests.put(remoteRequestId, request);
|
||||
(void)queueResult;
|
||||
WB_ASSERT(queueResult);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0); // Should not happen
|
||||
}
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onUnsubscribe(const whiteboard::Request& request,
|
||||
const whiteboard::ParameterList& parameters)
|
||||
{
|
||||
switch (request.getResourceConstId())
|
||||
{
|
||||
case WB_RES::LOCAL::SAMPLE_ACCELEROMETER_DATA::ID:
|
||||
stopRunning();
|
||||
returnResult(request, wb::HTTP_CODE_OK);
|
||||
break;
|
||||
|
||||
default:
|
||||
returnResult(request, wb::HTTP_CODE_BAD_REQUEST);
|
||||
ASSERT(0); // Should not happen
|
||||
}
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onRemoteWhiteboardDisconnected(whiteboard::WhiteboardId whiteboardId)
|
||||
{
|
||||
DEBUGLOG("AccelerometerSampleService::onRemoteWhiteboardDisconnected()");
|
||||
stopRunning();
|
||||
}
|
||||
|
||||
void AccelerometerSampleService::onClientUnavailable(whiteboard::ClientId clientId)
|
||||
{
|
||||
DEBUGLOG("AccelerometerSampleService::onClientUnavailable()");
|
||||
stopRunning();
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include <whiteboard/LaunchableModule.h>
|
||||
#include <whiteboard/ResourceClient.h>
|
||||
#include <whiteboard/ResourceProvider.h>
|
||||
#include <whiteboard/containers/RequestMap.h>
|
||||
|
||||
#include "wb-resources/resources.h"
|
||||
|
||||
class AccelerometerSampleService FINAL : private whiteboard::ResourceClient,
|
||||
private whiteboard::ResourceProvider,
|
||||
public whiteboard::LaunchableModule
|
||||
|
||||
{
|
||||
public:
|
||||
/** Name of this class. Used in StartupProvider list. */
|
||||
static const char* const LAUNCHABLE_NAME;
|
||||
AccelerometerSampleService();
|
||||
~AccelerometerSampleService();
|
||||
|
||||
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 { mModuleState = WB_RES::ModuleStateValues::STOPPED; }
|
||||
|
||||
/**
|
||||
* Subscribe notification callback.
|
||||
*
|
||||
* @param request Request information
|
||||
* @param parameters List of parameters
|
||||
*/
|
||||
virtual void onSubscribe(const whiteboard::Request& request,
|
||||
const whiteboard::ParameterList& parameters) OVERRIDE;
|
||||
|
||||
/**
|
||||
* Unsubscribe notification callback.
|
||||
*
|
||||
* @param request Request information
|
||||
* @param parameters List of parameters
|
||||
*/
|
||||
virtual void onUnsubscribe(const whiteboard::Request& request,
|
||||
const whiteboard::ParameterList& parameters) OVERRIDE;
|
||||
|
||||
/**
|
||||
* Whiteboard disconnect notification handler.
|
||||
*
|
||||
* This can be used for example to cleanup possible subscription related information of clients from
|
||||
* the remote whiteboard.
|
||||
*
|
||||
* @param whiteboardId ID of the whiteboard that has been disconnected.
|
||||
*
|
||||
* @see whiteboard::ResourceProvider::onSubscribe
|
||||
* @see whiteboard::ResourceProvider::onUnsubscribe
|
||||
*/
|
||||
virtual void onRemoteWhiteboardDisconnected(whiteboard::WhiteboardId whiteboardId) OVERRIDE;
|
||||
|
||||
/**
|
||||
* Local client 'disconnect' notification handler.
|
||||
*
|
||||
* This can be used for example to cleanup possible subscription related information of the client.
|
||||
*
|
||||
* @see whiteboard::ResourceProvider::onSubscribe
|
||||
* @see whiteboard::ResourceProvider::onUnsubscribe
|
||||
*/
|
||||
virtual void onClientUnavailable(whiteboard::ClientId clientId) OVERRIDE;
|
||||
|
||||
/**
|
||||
* Callback for resource notifications.
|
||||
* Note that this function will not be called for notifications that are
|
||||
* of types WB_RESOURCE_NOTIFICATION_TYPE_INSERT or WB_RESOURCE_NOTIFICATION_TYPE_DELETE,
|
||||
* just for notifications that are of type WB_RESOURCE_NOTIFICATION_TYPE_UPDATE.
|
||||
*
|
||||
* @param resourceId Resource id associated with the update
|
||||
* @param rValue Current value of the resource
|
||||
*/
|
||||
virtual void onNotify(whiteboard::ResourceId resourceId, const whiteboard::Value& value,
|
||||
const whiteboard::ParameterList& parameters);
|
||||
|
||||
/**
|
||||
* Callback for asynchronous UNSUBSCRIBE requests
|
||||
*
|
||||
* @param requestId ID of the request
|
||||
* @param resourceId Successful request contains ID of the resource
|
||||
* @param resultCode Result code of the request
|
||||
* @param rResultData Successful result contains the request result
|
||||
*/
|
||||
virtual void onUnsubscribeResult(whiteboard::RequestId requestId,
|
||||
whiteboard::ResourceId resourceId,
|
||||
whiteboard::Result resultCode,
|
||||
const whiteboard::Value& rResultData);
|
||||
/**
|
||||
* Callback for asynchronous SUBSCRIBE requests
|
||||
*
|
||||
* @param requestId ID of the request
|
||||
* @param resourceId Successful request contains ID of the resource
|
||||
* @param resultCode Result code of the request
|
||||
* @param rResultData Successful result contains the request result
|
||||
*/
|
||||
virtual void onSubscribeResult(whiteboard::RequestId requestId,
|
||||
whiteboard::ResourceId resourceId,
|
||||
whiteboard::Result resultCode,
|
||||
const whiteboard::Value& rResultData);
|
||||
|
||||
private:
|
||||
whiteboard::Result startRunning(whiteboard::RequestId& remoteRequestId);
|
||||
whiteboard::Result stopRunning();
|
||||
|
||||
whiteboard::ResourceId mMeasAccResourceId;
|
||||
|
||||
whiteboard::RequestMap<2, void> mOngoingRequests; // For storing relations of incoming & outgoing requests
|
||||
|
||||
bool isRunning;
|
||||
size_t mSamplesIncluded;
|
||||
float mMaxAccelerationSq;
|
||||
};
|
@ -0,0 +1,43 @@
|
||||
#include "AccelerometerSampleService.h"
|
||||
#include "movesense.h"
|
||||
|
||||
MOVESENSE_APPLICATION_STACKSIZE(1024)
|
||||
|
||||
MOVESENSE_PROVIDERS_BEGIN(1)
|
||||
|
||||
MOVESENSE_PROVIDER_DEF(AccelerometerSampleService)
|
||||
|
||||
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, false)
|
||||
OPTIONAL_CORE_MODULE(DebugService, false)
|
||||
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 are (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(false, 0, 0)
|
||||
LOGBOOK_MEMORY_AREA(0, 384 * 1024);
|
||||
|
||||
APPINFO_NAME("Sample Accelerometer");
|
||||
APPINFO_VERSION("1.1.0");
|
||||
APPINFO_COMPANY("Movesense");
|
||||
|
||||
// NOTE: SERIAL_COMMUNICATION macro has been DEPRECATED
|
||||
BLE_COMMUNICATION(true)
|
||||
MOVESENSE_FEATURES_END()
|
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
enable_language(C CXX ASM)
|
||||
|
||||
if(NOT DEFINED MOVESENSE_CORE_LIBRARY)
|
||||
# Give error that user must provide path to movescount-core library
|
||||
message(FATAL_ERROR "Path to movesense-core library not set. Add -DMOVESENSE_CORE_LIBRARY=<path_to_core_lib> to cmake command line")
|
||||
endif()
|
||||
|
||||
if(NOT IS_ABSOLUTE ${MOVESENSE_CORE_LIBRARY})
|
||||
set(MOVESENSE_CORE_LIBRARY ${CMAKE_BINARY_DIR}/${MOVESENSE_CORE_LIBRARY})
|
||||
endif()
|
||||
|
||||
include(${MOVESENSE_CORE_LIBRARY}/MovesenseFromStaticLib.cmake REQUIRED)
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Type of the document
|
||||
wbres:
|
||||
version: "2.0"
|
||||
type: "root"
|
||||
|
||||
# Execution context definitions
|
||||
executionContexts:
|
||||
application:
|
||||
numberOfDpcs: 8
|
||||
numberOfRequests: 20
|
||||
numberOfResponses: 25
|
||||
externalThread: true # we run this execution context in main thread
|
||||
stackSize: 768
|
||||
priority: normal
|
||||
meas:
|
||||
numberOfDpcs: 9
|
||||
numberOfRequests: 25
|
||||
numberOfResponses: 10
|
||||
stackSize: 768
|
||||
priority: normal
|
||||
|
||||
|
||||
apis:
|
||||
AccelerometerSample.*:
|
||||
apiId: 100
|
||||
defaultExecutionContext: meas
|
@ -0,0 +1,61 @@
|
||||
# This file defines Suunto Whiteboard API for Movesense Hackathon 2016 sample
|
||||
#
|
||||
swagger: '2.0'
|
||||
|
||||
# Document metadata
|
||||
info:
|
||||
version: "0.0.0"
|
||||
title: Movesense Accelerometer sample app API
|
||||
description: |
|
||||
This file defines API for Movesense Accelerometer Sample service
|
||||
|
||||
See http://movesense.com for more information.
|
||||
termsOfService: http://suunto.com/wbapi/terms/
|
||||
contact:
|
||||
name: Suunto team
|
||||
url: http://developer.suunto.com
|
||||
|
||||
# Paths
|
||||
paths:
|
||||
/Sample/Accelerometer/Data/Subscription:
|
||||
post:
|
||||
description: |
|
||||
Subscribe to periodic Data values.
|
||||
See documentation on product-specific measurement periods at
|
||||
http://XXX.suunto.com/XXX. If measurement source is unavailable, the
|
||||
Measurement member will be empty. If present, Measurement member
|
||||
contains single measurement result.
|
||||
responses:
|
||||
200:
|
||||
description: Operation completed successfully
|
||||
x-std-errors:
|
||||
description: See common error codes http://developer.suunto.com/api/std-errors#subscribe
|
||||
x-notification:
|
||||
description: New value
|
||||
schema:
|
||||
$ref: '#/definitions/SampleDataValue'
|
||||
delete:
|
||||
description: |
|
||||
Unsubscribe from sample data values.
|
||||
responses:
|
||||
200:
|
||||
description: Operation completed successfully
|
||||
x-std-errors:
|
||||
description: See common error codes http://developer.suunto.com/api/std-errors#unsubscribe
|
||||
|
||||
definitions:
|
||||
SampleDataValue:
|
||||
required:
|
||||
- RelativeTime
|
||||
- Value
|
||||
properties:
|
||||
RelativeTime:
|
||||
description: Relative time of measurement
|
||||
type: integer
|
||||
format: uint32
|
||||
x-unit: millisecond
|
||||
Value:
|
||||
description: Sample Data Value (in practice max absolute acceleration, over about 5 seconds when subscribed)
|
||||
type: number
|
||||
format: float
|
||||
x-unit: m/s^2
|
@ -0,0 +1 @@
|
||||
// This file is needed by CMAKE. It can't generate empty libraries.
|
Loading…
Reference in new issue