Skip to content

Conversation

@Raupinger
Copy link
Contributor

@Raupinger Raupinger commented May 13, 2021

Incoming calls now cause a periodic vibration. The vibration stops when the call is accepted, rejected, muted or the notification is dismissed. The timeout for the call notification preview doesn't start until one of the three buttons is pressed.

Overview of the changes:

  • introduced new methods for stopping and starting the vibration. MotorController::startRunning(uint8_t motorDuration) starts a vibration pattern with a period of motorDuration and 50% duty cycle. stopRunning() stops that pattern. In the meantime no other vibrations can be triggered.
  • renamed APP_TIMER_DEF(shortVibTimer) to MotorController::runForDuration(uint8_t motorDuration) for clarity.
  • Screens::Notifications and Notifications::NotificationItem now require a reference to the motor Controller. This is needed so they can turn off the vibrations based on user interaction.
  • SystemTask::Work() will check the notification category and either starts a vibration pattern or a one time vibration based on it.
  • Notifications::NotificationItem now gets a pointer to timeoutTickCountEnd and timeoutTickCountStart. This is needed because it needs to set those times based on when one of the buttons is pressed.
  • the constructor of NotificationItem sets the timeoutOnHold flag when the notification is an incoming call
  • the event handlers for the buttons on the call notification now reset the timeout, clear the timeoutOnHold flag and stop the vibration pattern. A helper function is used to prevent dublicating that code.
  • Notifications::Refresh() checks if the timeoutOnHold flag is set before moving the progress bar. It also includes a check to make sure the vibration pattern gets stopped before the app quits.

Caveats:

  • the motor takes a lot of energy. It might be worth thinking about reducing the duty cycle of the pattern. I choose 50% because it allowed me to use a single timer. It might also be a good idea to add a timeout after which the vibration stops.
  • while working on this, the SWD interface on my devkit stopped working. Because of that, I could not test the finished code. In particular the sections relevant for resting the timeout when the timeoutOnHold flag is cleared. It looks fine to me and I didn't want to wait for a new kit to open this PR. I would appreciate if somebody could confirm that its working.

@Raupinger
Copy link
Contributor Author

call.mp4

Video of Gadgetbridges "find me" feature. As you can see the progress bar makes a jump when the mute button is pressed. The reason is that this build doesn't reset the timeout.

@Raupinger
Copy link
Contributor Author

I found a different adapter. tested the remaining changes and everything works.

@JF002 JF002 added the enhancement Enhancement to an existing app/feature label May 15, 2021
@Raupinger Raupinger force-pushed the Call-Improvements branch 2 times, most recently from 8a1ad9a to 4fcef4f Compare May 15, 2021 22:24
@JF002
Copy link
Collaborator

JF002 commented Jul 4, 2021

Thanks for this PR, and sorry for the delay to review it!

It looks mostly good to me, and the vibration is a lot more perceptible when receiving a call. No one will ever miss a call with this PR!

1 small formatting detail : Could you use the CamelCase for the methods you created (first letter is a capital one) so they are consistent with (most of) the other ones?

Also, could you fix the conflicts with develop so I can merge it?

Thanks!

@JF002 JF002 added this to the Version 1.3 milestone Jul 4, 2021
nlfx and others added 2 commits July 6, 2021 17:24
# Conflicts:
#	src/components/motor/MotorController.cpp
#	src/displayapp/DisplayApp.cpp
#	src/systemtask/SystemTask.cpp
@Raupinger
Copy link
Contributor Author

Raupinger commented Jul 6, 2021

ok, i changed the method names and merged current develop into the branch. didint rebase this time because i cant test it right now and the conflicts weren't 100% trivial so i would like to keep the working history.

@JF002
Copy link
Collaborator

JF002 commented Jul 6, 2021

Thanks for the merge. However, I think something went wrong during conflict fixing, and new changes that are not related to this PR got added (in DfuService.cpp (IsSleeping() is called 2x, once as a field, once as a method), SystemTask.h (IsSleeping was a method, it's now an atomic field), SystemTask.cpp (I think the code that actually enables the new vibrations for the call have been removed).
Could you check that out?

@Raupinger
Copy link
Contributor Author

Sure. Ill look it once im back at my desk

@JF002
Copy link
Collaborator

JF002 commented Jul 6, 2021

Of course, take your time, we're not in a hurry ;)

}

void MotorController::vibrate(void* p_context) {
void MotorController::startRunning(uint8_t motorDuration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint8_t isn't big enough

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe we don't need this parameter at all.

Copy link
Contributor Author

@Raupinger Raupinger Jul 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It defines the length of a the individual vibration and wait times the continuous pattern is made up of. You're right that using uint8_t limits that lenght to 255ms. Ill switch to 16 bit, but its really not that big of a deal (the only place this is currently used, the call notification sets it to 10ms). Removing this would mean hard-coding the "period" of the pattern which would mean applications cant vary their patterns.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, however I think it might be better for consistency to not let applications change it. And "hard coding" isn't always a bad thing if the alternative is to re define the same thing in many places.

In one of the earlier commits, there was this line, which overflowed the parameter. I don't know if you changed this later, as currently this line doesn't exist in this PR.
motorController.startRunning(500);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding this parameter is a possibility, indeed, mostly if we only use 1 single value.
If you want to future proof the class, the parameter is nice too. IMHO, the best solution for the type is not uint8_t or uint16_t or uint32_t but a stronger type that clearly represents a duration : std::chrono::millisecond or a custom type Duration, for example.

Copy link
Contributor

@jonvmey jonvmey Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with using std::chrono::milliseconds, it's large enough and eliminates any ambiguity as to what the expected units of motorDuration are without needing to dig into the implementation.

Comment on lines +50 to +55
void MotorController::vibrate(void* p_context) {
if (nrf_gpio_pin_out_read(pinMotor) == 0) {
nrf_gpio_pin_set(pinMotor);
} else {
nrf_gpio_pin_clear(pinMotor);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this function should play a pattern on each call. This would work for both a short and continuous notification and make them more noticable, and nicer. Just two short vibrations could work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vibration patterns would be a nice addition to this class MotorController. However, I think we can create a new PR to add them :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at extending the MotorController interface with something like void vibrate(std::chrono::milliseconds pulseDuration, int pulseCount = 1, std::chrono::milliseconds = some_reasonable_default) (or maybe a 0-100 duty cycle as the last parameter, defaulted to 50). If you think something like that would be useful here I can keep working on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the current 50% duty cycle is too aggressive and uncomfortable for the user. We should also limit the maximum duration the motor is running, because even in Metronome we can hear it get weaker.

}

void MotorController::vibrate(void* p_context) {
if (nrf_gpio_pin_out_read(pinMotor) == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nrf_gpio_pin_toggle exists as an option here.

@JF002
Copy link
Collaborator

JF002 commented Aug 4, 2021

@Raupinger do you plan on continuing working on this PR? Or should we focus on #544 instead? (no pressure, I'm just trying to plan my reviews of some PRs on the project :))

@Raupinger Raupinger closed this Aug 4, 2021
@Raupinger
Copy link
Contributor Author

Better to work on #544. I'll focus on other things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Enhancement to an existing app/feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants