-
Notifications
You must be signed in to change notification settings - Fork 182
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
Flash Read/Write Support #257
Conversation
Please, use |
0a997b0
to
c388e0a
Compare
Alright, I've rebased on master, it also looks like I need to run rustfmt over the code? |
Yea, that would be nice. Should just require doing |
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.
Thanks for putting in the work to finishing this!
Over all I think the changes look good on the surface though I'm not read up on the details of the flash device so these comments are mostly overall code quality. Since this has seen testing by at least 2 people, I think it's safe to merge despite this :)
@TheZoq2, thanks for the review feedback! I agree about squashing the warnings and the various name changes, but I did have comments/questions on two other parts, let me know what you think! |
I believe I've addressed all of the review findings, with the exception of handling the lock/unlock, still working on that! |
Actually, I don't think we need the pub fn read(&self, offset: u32, length: usize) -> Result<&[u8]> should be the same as pub fn read(&'c self, offset: u32, length: usize) -> Result<&'c [u8]> So it has to extend the borrow as long as the output lives if my understanding is correct, see this playground example: |
@thalesfragoso, yeah, I think you're right, we don't need to have the separate ReaderGuard, since the type system will prevent us from mutably borrowing the FlashWriter until the data returned by read() is out of scope, and we need to mutably borrow the FlashWriter before we could do any operations that would invalidate the data. |
So, I've been playing around with different ways to deal with the locking/unlocking of the flash, and I've found things I really don't like about each solution, I'd appreciate some input. I started out trying to wrap the The trouble with the I think my greater issue is the fact that the current Also, I don't know if there really is a strong need to unlock/lock the flash around each write/erase operation. This does minimize the window that the flash could get corrupted if the code were to go off the rails, but why not just unlock the flash when the I'd love to get @luctius's thoughts to know the intent behind the original design, but barring that, what do you guys think? |
src/flash.rs
Outdated
// reference to this FlashWriter, and any operation that would | ||
// invalidate the data returned would first require taking a mutable | ||
// reference to this FlashWriter. | ||
unsafe { core::slice::from_raw_parts::<'static, u8>(address, length) }, |
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.
This shouldn't be 'static
, it should have the same lifetime of &self
. Not sure if you need to strictly annotate it in order for the compiler to be happy.
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 looks like the compiler can infer the lifetime, as this compiles:
unsafe { core::slice::from_raw_parts(address, length) }
However, I decided to explicitly annotate the lifetimes around read()
to make the relationship more obvious.
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.
Hmm, but I don't think the 'a
lifetime was the best idea, since it's the same lifetime as Parts
like in the other case.
To be honest I think we should just let the compiler do the job and use just
pub fn read(&self, offset: u32, length: usize) -> Result<&[u8]> {
//...
unsafe { core::slice::from_raw_parts(address, length) }
}
The lifetime elisions rules seem to be very clear in this case anyway, so it's best to leave the compiler to choose the appropriate lifetime I think, maybe add a comment. Sorry for all the nitpicking .-.
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.
Haha don't be sorry, glad to get feedback! I didn't realize annotating the lifetime would change the behavior, I thought I was just making something that was implicit explicit.
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 was just because it was the same lifetime you used at
impl<'a> FlashWriter<'a>
I think we should hold on this change, better to leave for another PR, since the path isn't clear yet and the way it's now isn't that bad. |
@TheZoq2, if you agree, we can leave reworking the unlock/locking logic for a future PR? |
Sounds like a plan to me! |
If everything looks good now, should I squash-rebase before we merge? |
Yes, please. |
Incorporated Comments - Added FlashReaderGuard - Removed modulo operations - Added option to avoid verify operations - Cleanup Added more detailed notes for usage of unsafe in flash functions. ran "cargo fmt" to cleanup flash code Suppressed unused warnings for flash code, enum naming tweaks Added prefix '_' to registers and constants that aren't currently used, and renamed enum values based on review feedback added more descriptive comments where requested moved initialization of hword closer to where it's used Removed FlashReaderGuard, not necessary We can rely on the lifetime system to protect us here, the guard structure is unnecessary (see the unsafe comments for details). removed lifetimes from FlashWriter::read() Better to let the compiler determine the lifetime
9d0b35b
to
e6cb4a8
Compare
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.
Looks great to me, just 2 things remain: a changelog entry and a tiny issue with one of the doc comments :)
src/flash.rs
Outdated
Ok(()) | ||
} | ||
|
||
/// Retrieve an slice of data from FLASH_START +offset |
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.
Nitpick: should be a slice
. Also, would be nice to have the math in a code block, and a space after the +
src/flash.rs
Outdated
let end = start + self.sector_sz.kbytes() as u32 - 1; | ||
for idx in start..end { |
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.
Should this range be inclusive ? i.e. start..=end
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.
You are absolutely right, good catch. Do you think it should be start..=end
, or remove the -1
on the line above when end
is calculated?
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.
remove -1
is better
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.
Wait, I did not see previous line.
src/flash.rs
Outdated
// By subtracting 1 from the sector size and masking with | ||
// start_offset, we make 'start' point to the beginning of the | ||
// page, and similarly 'end' at the end of the page. We do this | ||
// because the entire page should have been erased, regardless | ||
// of where in the page the given 'start_offset' was. | ||
let start = start_offset & !(self.sector_sz.kbytes() as u32 - 1); | ||
let end = start + self.sector_sz.kbytes() as u32 - 1; | ||
for idx in start..end { |
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.
// By subtracting 1 from the sector size and masking with | |
// start_offset, we make 'start' point to the beginning of the | |
// page, and similarly 'end' at the end of the page. We do this | |
// because the entire page should have been erased, regardless | |
// of where in the page the given 'start_offset' was. | |
let start = start_offset & !(self.sector_sz.kbytes() as u32 - 1); | |
let end = start + self.sector_sz.kbytes() as u32 - 1; | |
for idx in start..end { | |
// By subtracting 1 from the sector size and masking with | |
// start_offset, we make 'start' point to the beginning of the | |
// page. We do this | |
// because the entire page should have been erased, regardless | |
// of where in the page the given 'start_offset' was. | |
let size = self.sector_sz.kbytes() as u32; | |
let start = start_offset & !(size - 1); | |
for idx in start..start+size { |
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.
Is this what you want to do?
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 like that, I think it is more readable than the previous version.
Looks like all standing issues are resolved, thanks everyone who helped out! |
This PR is a followup on #141.