- Notifications
You must be signed in to change notification settings - Fork 28
Initial MOxy sensor code #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d44c8e2 98d5cff 9b000e8 68e0b7b b051972 d38ecb3 81c9431 f841494 91cb627 50e7ce8 128d11c d8b830c 6fd66e2 6395970 b9582be b294cad 59a5074 36e4357 8897dd8 b093d80 fd43f0d 6d3c6dd 54a2ffa 7b78805 225398d 355c3b0 26f5aae f3d15fb 1cb487b d3c5962 dfdd074 6fca841 919362b ad3ba44 6d091c5 bc5f297 File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /********************************************** | ||
| * AntPlus muscle oxygen monitor example | ||
| * | ||
| * Deliver data of a muscle oxygen sensor | ||
| * to a display via serial port | ||
| * | ||
| * Author Bernd Wok�ck | ||
| * based on the work of Curtis Malainey | ||
| **********************************************/ | ||
| #include <Arduino.h> | ||
| #include "ANT.h" | ||
| #include "ANTPLUS.h" | ||
| | ||
| #define BAUD_RATE 9600 | ||
| #define CHANNEL_1 0 | ||
| | ||
| const uint8_t NETWORK_KEY[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; | ||
| | ||
| AntWithCallbacks ant = AntWithCallbacks(); | ||
| AntPlusRouter router = AntPlusRouter(); | ||
| ProfileMuscleOxygenMonitor moxy = ProfileMuscleOxygenMonitor( 7369 ); | ||
| | ||
| void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data); | ||
| | ||
| void setup() { | ||
| Serial2.begin(BAUD_RATE); | ||
| ant.setSerial(Serial2); | ||
| delay(1000); | ||
| | ||
| router.setDriver(&ant); // never touch ant again | ||
| router.setAntPlusNetworkKey(NETWORK_KEY); | ||
| router.setProfile(CHANNEL_1, &moxy); | ||
| // Delay after initial setup to wait for user to connect on serial | ||
| | ||
| Serial.begin(BAUD_RATE); | ||
| Serial.println("Running"); | ||
| | ||
| // setup muscle oxygen monitor | ||
| moxy.createMuscleOxygenDataMsg(moxyCreateMsgHandler); | ||
| moxy.begin(); | ||
| } | ||
| | ||
| void loop() { | ||
| router.loop(); | ||
| } | ||
| | ||
| void moxyCreateMsgHandler(MuscleOxygenBaseMainDataPageMsg& msg, uintptr_t data) | ||
| { | ||
| const int lo = 500, hi = 2500; | ||
| static uint16_t c = lo; | ||
| | ||
| // fake data | ||
| msg.setTotalHemoglobinConcentration(c); | ||
| msg.setCurrentSaturatedHemoglobinPercentage(c++/4); | ||
| | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO to add "previous sat hemoglobin" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is a mystery to me and my moxy display. Somebody else should integrate it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do | ||
| if (c > hi) | ||
| c = lo; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #ifndef ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h | ||
| #define ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h | ||
| | ||
| /* Channel Config */ | ||
| #define ANTPLUS_MUSCLEOXYGEN_CHANNELTYPE CHANNEL_TYPE_BIDIRECTIONAL_RECEIVE | ||
| ||
| #define ANTPLUS_MUSCLEOXYGEN_DEVICETYPE 31 | ||
| #define ANTPLUS_MUSCLEOXYGEN_CHANNELPERIOD 8192 | ||
| // Master channel | ||
| #define ANTPLUS_MUSCLEOXYGEN_MASTER_CHANNELTYPE 0x10 | ||
| ||
| #define ANTPLUS_MUSCLEOXYGEN_MASTER_TRANSMISSIONTYPE 5 | ||
| #define ANTPLUS_MUSCLEOXYGEN_MASTER_DEVICENUMBER 5 | ||
| ||
| | ||
| // 30 / 2.5 = 12 | ||
| #define ANTPLUS_MUSCLEOXYGEN_SEARCHTIMEOUT 12 | ||
| | ||
| /* Pages */ | ||
| #define ANTPLUS_MUSCLEOXYGEN_DATAPAGE_MUSCLEOXYGENDATA 1 | ||
| ||
| | ||
| // Base page */ | ||
| #define ANTPLUS_MUSCLEOXYGEN_DATAPAGEBASE_DATAPAGE_BYTE 0x00 | ||
| | ||
| | ||
| #endif // ANTPLUS_MUSCLEOXYGENPROFILEPRIVATEDEFINES_h | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #ifndef ANTPLUS_MUSCLEOXYGENPROFILE_h | ||
| #define ANTPLUS_MUSCLEOXYGENPROFILE_h | ||
| | ||
| // General Definitions | ||
| #include <Profiles/MuscleOxygen/Monitor/ANTPLUS_ProfileMuscleOxygenMonitor.h> | ||
| | ||
| // Datapages | ||
| #include <Profiles/MuscleOxygen/DataPages/ANTPLUS_ProfileMuscleOxygenDataPages.h> | ||
| | ||
| // Profile Classes | ||
| // ... | ||
| | ||
| #endif // ANTPLUS_MUSCLEOXYGENPROFILE_h |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #ifndef ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h | ||
| #define ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h | ||
| | ||
| /* Base */ | ||
| #include <Profiles/MuscleOxygen/DataPages/Base/ANTPLUS_MuscleOxygenBaseMainDataPageMsg.h> | ||
| | ||
| /* RX */ | ||
| // ... | ||
| | ||
| /* TX */ | ||
| // ... | ||
| | ||
| #endif // ANTPLUS_PROFILEMUSCLEOXYGENDATAPAGES_h |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #include <Profiles/MuscleOxygen/DataPages/Base/ANTPLUS_MuscleOxygenBaseMainDataPageMsg.h> | ||
| #include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h> | ||
| #include <ANTPLUS_PrivateDefines.h> | ||
| | ||
| | ||
| MuscleOxygenBaseGenericMsg::MuscleOxygenBaseGenericMsg() : BaseDataPageMsg<BroadcastDataMsg>() | ||
| { | ||
| memset(_buffer, 0, MESSAGE_SIZE); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious what the benefit of memsetting the values are :) All values in the datapage should be defined so we shouldnt be left with an 0s. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. During development, you cannot be sure to have all the bytes in a defined state. Initializing with "0" makes it easier to see bugs in bit math. Generally spoken: Initializing member data has very low cost and pays off during develplement and maintenance life cycle. In our special case "moxy" setPreviousSaturatedHemoglobinPercentage is unused and therefore a default initialization is helpful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point, I think though I would just set it to 0 it out in the variable declaration. *edit fair | ||
| setDataBuffer(_buffer); | ||
| } | ||
| | ||
| MuscleOxygenBaseMainDataPageMsg::MuscleOxygenBaseMainDataPageMsg(uint8_t dataPageNumber) : MuscleOxygenBaseGenericMsg() | ||
| { | ||
| _buffer[ANTPLUS_DEFAULT_DATAPAGE_BYTE] = dataPageNumber; | ||
| setCapabilities(); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment on other review about automating API :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dataPageNumber parameter removed. | ||
| setNotifications(); | ||
| } | ||
| | ||
| void MuscleOxygenBaseMainDataPageMsg::setEventCount( uint8_t n ) | ||
| { | ||
| _buffer[1] = n; | ||
| } | ||
| | ||
| void MuscleOxygenBaseMainDataPageMsg::setNotifications( uint8_t n ) | ||
| { | ||
| _buffer[2] = n; | ||
| } | ||
| | ||
| void MuscleOxygenBaseMainDataPageMsg::setCapabilities( uint8_t c ) | ||
| { | ||
| _buffer[3] = c; | ||
| } | ||
| | ||
| void MuscleOxygenBaseMainDataPageMsg::setTotalHemoglobinConcentration( uint16_t tc ) | ||
| { | ||
| _buffer[4] = (uint8_t)tc; | ||
| _buffer[5] &= ~0x0F; | ||
| _buffer[5] |= (tc >> 8) & 0x0F; | ||
| } | ||
| | ||
| /* TODO | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good, what is missing here that needs the TODO? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The behaviour of "setPreviousSaturatedHemoglobinPercentage" cannot be verified with my moxy display device. So it is not clear for me, how to handle it from the application side. Of course, I read the antplus docs, but I do not have a clue about the use of it. Since I cannot test it, I commented it out to give somebody else a chance to use it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the device just bumps the reading down. So on every event it moves the current value into previous and puts a new current. Docs site this reasoning for in the event of a data loss. It would be awesome if the class could handle this itself but since the class is never preserver I don't think there is a way around it other than showing the user through the example to do it themselves. | ||
| void MuscleOxygenBaseMainDataPageMsg::setPreviousSaturatedHemoglobinPercentage( uint16_t pp ) | ||
| { | ||
| _buffer[5] &= ~0xF0; | ||
| _buffer[5] |= (uint8_t)(pp << 4); | ||
| _buffer[6] &= ~0x3F; | ||
| _buffer[6] |= (pp >> 4) & 0x3F; | ||
| } | ||
| */ | ||
| | ||
| void MuscleOxygenBaseMainDataPageMsg::setCurrentSaturatedHemoglobinPercentage( uint16_t cp ) | ||
| { | ||
| _buffer[6] &= ~0xC0; | ||
| _buffer[6] |= (uint8_t)(cp << 6); | ||
| _buffer[7] = cp >> 2; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| #ifndef ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h | ||
| #define ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h | ||
| | ||
| #include <BaseClasses/ANTPLUS_BaseDataPageMsg.h> | ||
| #include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h> | ||
| | ||
| #include "ANT.h" | ||
| | ||
| class MuscleOxygenBaseGenericMsg : public BaseDataPageMsg<BroadcastDataMsg> { | ||
| public: | ||
| MuscleOxygenBaseGenericMsg(); | ||
| | ||
| void copyData(uint8_t * buf, size_t len) { memcpy(_buffer, buf, len); } | ||
| | ||
| protected: | ||
| uint8_t _buffer[MESSAGE_SIZE]; | ||
| }; | ||
| | ||
| class MuscleOxygenBaseMainDataPageMsg : public MuscleOxygenBaseGenericMsg { | ||
| public: | ||
| MuscleOxygenBaseMainDataPageMsg(uint8_t dataPageNumber = ANTPLUS_MUSCLEOXYGEN_DATAPAGE_MUSCLEOXYGENDATA); | ||
| | ||
| void setTotalHemoglobinConcentration( uint16_t tc ); | ||
| void setCurrentSaturatedHemoglobinPercentage(uint16_t cp); | ||
| | ||
| // internal | ||
| ||
| void setEventCount(uint8_t n); | ||
| void setNotifications(uint8_t n = 0x00); | ||
| void setCapabilities(uint8_t c = 0x06); | ||
| }; | ||
| | ||
| #endif // ANTPLUS_MUSCLEOXYGENBASEMAINDATAPAGEMSG_h | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #include <Profiles/MuscleOxygen/Monitor/ANTPLUS_ProfileMuscleOxygenMonitor.h> | ||
| #include <CommonDataPages/ANTPLUS_CommonDataPagePrivateDefines.h> | ||
| | ||
| | ||
| ProfileMuscleOxygenMonitor::ProfileMuscleOxygenMonitor( uint16_t deviceNumber, uint8_t transmissionType) : | ||
| BaseMasterProfile(deviceNumber, transmissionType), | ||
| _patternStep(0), | ||
| _toggle(0), | ||
| _eventCount(0) | ||
| | ||
| { | ||
| setChannelConfig(); | ||
| } | ||
| | ||
| void ProfileMuscleOxygenMonitor::setChannelConfig() { | ||
| setChannelType(ANTPLUS_MUSCLEOXYGEN_MASTER_CHANNELTYPE); | ||
| setDeviceType(ANTPLUS_MUSCLEOXYGEN_DEVICETYPE); | ||
| setChannelPeriod(ANTPLUS_MUSCLEOXYGEN_CHANNELPERIOD); | ||
| setSearchTimeout(ANTPLUS_MUSCLEOXYGEN_SEARCHTIMEOUT); | ||
| } | ||
| | ||
| void ProfileMuscleOxygenMonitor::transmitNextDataPage() { | ||
| // some static aux messages | ||
| ||
| const uint8_t manufacturer[] = { 0x50, 0xFF, 0xFF, 0x01, 0x0F, 0x00, 0x85, 0x83 }; | ||
| const uint8_t product[] = { 0x51, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0x00, 0x00 }; | ||
| | ||
| if (_patternStep++ < 64) { | ||
| transmitMuscleOxygenMainPageMsg(); | ||
| } | ||
| else { | ||
| MuscleOxygenBaseGenericMsg msg; | ||
| if (_toggle++ % 1 == 0) | ||
| msg.copyData((uint8_t*)manufacturer, MESSAGE_SIZE); | ||
| else | ||
| msg.copyData((uint8_t*)product, MESSAGE_SIZE); | ||
| send(msg); | ||
| _patternStep = 0; | ||
| | ||
| // debug | ||
| /* | ||
| ||
| for (int i = 0; i < msg.getDataLength(); i++) { | ||
| Serial.print(msg.getData(i), HEX); Serial.print(" "); | ||
| } | ||
| Serial.println("");*/ | ||
| } | ||
| } | ||
| | ||
| void ProfileMuscleOxygenMonitor::transmitMuscleOxygenMainPageMsg() { | ||
| MuscleOxygenBaseMainDataPageMsg msg; | ||
| msg.setEventCount( _eventCount ); | ||
| ||
| if( _patternStep % 4 == 0 ) | ||
| _eventCount++; | ||
| _createMuscleOxygenDataMsg.call(msg); | ||
| send(msg); | ||
| } | ||
| | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #ifndef ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h | ||
| #define ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h | ||
| | ||
| #include <BaseClasses/ANTPLUS_BaseMasterProfile.h> | ||
| #include <Profiles/MuscleOxygen/DataPages/ANTPLUS_ProfileMuscleOxygenDataPages.h> | ||
| #include <Profiles/MuscleOxygen/ANTPLUS_MuscleOxygenPrivateDefines.h> | ||
| #include <CommonDataPages/ANTPLUS_CommonDataPages.h> | ||
| | ||
| class ProfileMuscleOxygenMonitor : public BaseMasterProfile { | ||
| public: | ||
| ProfileMuscleOxygenMonitor(uint16_t deviceNumber, uint8_t transmissionType = ANTPLUS_MUSCLEOXYGEN_MASTER_TRANSMISSIONTYPE); | ||
| | ||
| /** | ||
| * Register callback to populate default data messages (Datapage 0) | ||
| */ | ||
| void createMuscleOxygenDataMsg(void(*func)(MuscleOxygenBaseMainDataPageMsg&, uintptr_t), uintptr_t data = 0) { _createMuscleOxygenDataMsg.set(func, data); } | ||
| | ||
| protected: | ||
| virtual void transmitNextDataPage(); | ||
| virtual bool isDataPageValid(uint8_t dataPage) { return true; } | ||
| | ||
| private: | ||
| void setChannelConfig(); | ||
| void transmitMuscleOxygenMainPageMsg(); | ||
| | ||
| uint8_t _patternStep; | ||
| uint8_t _toggle; | ||
| uint8_t _eventCount; | ||
| | ||
| Callback<MuscleOxygenBaseMainDataPageMsg&> _createMuscleOxygenDataMsg; | ||
| }; | ||
| | ||
| #endif // ANTPLUS_PROFILEMUSCLEOXYGENMONITOR_h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHANNEL_1 but defined as 0?