Skip to content

Commit 7b2912c

Browse files
authored
Merge pull request #15 from Sepp62/profiles/moxy/monitor
Initial MOxy sensor code
2 parents 650d84a + bc5f297 commit 7b2912c

File tree

48 files changed

+1764
-12
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1764
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ src/main.cpp
88
.DS_Store
99
.tags*
1010
tags
11+
examples/BikeSensorConverter/arduino_secrets.h

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ env:
3737
- PLATFORMIO_CI_SRC=examples/BicycleSpeedDisplay/BicycleSpeedDisplay.ino
3838
- PLATFORMIO_CI_SRC=examples/EnvironmentDisplay/EnvironmentDisplay.ino
3939
- PLATFORMIO_CI_SRC=examples/HeartRateDisplay/HeartRateDisplay.ino
40+
- PLATFORMIO_CI_SRC=examples/BicycleSpeedDisplay/BicycleSpeedDisplay.ino
41+
- PLATFORMIO_CI_SRC=examples/LEVDisplay/LEVDisplay.ino
4042
- PLATFORMIO_CI_SRC=examples/HeartRateMonitor/HeartRateMonitor.ino
41-
43+
- PLATFORMIO_CI_SRC=examples/MuscleOxygenMonitor/MuscleOxygenMonitor.ino
4244
install:
4345
- pip install -U platformio
4446

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ See [ant-arduino](https://github.com/cujomalainey/ant-arduino#hardware)
6666

6767
## Support ANT+ Profiles
6868

69-
This library aims to support all ANT+ devices. This goal will take time but its an attainable one. Check out the [wiki](https://github.com/cujomalainey/antplus-arduino/wiki/Profile-Support) for the list of profiles implemented and their verions.
69+
This library aims to support all ANT+ devices. This goal will take time but its an attainable one. Check out the [wiki](https://github.com/cujomalainey/antplus-arduino/wiki/Profile-Support) for the list of profiles implemented and their versions.
7070

7171
## Installation
7272

@@ -76,7 +76,7 @@ Arduino 1.5 and later
7676

7777
Arduino now includes a library manager for easier library installation. From the Sketch menu select include library->Manage Libraries, then type "antplus-arduino" in the filter and install.
7878

79-
Prior to Arduino 1.5 installation is a manual
79+
Prior to Arduino 1.5 installation is manual
8080

8181
Download a .zip or .tar.gz release from github. Determine the location of your sketchbook by selecting "preferences" on the Arduino menu. Create a "libraries" folder in your sketchbook and unzip the release file in that location.
8282

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
/**********************************************
2+
* AntPlus Bike Sensor Converter
3+
* LEV Display example
4+
* MuscleOxygen monitor
5+
* Shifting monitor
6+
*
7+
* Finds a nearby LEV Sensor, pairs
8+
* to it and then reads the information
9+
* out via the serial port.
10+
*
11+
* Author Bernd Woköck
12+
* based on the work of Curtis Malainey
13+
**********************************************/
14+
#include <Arduino.h>
15+
#include "ANT.h"
16+
#include "ANTPLUS.h"
17+
18+
// get ANT network key
19+
#include "arduino_secrets.h"
20+
21+
#define BAUD_RATE 9600
22+
23+
#define ANT_DEVICE_NUMBER_MOXY 7369
24+
#define ANT_DEVICE_NUMBER_SHIFT 7370
25+
#define CHANNEL_0 0
26+
#define CHANNEL_1 1
27+
#define CHANNEL_2 2
28+
29+
const uint8_t NETWORK_KEY[] = SECRET_ANTNETWORK_KEY;
30+
31+
AntWithCallbacks ant = AntWithCallbacks();
32+
AntPlusRouter router = AntPlusRouter();
33+
ProfileLevDisplay lev = ProfileLevDisplay();
34+
ProfileMuscleOxygenMonitor moxy = ProfileMuscleOxygenMonitor(ANT_DEVICE_NUMBER_MOXY);
35+
ProfileShiftingShifter shift = ProfileShiftingShifter(ANT_DEVICE_NUMBER_SHIFT);
36+
37+
void levBaseDataPageHandler(AntRxDataResponse& msg, uintptr_t data);
38+
void levSpeedSystemInformation1Handler(LevSpeedSystemInformation1& msg, uintptr_t data);
39+
void levSpeedDistanceInformationHandler(LevSpeedDistanceInformation& msg, uintptr_t data);
40+
void levAltSpeedDistanceInformationHandler(LevAltSpeedDistanceInformation& msg, uintptr_t data);
41+
void levSpeedSystemInformation2Handler(LevSpeedSystemInformation2& msg, uintptr_t data);
42+
void levBatteryInfo(LevBatteryInfo& msg, uintptr_t data);
43+
void levAntChannelEvent(ChannelEventResponse& msg, uintptr_t data);
44+
45+
void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data);
46+
void moxyCreateManufacturerInformationMsg(ManufacturersInformationMsg& msg, uintptr_t data);
47+
void moxyCreateProductInformationMsg(ProductInformationMsg& msg, uintptr_t data);
48+
49+
void shiftCreateMsgHandler(ShiftingBaseMainDataPageMsg& msg, uintptr_t data);
50+
void shiftCreateManufacturerInformationMsg(ManufacturersInformationMsg& msg, uintptr_t data);
51+
void shiftCreateProductInformationMsg(ProductInformationMsg& msg, uintptr_t data);
52+
53+
void manufacturersInformationDataPageHandler(ManufacturersInformation& msg, uintptr_t data);
54+
void productInformationDataPageHandler(ProductInformation& msg, uintptr_t data);
55+
56+
void printStatus(uint8_t status);
57+
58+
// mask for changed values
59+
enum {
60+
SPEED = 1,
61+
ODOMETER = 2,
62+
BATTERYSOC = 4,
63+
SUPPORTLEVEL = 8,
64+
SUPPORTLEVELCNT = 16,
65+
PERCENTASSIST = 32,
66+
WHEELCIRC = 64,
67+
};
68+
69+
// LEV data
70+
struct levDataST {
71+
uint32_t changedValueMask; // bit field for changed values
72+
uint16_t speed; // in 0.1km/h
73+
uint32_t odometer; // in 0.01km
74+
uint8_t batterySOC; // in percent
75+
uint8_t supportLevel; // 0..3
76+
uint8_t supportLevelCount; // 4
77+
uint8_t percentAssist; // in percent
78+
uint16_t wheelCircumference; // in mm
79+
}
80+
_levData = { 0, 0, 0, 0, 0, 0, 0, 0 };
81+
82+
void setup() {
83+
Serial2.begin(BAUD_RATE);
84+
ant.setSerial(Serial2);
85+
delay(1000);
86+
87+
router.setDriver(&ant); // never touch ant again
88+
router.setAntPlusNetworkKey(NETWORK_KEY);
89+
router.setProfile(CHANNEL_0, &lev);
90+
router.setProfile(CHANNEL_1, &moxy);
91+
router.setProfile(CHANNEL_2, &shift);
92+
// Delay after initial setup to wait for user to connect on serial
93+
94+
Serial.begin(BAUD_RATE);
95+
Serial.println("Running");
96+
97+
// setup lev display
98+
lev.onDataPage(levBaseDataPageHandler);
99+
lev.onLevSpeedSystemInformation1(levSpeedSystemInformation1Handler);
100+
lev.onLevSpeedDistanceInformation(levSpeedDistanceInformationHandler);
101+
lev.onLevAltSpeedDistanceInformation(levAltSpeedDistanceInformationHandler);
102+
lev.onLevSpeedSystemInformation2(levSpeedSystemInformation2Handler);
103+
lev.onLevBatteryInfo(levBatteryInfo);
104+
lev.onLevCapabilities(levCapabilities);
105+
lev.onManufacturersInformation(manufacturersInformationDataPageHandler);
106+
lev.onProductInformation(productInformationDataPageHandler);
107+
lev.onChannelEvent(levAntChannelEvent);
108+
lev.begin();
109+
delay(500); // wait for module initialization
110+
111+
// setup muscle oxygen monitor
112+
moxy.createMuscleOxygenDataMsg(moxyCreateMsgHandler);
113+
moxy.createMuscleOxygenManufacturerInformationMsg(moxyCreateManufacturerInformationMsg);
114+
moxy.createMuscleOxygenProductInformationMsg(moxyCreateProductInformationMsg);
115+
moxy.begin();
116+
delay(500);
117+
118+
// setup shifting oxygen monitor
119+
shift.createShiftingSystemStatusMsg(shiftCreateMsgHandler);
120+
shift.createShiftingManufacturerInformationMsg(shiftCreateManufacturerInformationMsg);
121+
shift.createShiftingProductInformationMsg(shiftCreateProductInformationMsg);
122+
shift.begin();
123+
delay(500);
124+
125+
// uint8_t status = lev.waitForPair(); // todo no busy wait here
126+
}
127+
128+
void loop() {
129+
router.loop();
130+
}
131+
132+
void levAntChannelEvent(ChannelEventResponse& msg, uintptr_t data) {
133+
if (msg.getCode() == STATUS_EVENT_CHANNEL_CLOSED)
134+
{
135+
Serial.println("channel closed - reconnect");
136+
lev.begin();
137+
}
138+
}
139+
140+
void levBaseDataPageHandler(AntRxDataResponse& msg, uintptr_t data) {
141+
LevBaseMainDataPage dp = LevBaseMainDataPage(msg);
142+
Serial.println("===========================");
143+
Serial.print("DataPage: ");
144+
Serial.println(dp.getDataPageNumber());
145+
}
146+
147+
void levSpeedSystemInformation1Handler(LevSpeedSystemInformation1& msg, uintptr_t data) {
148+
_levData.speed = msg.getSpeed();
149+
_levData.supportLevel = decodeSupportLevel(msg.getTravelModeState());
150+
_levData.changedValueMask |= SPEED | SUPPORTLEVEL;
151+
152+
Serial.print("Temperature state: ");
153+
Serial.println(msg.getTemperatureState()); // TODO enums for temperature state
154+
Serial.print("Travel mode state: ");
155+
Serial.println(msg.getTravelModeState()); // TODO decode travel mode state
156+
Serial.print("System state: ");
157+
Serial.println(msg.getSystemState()); // TODO enums for system state
158+
Serial.print("Gear state: ");
159+
Serial.println(msg.getGearState()); // TODO decode gear state
160+
Serial.print("Gear error: ");
161+
Serial.println(msg.getErrorMessage()); // TODO enums for error message
162+
Serial.print("Speed: ");
163+
Serial.print(msg.getSpeed() / 10);
164+
Serial.print(".");
165+
Serial.println(msg.getSpeed() % 10);
166+
}
167+
168+
void levSpeedDistanceInformationHandler(LevSpeedDistanceInformation& msg, uintptr_t data) {
169+
_levData.odometer = msg.getOdometer();
170+
_levData.speed = msg.getSpeed();
171+
_levData.changedValueMask |= SPEED | ODOMETER;
172+
173+
Serial.print("Odometer: ");
174+
Serial.println((float)msg.getOdometer() / 100);
175+
Serial.print("Remaining range: ");
176+
Serial.println(msg.getRemainingRange()); // TODO 0 = unknown
177+
Serial.print("Speed: ");
178+
Serial.print(msg.getSpeed() / 10);
179+
Serial.print(".");
180+
Serial.println(msg.getSpeed() % 10);
181+
}
182+
183+
void levAltSpeedDistanceInformationHandler(LevAltSpeedDistanceInformation& msg, uintptr_t data) {
184+
_levData.odometer = msg.getOdometer();
185+
_levData.speed = msg.getSpeed();
186+
_levData.changedValueMask |= SPEED | ODOMETER;
187+
188+
Serial.print("Total dist: ");
189+
Serial.println((float)msg.getOdometer() / 100);
190+
Serial.print("Fuel consumption: ");
191+
Serial.println(msg.getFuelConsumption()); // TODO 0 = unknown
192+
Serial.print("Speed: ");
193+
Serial.print(msg.getSpeed() / 10);
194+
Serial.print(".");
195+
Serial.println(msg.getSpeed() % 10);
196+
}
197+
198+
void levSpeedSystemInformation2Handler(LevSpeedSystemInformation2& msg, uintptr_t data) {
199+
_levData.batterySOC = msg.getBatterySOC();
200+
_levData.supportLevel = decodeSupportLevel(msg.getTravelModeState());
201+
_levData.percentAssist = msg.getPercentAssist();
202+
_levData.speed = msg.getSpeed();
203+
_levData.changedValueMask |= BATTERYSOC | SUPPORTLEVEL| PERCENTASSIST| SPEED;
204+
205+
Serial.print("Battery SOC: ");
206+
Serial.println(msg.getBatterySOC());
207+
Serial.print("Travel mode state: ");
208+
Serial.println(msg.getTravelModeState()); // TODO decode travel mode state
209+
Serial.print("System state: ");
210+
Serial.println(msg.getSystemState()); // TODO enums for system state
211+
Serial.print("Gear state: ");
212+
Serial.println(msg.getGearState()); // TODO decode gear state
213+
Serial.print("Percent Assist: ");
214+
Serial.println(msg.getPercentAssist());
215+
Serial.print("Speed: ");
216+
Serial.print(msg.getSpeed() / 10);
217+
Serial.print(".");
218+
Serial.println(msg.getSpeed() % 10);
219+
}
220+
221+
void levBatteryInfo(LevBatteryInfo& msg, uintptr_t data) {
222+
Serial.print("Charging Cycle Count: ");
223+
Serial.println(msg.getChargingCycleCount());
224+
Serial.print("Fuel consumption: ");
225+
Serial.println(msg.getFuelConsumption());
226+
Serial.print("Battery voltage: ");
227+
Serial.println(msg.getBatteryVoltage());
228+
Serial.print("Distance on current charge: ");
229+
Serial.println(msg.getDistanceOnCurrentCharge());
230+
}
231+
232+
void levCapabilities(LevCapabilities& msg, uintptr_t data) {
233+
_levData.wheelCircumference = msg.getWheelCircumference(); // in mm
234+
_levData.supportLevelCount = 4; // (msg.getTravelModesSupported() >> 3) & 0x07; // 4
235+
_levData.changedValueMask |= WHEELCIRC | SUPPORTLEVELCNT;
236+
237+
Serial.print("Travel modes supported: ");
238+
Serial.println(msg.getTravelModesSupported());
239+
Serial.print("Wheel circumference: ");
240+
Serial.println(msg.getWheelCircumference());
241+
}
242+
243+
void manufacturersInformationDataPageHandler(ManufacturersInformation& msg, uintptr_t data) {
244+
Serial.print("DataPage: ");
245+
Serial.println(msg.getDataPageNumber());
246+
Serial.print("HW Revision: ");
247+
Serial.println(msg.getHWRevision());
248+
Serial.print("ManufacturerID: ");
249+
Serial.println(msg.getManufacturerID());
250+
Serial.print("Model Number: ");
251+
Serial.println(msg.getModelNumber());
252+
}
253+
254+
void productInformationDataPageHandler(ProductInformation& msg, uintptr_t data) {
255+
Serial.print("DataPage: ");
256+
Serial.println(msg.getDataPageNumber());
257+
Serial.print("SW Revision Supplemental: ");
258+
Serial.println(msg.getSWRevisionSupplemental());
259+
Serial.print("SW Revision Main: ");
260+
Serial.println(msg.getSWRevisionMain());
261+
Serial.print("Serial Number: ");
262+
Serial.println(msg.getSerialNumber());
263+
}
264+
265+
void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data)
266+
{
267+
static uint8_t _eventCnt = 0;
268+
/* value mapping
269+
batterySOC --> CurrentSaturatedHemoglobinPercentage
270+
supportlevel.percentAssist --> TotalHemoglobinConcentration
271+
*/
272+
273+
if (_levData.changedValueMask & (BATTERYSOC | SUPPORTLEVEL | PERCENTASSIST)) {
274+
_levData.changedValueMask &= ~(BATTERYSOC | SUPPORTLEVEL | PERCENTASSIST);
275+
_eventCnt++;
276+
}
277+
msg.setCurrentSaturatedHemoglobinPercentage(_levData.batterySOC * 10 + _eventCnt % 2); // in 0.1 % (0 - 100)-- > 0 - 1000
278+
msg.setTotalHemoglobinConcentration(_levData.supportLevel * 100 + min(99, _levData.percentAssist)); // in 0.01g/dl (0-40) --> 0-4000
279+
msg.setEventCount(_eventCnt);
280+
Serial.println("new moxy values--------------");
281+
}
282+
283+
void moxyCreateManufacturerInformationMsg(ManufacturersInformationMsg& msg, uintptr_t data) {
284+
msg.setHWRevision(0x01);
285+
msg.setManufacturerId(0x1234);
286+
msg.setModelNumber(0x0001);
287+
}
288+
289+
void moxyCreateProductInformationMsg(ProductInformationMsg& msg, uintptr_t data) {
290+
msg.setSerialNumber(0x12345678);
291+
msg.setSWRevisionMain(0x01);
292+
msg.setSWRevisionSupplemental(0x00);
293+
}
294+
295+
void shiftCreateMsgHandler(ShiftingBaseMainDataPageMsg& msg, uintptr_t data)
296+
{
297+
static uint8_t _eventCnt = 0;
298+
299+
/* value mapping
300+
supportLevelCount (3) --> TotalNumbersGearFront
301+
10 --> TotalNumbersGearRear
302+
supportLevel (1-3) --> CurrentGearFront
303+
percentAssist/10 --> CurrentGearRear
304+
*/
305+
306+
if (_levData.changedValueMask & (SUPPORTLEVELCNT | SUPPORTLEVEL | PERCENTASSIST)) {
307+
_levData.changedValueMask &= ~(SUPPORTLEVELCNT | SUPPORTLEVEL | PERCENTASSIST);
308+
_eventCnt++;
309+
}
310+
msg.setTotalNumbersGearFront(3);
311+
msg.setTotalNumbersGearRear(10);
312+
msg.setCurrentGearFront(_levData.supportLevel-1);
313+
msg.setCurrentGearRear(10 - (_levData.percentAssist / 10));
314+
msg.setEventCount(_eventCnt);
315+
Serial.println("new shifting values---------------");
316+
}
317+
318+
void shiftCreateManufacturerInformationMsg(ManufacturersInformationMsg& msg, uintptr_t data) {
319+
msg.setHWRevision(0x01);
320+
msg.setManufacturerId(0x1234);
321+
msg.setModelNumber(0x0002);
322+
}
323+
324+
void shiftCreateProductInformationMsg(ProductInformationMsg& msg, uintptr_t data) {
325+
msg.setSerialNumber(0x12345678);
326+
msg.setSWRevisionMain(0x01);
327+
msg.setSWRevisionSupplemental(0x00);
328+
}
329+
330+
uint8_t decodeSupportLevel(uint8_t inValue) {
331+
const uint8_t slConv[] = {0,1,1,2,2,3,3,4,4}; // specialized: 0,1,3,5
332+
uint8_t sl = slConv[((inValue >> 3) & 0x07)];
333+
return sl;
334+
}
335+
336+
void printStatus(uint8_t status) {
337+
Serial.print("Channel Status: ");
338+
switch (status) {
339+
case CHANNEL_STATUS_UNASSIGNED:
340+
Serial.println("Unassigned");
341+
break;
342+
case CHANNEL_STATUS_ASSIGNED:
343+
Serial.println("Assigned");
344+
break;
345+
case CHANNEL_STATUS_SEARCHING:
346+
Serial.println("Searching");
347+
break;
348+
case CHANNEL_STATUS_TRACKING:
349+
Serial.println("Tracking");
350+
break;
351+
}
352+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#define SECRET_ANTNETWORK_KEY {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}

0 commit comments

Comments
 (0)