-
-
Notifications
You must be signed in to change notification settings - Fork 938
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
Step counter history added #2120
base: main
Are you sure you want to change the base?
Conversation
Build checks have not completed. Possible reasons for this are:
|
Nice! You should be able to test this on your sealed watch without problems. As long as you don't verify the firmware, a reboot will be enough to get it back to working. And if you do verify it, a force reboot into the backup firmware still enables you to install another firmware. |
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.
Cool feature, looking good :) haven't tried it yet on my PT yet but hopefully will soon
if (this->nbSteps != nbSteps && service != nullptr) { | ||
void MotionController::AdvanceDay() { | ||
--nbSteps; // Higher index = further in the past | ||
nbSteps[today] = -1; // Ensure that the `this->nbSteps[today] != nbSteps` condition in `Update()` will be FALSE |
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.
I think it'd be better to assign zero here and do service->OnNewStepCount() inside this function. Reasoning about -1 applied to an unsigned int is complex and so is reasoning about the delta steps calculation
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.
Done
@@ -18,7 +19,17 @@ namespace Pinetime { | |||
BMA425, | |||
}; | |||
|
|||
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps); | |||
enum Days { | |||
today = 0, |
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.
Enum members should be capitalised
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.
Done
yesterday = 1, | ||
}; | ||
|
||
using step_t = uint32_t; |
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.
I'm really split on this one. On one hand it's nice to have this as a type. On the other, I can't see this type ever being changed (nobody is ever gonna exceed 4 billion steps in a day :P) and it is slower to read and more verbose than uint32_t
. Also IIRC C++ still will allow using step_t
and uint32_t
interchangeably right? (and perhaps any larger/smaller integer type depending on the context). If that's true then we don't get any safety benefits either
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.
I was torn when I wrote this too :D
Yeah, it is unlikely to change, since the hardware returns a uint32_t
through bma423_step_counter_output()
and since it's an alias, step_t
is completely interchangeable with uint32_t
, so having this does not make the code any safer or faster.
But on the other hand, it is more verbose, potentially making the code easier to read (at least for me) that this function returns or expects a type in which steps are stored (even though the function/parameter name should be enough), much like how size_t
is used for most if not all functions where a container size is used.
At least that was my rationale when I wrote this, but I can change it back to uint32_t
if needed (or move it out of the MotionController
class).
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.
Or I could make it a real type instead of an alias, so they wouldn't be interchangeable.
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.
I think when it comes to verboseness what I mean is having to reference Controllers::MotionController::step_t
instead of uint32_t
. To me uint32_t
is easier to read, with the operations available on the type being clearer rather than having to look it up and go "oh, it's just an unsigned int, right". But your point about the semantics of the variable being clearer is fair.
I don't know, maybe someone else will have an opinion? I don't strongly oppose it either way
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.
It's just a count, right? Maybe keep it simple. I don't see, what problem would be solved, or is there any critical code, where confusion must not happen (e.g. temperature, where we handle values with different units)?
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.
Yeah, it's just a counter, I just didn't feel important to know the real underlying type everywhere in the code.
Even if step_t
makes sense, it definitely shouldn't be defined within MotionController
, so I'm removing it
@@ -32,15 +43,19 @@ namespace Pinetime { | |||
return zHistory[0]; | |||
} | |||
|
|||
uint32_t NbSteps() const { | |||
step_t NbSteps() const { |
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.
I think it'd be better if NbSteps took a member of Days as an argument (as you suggest actually)
The step counter history method is still needed though if you plan on exposing this over BLE
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.
Done
I've set Today
as default parameter.
Should I revert most of the changes to Steps.cpp
, where I'm storing a const reference to nbSteps
?
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.
I would personally as I think calling NbSteps() is a bit clearer than using the buffer reference
@@ -440,6 +440,7 @@ void SystemTask::UpdateMotion() { | |||
|
|||
if (stepCounterMustBeReset) { | |||
motionSensor.ResetStepCounter(); | |||
motionController.AdvanceDay(); |
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.
Can I suggest removing stepCounterMustBeReset
and the associated message as they aren't needed anymore? (as I2C is never slept) This would cause the step count handling to be done immediately when a new day starts. It's a little out of scope for this PR technically but it needs to be refactored anyway and I reckon now is a sensible time to do it
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.
It indeed sounds a bit out of scope
I can open a pull request only with this after this one if that's alright
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.
No worries, I'll get round to it
src/displayapp/screens/Steps.h
Outdated
lv_obj_t* stepsArc; | ||
lv_obj_t* resetBtn; | ||
lv_obj_t* resetButtonLabel; | ||
lv_obj_t* tripLabel; | ||
|
||
uint32_t stepsCount; | ||
const char* yesterdayStr; |
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.
Could yesterdayStr be a constant?
If that's fine, you could stick it in an anonymous namespace in the implementation as constexpr const char *
(I think!) and then it will live in just flash rather than flash and RAM
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.
In theory that's how it should work right now too, because I'm not copying the string, just taking the address of a string literal (that's why I don't need to free it either)
Unless I'm misunderstanding something
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.
It doesn't matter here too much as it's heap memory rather than stack, but you can avoid storing the pointer at all by effectively inlining the constant
Last, | ||
}; | ||
|
||
static constexpr size_t stepHistorySize = static_cast<std::underlying_type_t<Days>>(Days::Last); // Store this many day's step counter |
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.
NbSteps(Days::Last)
is out of bounds with this implementation right? I think that could be better, I'd expect every entry of the enum to be valid. Perhaps do LastEntry = Yesterday
and then static_cast<std::underlying_type_t<Days>>(Days::LastEntry) + 1
? Also probably assign an integer value explicitly to every enum member as well for clarity (except LastEntry as above)
My other concern is that there's no way to get all of the days without having an enum entry for each one. If we want to expose 7 days over BLE, at the moment all 7 days would need to be named in the enum which feels a bit odd. Not a dealbreaker though
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.
Yeah, theoretically out of bounds. In practice the CircularBuffer handles it internally by doing modulo (%
) operation on the size, so Days::Last
would be just index 0 again.
While it is nice to refer to the days with Today
and Yesterday
, maybe having to name 5 more enum values is not that nice.
One option is that the Days
enum can be removed altogether. Or alternatively it can remain with only Today
and Yesterday
values, and NbSteps()
function could get an overload that expects a uint8_t
.
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.
That second option sounds good to me, that way we have a nice human readable enum while also allowing specifying a number of days ago for more flexible usage
Sorry for the seemingly endless review! It's looking really good now, almost there |
It's alright, I'm actually enjoying this opportunity to "nerd out" with people on a project 😄 |
20168fa
to
7f7189e
Compare
7f7189e
to
85c1f4e
Compare
Since most if not all calls expect today, I set it as default value
85c1f4e
to
e973125
Compare
I changed the MotionController to remember the past N (currently 2) day's step counter history after the midnight reset. And I also changed the Steps screen to display (and update) yesterday's step count in addition to today's.
I didn't feel comfortable changing the return type of
MotionService::NbSteps()
yet without feedback, instead I wrote a new method to return the whole history.I've tested this only using InfiniSim, testing with devkits would be welcome!
In the future I would like to increase the history size from 2 to 7 and transfer the whole history to the companion applications, but I haven't really looked into how bluetooth communication or "API"s work, so feedback would be most appreciated!