Skip to content
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

Features/driver/iwdg #21

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

PratyushMakkar
Copy link
Contributor

@PratyushMakkar PratyushMakkar commented Jul 10, 2023

@Aidan-B

Description

The pull request is for the independent watchdog driver. The driver can be initialized with either a prescaler/reload value or a IDWG watchog typedef, the driver will then copy the values from the watchdog instance The driver allows changing the prescaler/reload values while the program is running and to refresh the watchdog timer.

Why was this done (if applicable)?
The driver is part of Milestone 1

Testing

Since the driver is not accessible in debug mode, to test it, I set an indicator LED to turn on and off at the start of the program so indicate that the CPU restarted. One test was to see if prescaler values can be modified while the program ran. To do that, the IOC file was configured to set the prescaler as 16 and reload value as 4095, in the program, the prescaler was set to 8 and reload as 2095. It was then manually checked that the CPU restarted more often (almost instantly) when the prescaler value was lower.

The second test was to refresh the watchdog a fixed amount of times with a HAL_Delay(); and then not to refresh the watchdog. The expected result is that the CPU will restart after 5 seconds + The Independent watchdog timer delay.

What unit tests were used to validate the code?

HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
IWDG_t watchdogDriver{&hiwdg};
 if (!watchdogDriver.SetWatchdogParameters(IWDG_PRESCALER_16, 4095)) {
	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
	  HAL_Delay(2000);
	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  }

  while (1) {
	 HAL_Delay(1000);
  }

Second Test

HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  HAL_Delay(500);
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  IWDG_t watchdogDriver{&hiwdg};
           for (uint8_t i = 0; i<100; i++) {
                 if (i<10) {
                      if (watchdogDriver.RefreshWatchdog()) {
                    	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
                    	  HAL_Delay(250);
                    	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
                    	  HAL_Delay(250);
                    	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
                      }
                  }
                  HAL_Delay(500);
           }

Documentation

Milestone number and name:
Milestone 1, Name: RSSI/Watchdog
Link to Asana task:
https://app.asana.com/0/1203458353737758/1204645025850461
Link to Confluence documentation:
TODO: Unsure how to use confluence.

Reminders

  • Add reviewers to the PR

  • Mention the PR in the appropriate discord channel

Drivers/IWDG_driver/Src/IndependentWatchdog.cpp Outdated Show resolved Hide resolved
* @brief Initalize the driver using custom IWDG_Prescaler and realod values.
*
*/
IWDG_t::IWDG_t(uint8_t iwdg_prescaler, uint16_t iwdg_reload) {

Choose a reason for hiding this comment

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

Any reason the Init function and this constructor cant be the same? Like, just do the Init function's logic in this constructor rather than have two separate functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have modified the driver so that setting prescaler and reload is the same as re-initializing the watchdog.

* to the value within the reload register.
*
*/
HAL_StatusTypeDef IWDG_t::RefreshWatchdog(IWDG_HandleTypeDef *watchdog) {

Choose a reason for hiding this comment

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

return a bool rather than HAL_StatusTypeDef here. perhaps return false for an error or something like that? Or make a status bool stored in the driver that can be checked by a manager. @TheSpaceDragon @Chrisc110 @Ayounggie Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I agree with changing the return type to bool. It would be nice to have something like didWatchdogRefresh confirmation after the function returns.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I use try catch to supress errors and return false as well in the newest commit?

* to the value within the reload register.
*
*/
HAL_StatusTypeDef IWDG_t::RefreshWatchdog(IWDG_HandleTypeDef *watchdog) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I agree with changing the return type to bool. It would be nice to have something like didWatchdogRefresh confirmation after the function returns.

Drivers/IWDG_driver/Src/IndependentWatchdog.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@Aidan-B Aidan-B left a comment

Choose a reason for hiding this comment

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

Overall, it seems like there is a little bit of redundancy in the code that should be pretty easy to simplify.

#include <stdint.h>
#include "main.h"

class IWDG_t {
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like an odd class name

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would IWDGDriver be more suitable?

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the name IndependentWatchdog, like you have named the file. IndependentWDG or IWDG might also be suitable.

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 the formatting isn't quite right. Could you run clang-format? There's some extra whitespace and the alignment doesn't match what we use elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is clang-format a bash command? I was unable to run it on my system. I am editing on Vscode and I am using tabs.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm pretty sure if you run Ctrl + Shift + I in vscode it will format the code for you, using our clang-format rules.

Drivers/IWDG_driver/Src/IndependentWatchdog.cpp Outdated Show resolved Hide resolved
Drivers/IWDG_driver/Inc/IndependentWatchdog.h Outdated Show resolved Hide resolved
Drivers/IWDG_driver/Inc/IndependentWatchdog.h Outdated Show resolved Hide resolved
Drivers/IWDG_driver/Inc/IndependentWatchdog.h Outdated Show resolved Hide resolved
Copy link
Contributor

@Aidan-B Aidan-B left a comment

Choose a reason for hiding this comment

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

I would suggest thinking about how you intend for users to interact with the watchdog. In my opinion, the primary actions would be to:
a) setup the watchdog. This can be done entirely from the constructor
b) pet the watchdog. This may need to be done from different threads

Think about then how your driver's API can meet the needs of the user.

return refresh;

bool IWDG_t::RefreshWatchdog() {
if (!this->watchdog) {
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 the following would be more readable:

Suggested change
if (!this->watchdog) {
if (this->watchdog == nullptr) {

Comment on lines 50 to 53
void IWDG_t::SetIWDGWatchdog(IWDG_HandleTypeDef* watchdog) {
this->watchdog = watchdog;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Why would we ever need to do this in the lifetime of the watchdog?

also, this will likely cause a memory leak, the old watchdog doesn't get deleted and it isn't very clear what owns that object.

Comment on lines 58 to 60
IWDG_HandleTypeDef* IWDG_t::GetIWDGWatchdog(IWDG_HandleTypeDef* watchdog) {
return this->watchdog;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think anything would ever need to get this? I don't really see the utility here.

Additionally, there is the issue of what owns the pointer, and the implications of passing it around (or even deleting it)

Choose a reason for hiding this comment

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

I agree, setting and getting the watchdog handle arent really important for this driver imo.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, for this function, wouldn't we be passing a watchdog pointer and then returning the same watchdog?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function has been removed

Comment on lines 10 to 11
uint8_t iwdg_prescaler;
uint16_t iwdg_reload;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need to store these values, since they exist in the IWDG_HandleTypeDef. We are just duplicating the storage of data by having them in this scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has been addressed. The values are not stored anymore.

Drivers/IWDG_driver/Src/IndependentWatchdog.cpp Outdated Show resolved Hide resolved
static HAL_StatusTypeDef RefreshWatchdog(IWDG_HandleTypeDef* watchdog);
void SetIWDGWatchdog(IWDG_HandleTypeDef* watchdog);
IWDG_HandleTypeDef* GetIWDGWatchdog(IWDG_HandleTypeDef* watchdog);
bool SetWatchdogParameters(uint8_t prescaler, uint16_t reload);
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 this should be something like UpdateWatchdogParameters, since it updates them. Currently it implies that it sets values that haven't been otherwise set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, after further review, I think I understand why you created this function - to allow the user to set the parameters of the watchdog (before starting the watchdog).
I would argue (and have been basing my reviews off this assumption) that this should configuration should be done by the user before they pass the IWDG_HandleTypeDef to the driver, with the Init function being called from the constructor. I believe it to be the general approach that the team has been taking with other drivers thus far. Curious what you and @SnackkOverflowError think about this approach.

Choose a reason for hiding this comment

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

Hmmm theres a lot of ways to handle this. On one hand, the watchdog parameters can be set in our IOC (which will generate code to configure them in the watchdog handle I believe). Then the handle is passed into this driver and the parameters can be retrieved from the handle. In which case I agree that this function should be named UpdateWatchDogParameters .
What exactly is the usecase for resetting the watchdog parameters after the driver has been created though? Is there a scenario where we want to change the frequency that we pet it at? Seems like we should agree on the watchdog parameters once and then never touch them again? If the usecase is being able to configure them in model config, IMO these params should be parameters in the constructor and set there once, then never reset during the programs lifetime.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, I feel like updating watchdog parameters after initialization could cause some unforeseen issues later on. Though, it doesn't hurt to have the function when/if need arises for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function has been removed as requested.

this->iwdg_prescaler = prescaler;
this->iwdg_reload = reload;

if (!IS_IWDG_PRESCALER(prescaler) || !IS_IWDG_RELOAD(reload)) return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Where are these macros defined? I didn't see them in my skim of the HAL docs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe the HAL docs do not mention it even though it is available. I saw that the f4 did not mention it either even though it is available in the stm32f4xx_iwdg.h file. However the function is removed in the newest commit so that should resolve any potential issues.

this->iwdg_reload = reload;

if (!IS_IWDG_PRESCALER(prescaler) || !IS_IWDG_RELOAD(reload)) return false;
watchdog->Init.Reload = reload;
Copy link
Contributor

Choose a reason for hiding this comment

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

You should probably check that the reload value is less than the max value for the reload (0x0FFF iirc)

#include <stdint.h>
#include "main.h"

class IWDG_t {
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the name IndependentWatchdog, like you have named the file. IndependentWDG or IWDG might also be suitable.

/**
* @brief Initalize the driver using custom IWDG_Prescaler and realod values.
* @brief Reset the reload and counter values inside a watchdog
* using the member variables of IWDG_t
*
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
*
* @returns true on success, false on failure


public:
IWDG_t(IWDG_HandleTypeDef* watchdog);
void SetIWDGWatchdog(IWDG_HandleTypeDef* watchdog);

Choose a reason for hiding this comment

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

Will this function ever need to be used? Seems like you can just use the constructor? I don't really see a reason that the watchdog handle will need to be reset.

Drivers/IWDG_driver/Src/IndependentWatchdog.cpp Outdated Show resolved Hide resolved
Comment on lines 58 to 60
IWDG_HandleTypeDef* IWDG_t::GetIWDGWatchdog(IWDG_HandleTypeDef* watchdog) {
return this->watchdog;
}

Choose a reason for hiding this comment

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

I agree, setting and getting the watchdog handle arent really important for this driver imo.

static HAL_StatusTypeDef RefreshWatchdog(IWDG_HandleTypeDef* watchdog);
void SetIWDGWatchdog(IWDG_HandleTypeDef* watchdog);
IWDG_HandleTypeDef* GetIWDGWatchdog(IWDG_HandleTypeDef* watchdog);
bool SetWatchdogParameters(uint8_t prescaler, uint16_t reload);

Choose a reason for hiding this comment

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

Hmmm theres a lot of ways to handle this. On one hand, the watchdog parameters can be set in our IOC (which will generate code to configure them in the watchdog handle I believe). Then the handle is passed into this driver and the parameters can be retrieved from the handle. In which case I agree that this function should be named UpdateWatchDogParameters .
What exactly is the usecase for resetting the watchdog parameters after the driver has been created though? Is there a scenario where we want to change the frequency that we pet it at? Seems like we should agree on the watchdog parameters once and then never touch them again? If the usecase is being able to configure them in model config, IMO these params should be parameters in the constructor and set there once, then never reset during the programs lifetime.

@@ -0,0 +1,22 @@
#ifndef SRC_DRIVERS_INDEPENDENTWATCHDOG_H_
#define SRC_DRIVERS_INDEPENDENTWATCHDOG_H_

Choose a reason for hiding this comment

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

Please fix the filenames according to our style guide: https://uwarg-docs.atlassian.net/wiki/spaces/ZP/pages/2268692486/Style+Standards

@Aidan-B
Copy link
Contributor

Aidan-B commented Jul 14, 2023

I just realized this class doesn't inherit from a base watchdog interface class, which it probably should do (so we can more easily mock it for unit tests)

Copy link

@SnackkOverflowError SnackkOverflowError left a comment

Choose a reason for hiding this comment

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

Looks good except for some code in your constructor

this->watchdog = watchdog;
IWDG_InitTypeDef initDef = watchdog->Init;
this->iwdg_prescaler = initDef.Prescaler;
this->iwdg_reload = initDef.Reload;

Choose a reason for hiding this comment

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

iwdg_prescaler and iwdf_reload dont exist anymore (and arent used) so probably remove lines 11,12 and 13 I think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants