Skip to content

Commit d5ff5e5

Browse files
Sepp62cujomalainey
authored andcommitted
MuscleOxygen: First shot of muscle oxygen monitor profile, rudimentarily tested
Signed-off-by: Curtis Malainey <curtis@malainey.com>
1 parent d3c5962 commit d5ff5e5

10 files changed

+286
-1
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ env:
3838
- PLATFORMIO_CI_SRC=examples/EnvironmentDisplay/EnvironmentDisplay.ino
3939
- PLATFORMIO_CI_SRC=examples/HeartRateDisplay/HeartRateDisplay.ino
4040
- PLATFORMIO_CI_SRC=examples/HeartRateMonitor/HeartRateMonitor.ino
41-
41+
- PLATFORMIO_CI_SRC=examples/MuscleOxygenMonitor/MuscleOxygenMonitor.ino
4242
install:
4343
- pip install -U platformio
4444

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**********************************************
2+
* AntPlus muscle oxygen monitor example
3+
*
4+
* Deliver data of a muscle oxygen sensor
5+
* to a display via serial port
6+
*
7+
* Author Bernd Woköck
8+
* based on the work of Curtis Malainey
9+
**********************************************/
10+
#include <Arduino.h>
11+
#include "ANT.h"
12+
#include "ANTPLUS.h"
13+
14+
#define BAUD_RATE 9600
15+
#define CHANNEL_1 0
16+
17+
const uint8_t NETWORK_KEY[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
18+
19+
AntWithCallbacks ant = AntWithCallbacks();
20+
AntPlusRouter router = AntPlusRouter();
21+
ProfileMuscleOxygenMonitor moxy = ProfileMuscleOxygenMonitor( 7369 );
22+
23+
void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data);
24+
25+
void setup() {
26+
Serial2.begin(BAUD_RATE);
27+
ant.setSerial(Serial2);
28+
delay(1000);
29+
30+
router.setDriver(&ant); // never touch ant again
31+
router.setAntPlusNetworkKey(NETWORK_KEY);
32+
router.setProfile(CHANNEL_1, &moxy);
33+
// Delay after initial setup to wait for user to connect on serial
34+
35+
Serial.begin(BAUD_RATE);
36+
Serial.println("Running");
37+
38+
// setup muscle oxygen monitor
39+
moxy.createMuscleOxygenDataMsg(moxyCreateMsgHandler);
40+
moxy.begin();
41+
}
42+
43+
void loop() {
44+
router.loop();
45+
}
46+
47+
void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data)
48+
{
49+
const int lo = 500, hi = 2500;
50+
static uint16_t c = lo;
51+
52+
// fake data
53+
msg.setTotalHemoglobinConcentration(c);
54+
msg.setCurrentSaturatedHemoglobinPercentage(c++/4);
55+
56+
if (c > hi)
57+
c = lo;
58+
}

src/Profiles/ANTPLUS_Profiles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
#include <Profiles/BicycleSpeed/ANTPLUS_BicycleSpeedProfile.h>
55
#include <Profiles/HeartRate/ANTPLUS_HeartRateProfile.h>
66
#include <Profiles/Environment/ANTPLUS_EnvironmentProfile.h>
7+
#include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenProfile.h>
78

89
#endif // ANTPLUS_ANTROUTER_h
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h
2+
#define ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h
3+
4+
/* Channel Config */
5+
#define ANTPLUS_MUSCLEOXYGEN_CHANNELTYPE CHANNEL_TYPE_BIDIRECTIONAL_RECEIVE
6+
#define ANTPLUS_MUSCLEOXYGEN_DEVICETYPE 31
7+
#define ANTPLUS_MUSCLEOXYGEN_CHANNELPERIOD 8192
8+
// Master channel
9+
#define ANTPLUS_MUSCLEOXYGEN_MASTER_CHANNELTYPE 0x10
10+
#define ANTPLUS_MUSCLEOXYGEN_MASTER_TRANSMISSIONTYPE 5
11+
#define ANTPLUS_MUSCLEOXYGEN_MASTER_DEVICENUMBER 5
12+
13+
// 30 / 2.5 = 12
14+
#define ANTPLUS_MUSCLEOXYGEN_SEARCHTIMEOUT 12
15+
16+
/* Pages */
17+
#define ANTPLUS_MUSCLEOXYGEN_DATAPAGE_MUSCLEOXYGENDATA 1
18+
19+
// Base page */
20+
#define ANTPLUS_MUSCLEOXYGEN_DATAPAGEBASE_DATAPAGE_BYTE 0x00
21+
22+
23+
#endif // ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef ANTPLUS_MUSCLEOXYGENPROFILE_h
2+
#define ANTPLUS_MUSCLEOXYGENPROFILE_h
3+
4+
// General Definitions
5+
#include <Profiles/MuscleOxygen/Monitor/ANTPLUS_ProfileMuscleOxygenMonitor.h>
6+
7+
// Datapages
8+
#include <Profiles/MuscleOxygen/DataPages/ANTPLUS_ProfileMuscleOxygenDataPages.h>
9+
10+
// Profile Classes
11+
// ...
12+
13+
#endif // ANTPLUS_MUSCLEOXYGENPROFILE_h
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h
2+
#define ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h
3+
4+
/* Base */
5+
#include <Profiles/MuscleOxygen/DataPages/Base/ANTPLUS_MuscleOxygenBaseMainDataPageMsg.h>
6+
7+
/* RX */
8+
// ...
9+
10+
/* TX */
11+
// ...
12+
13+
#endif // ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <Profiles/MuscleOxygen/DataPages/Base/ANTPLUS_MuscleOxygenBaseMainDataPageMsg.h>
2+
#include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h>
3+
#include <ANTPLUS_PrivateDefines.h>
4+
5+
6+
MuscleOxygenBaseGenericMsg::MuscleOxygenBaseGenericMsg() : BaseDataPageMsg<BroadcastDataMsg>()
7+
{
8+
memset(_buffer, 0, MESSAGE_SIZE);
9+
setDataBuffer(_buffer);
10+
}
11+
12+
MuscleOxygenBaseMainDataPageMsg::MuscleOxygenBaseMainDataPageMsg(uint8_t dataPageNumber) : MuscleOxygenBaseGenericMsg()
13+
{
14+
_buffer[ANTPLUS_DEFAULT_DATAPAGE_BYTE] = dataPageNumber;
15+
setCapabilities();
16+
setNotifications();
17+
}
18+
19+
void MuscleOxygenBaseMainDataPageMsg::setEventCount( uint8_t n )
20+
{
21+
_buffer[1] = n;
22+
}
23+
24+
void MuscleOxygenBaseMainDataPageMsg::setNotifications( uint8_t n )
25+
{
26+
_buffer[2] = n;
27+
}
28+
29+
void MuscleOxygenBaseMainDataPageMsg::setCapabilities( uint8_t c )
30+
{
31+
_buffer[3] = c;
32+
}
33+
34+
void MuscleOxygenBaseMainDataPageMsg::setTotalHemoglobinConcentration( uint16_t tc )
35+
{
36+
_buffer[4] = (uint8_t)tc;
37+
_buffer[5] &= ~0x0F;
38+
_buffer[5] |= (tc >> 8) & 0x0F;
39+
}
40+
41+
/* TODO
42+
void MuscleOxygenBaseMainDataPageMsg::setPreviousSaturatedHemoglobinPercentage( uint16_t pp )
43+
{
44+
_buffer[5] &= ~0xF0;
45+
_buffer[5] |= (uint8_t)(pp << 4);
46+
_buffer[6] &= ~0x3F;
47+
_buffer[6] |= (pp >> 4) & 0x3F;
48+
}
49+
*/
50+
51+
void MuscleOxygenBaseMainDataPageMsg::setCurrentSaturatedHemoglobinPercentage( uint16_t cp )
52+
{
53+
_buffer[6] &= ~0xC0;
54+
_buffer[6] |= (uint8_t)(cp << 6);
55+
_buffer[7] = cp >> 2;
56+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h
2+
#define ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h
3+
4+
#include <BaseClasses/ANTPLUS_BaseDataPageMsg.h>
5+
#include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h>
6+
7+
#include "ANT.h"
8+
9+
class MuscleOxygenBaseGenericMsg : public BaseDataPageMsg<BroadcastDataMsg> {
10+
public:
11+
MuscleOxygenBaseGenericMsg();
12+
13+
void copyData(uint8_t * buf, size_t len) { memcpy(_buffer, buf, len); }
14+
15+
protected:
16+
uint8_t _buffer[MESSAGE_SIZE];
17+
};
18+
19+
class MuscleOxygenBaseMainDataPageMsg : public MuscleOxygenBaseGenericMsg {
20+
public:
21+
MuscleOxygenBaseMainDataPageMsg(uint8_t dataPageNumber = ANTPLUS_MUSCLEOXYGEN_DATAPAGE_MUSCLEOXYGENDATA);
22+
23+
void setTotalHemoglobinConcentration( uint16_t tc );
24+
void setCurrentSaturatedHemoglobinPercentage(uint16_t cp);
25+
26+
// internal
27+
void setEventCount(uint8_t n);
28+
void setNotifications(uint8_t n = 0x00);
29+
void setCapabilities(uint8_t c = 0x06);
30+
};
31+
32+
#endif // ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <Profiles/MuscleOxygen/Monitor/ANTPLUS_ProfileMuscleOxygenMonitor.h>
2+
#include <CommonDataPages/ANTPLUS_CommonDataPagePrivateDefines.h>
3+
4+
5+
ProfileMuscleOxygenMonitor::ProfileMuscleOxygenMonitor(uint16_t deviceNumber, uint8_t transmissionType) :
6+
BaseMasterProfile(deviceNumber, transmissionType),
7+
_patternStep(0),
8+
_toggle(0),
9+
_eventCount(0)
10+
11+
{
12+
setChannelConfig();
13+
}
14+
15+
void ProfileMuscleOxygenMonitor::setChannelConfig() {
16+
setChannelType(ANTPLUS_MUSCLEOXYGEN_MASTER_CHANNELTYPE);
17+
setDeviceType(ANTPLUS_MUSCLEOXYGEN_DEVICETYPE);
18+
setChannelPeriod(ANTPLUS_MUSCLEOXYGEN_CHANNELPERIOD);
19+
setSearchTimeout(ANTPLUS_MUSCLEOXYGEN_SEARCHTIMEOUT);
20+
}
21+
22+
void ProfileMuscleOxygenMonitor::transmitNextDataPage() {
23+
// some static aux messages
24+
const uint8_t manufacturer[] = { 0x50, 0xFF, 0xFF, 0x01, 0x0F, 0x00, 0x85, 0x83 };
25+
const uint8_t product[] = { 0x51, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0x00, 0x00 };
26+
27+
if (_patternStep++ < 64) {
28+
transmitMuscleOxygenMainPageMsg();
29+
}
30+
else {
31+
MuscleOxygenBaseGenericMsg msg;
32+
if (_toggle++ % 1 == 0)
33+
msg.copyData((uint8_t*)manufacturer, MESSAGE_SIZE);
34+
else
35+
msg.copyData((uint8_t*)product, MESSAGE_SIZE);
36+
send(msg);
37+
_patternStep = 0;
38+
39+
// debug
40+
/*
41+
for (int i = 0; i < msg.getDataLength(); i++) {
42+
Serial.print(msg.getData(i), HEX); Serial.print(" ");
43+
}
44+
Serial.println("");*/
45+
}
46+
}
47+
48+
void ProfileMuscleOxygenMonitor::transmitMuscleOxygenMainPageMsg() {
49+
MuscleOxygenBaseMainDataPageMsg msg;
50+
msg.setEventCount( _eventCount );
51+
if( _patternStep % 4 == 0 )
52+
_eventCount++;
53+
_createMuscleOxygenDataMsg.call(msg);
54+
send(msg);
55+
}
56+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h
2+
#define ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h
3+
4+
#include <BaseClasses/ANTPLUS_BaseMasterProfile.h>
5+
#include <Profiles/MuscleOxygen/DataPages/ANTPLUS_ProfileMuscleOxygenDataPages.h>
6+
#include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h>
7+
#include <CommonDataPages/ANTPLUS_CommonDataPages.h>
8+
9+
class ProfileMuscleOxygenMonitor : public BaseMasterProfile {
10+
public:
11+
ProfileMuscleOxygenMonitor(uint16_t deviceNumber, uint8_t transmissionType = ANTPLUS_MUSCLEOXYGEN_MASTER_TRANSMISSIONTYPE);
12+
13+
/**
14+
* Register callback to populate default data messages (Datapage 0)
15+
*/
16+
void createMuscleOxygenDataMsg(void(*func)(MuscleOxygenBaseMainDataPageMsg&, uintptr_t), uintptr_t data = 0) { _createMuscleOxygenDataMsg.set(func, data); }
17+
18+
protected:
19+
virtual void transmitNextDataPage();
20+
virtual bool isDataPageValid(uint8_t dataPage) { return true; }
21+
22+
private:
23+
void setChannelConfig();
24+
void transmitMuscleOxygenMainPageMsg();
25+
26+
uint8_t _patternStep;
27+
uint8_t _toggle;
28+
uint8_t _eventCount;
29+
30+
Callback<MuscleOxygenBaseMainDataPageMsg&> _createMuscleOxygenDataMsg;
31+
};
32+
33+
#endif // ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h

0 commit comments

Comments
 (0)