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

Get type for BlockDevice #9135

Merged
merged 4 commits into from
Jan 7, 2019
Merged

Conversation

yossi2le
Copy link
Contributor

@yossi2le yossi2le commented Dec 18, 2018

Description

In this PR we like to add get_type method to blockdevice classes.
The motivation for this change is described in the docs/design-documents/features/storage/BlockDevices/get_type_method.md document which is part of this PR.

Pull request type

[ ] Fix
[ ] Refactor
[ ] Target update
[ ] Functionality change
[ ] Docs update
[ ] Test update
[X] Breaking change

@yossi2le yossi2le changed the title Get type for bd Get type for BlockDevice Dec 18, 2018
@@ -248,6 +248,7 @@ using namespace mbed;

// Only HC block size is supported. Making this a static constant reduces code size.
const uint32_t SDBlockDevice::_block_size = BLOCK_SIZE_HC;
const char * SDBlockDevice::_type = "SD";
Copy link
Contributor

Choose a reason for hiding this comment

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

This goes into RAM. const char * const would avoid that, but would still likely waste 4 bytes on a pointer.

It should be const char SDBlockDevice::_type[] = "SD";. But even then, why do that? It doesn't need to be an actual variable. The get_type() functions can just return a string literal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

10x. I have changed it to string literal as you proposed.

@yossi2le
Copy link
Contributor Author

@geky , @flit , @bulislaw , @donatieng , @sg-, and @AnotherButler please review.
@kjbracey-arm, I skipped tagging you cause I see you already started the review.
Thanks

@kjbracey
Copy link
Contributor

This achieves somethings similar to a mechanism we have in NetworkInterface - that has a series of methods that act like dynamic_casts, eg WiFiInterface *NetworkInterface::wifiInterface() which returns either WiFiInterface pointer, or NULL if it's not a WiFiInterface

So this is different to that, but I can see why - it's not an actual C++ type query, but an underlying device type query. This wouldn't be legal:

if (strcmp(bd->get_type(), "SD") == 0) {
    SDBlockDevice *sd = static_cast<SDBlockDevice *>(bd);
}

As long as that's as far as it goes, it seems reasonable, but if you ever feel you would want to get at the underlying driver type - find the underlying SDBlockDevice on a composed driver to call a method on it - then maybe the NetworkInterface "dynamic cast" version might be better than this pseudo-typeinfo. Maybe you don't want to encourage that sort of thing though - it would be stepping around the upper layer.

Or maybe the two mechanisms could coexist - a dynamic_cast-like thing that checks the actual top-level type, and a string query for the base physical(?) type.

@0xc0170 0xc0170 requested a review from a team December 18, 2018 13:26
@@ -36,6 +36,8 @@ using namespace mbed;
#define DEBUG_PRINTF(...)
#endif

#define BD_TYPE "FLASHIAP"
Copy link
Contributor

Choose a reason for hiding this comment

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

Others may disagree, but I'm not a fan of this model, at all. Writing:

 const char * FlashIAPBlockDevice::get_type()
 {
     return BD_TYPE;
 }

is basically semantically meaningless. Extend that further and you can get

REG1 = REG1_VALUE;
REG2 = REG2_VALUE;
<repeat for 100s of lines>

which I've seen in the past and it made me wince. It basically forces people to look in two places for a single piece of information. Pointless indirection.

Isn't this better?

 const char * FlashIAPBlockDevice::get_type()
 {
     return "FLASHIAP";
 }

No need to have a #define for a constant if that constant is used in exactly one place - doubly so if that place is the "specification" point itself.

Alternatively you could make the constants public in the drivers' header files so people strcmp against FLASHIAP_TYPE rather than "FLASHIAP", meaning it is used in more than one place, but don't think that buys you anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Member

@bulislaw bulislaw left a comment

Choose a reason for hiding this comment

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

I'd like to see a real situation how that will be used, it's not extremely object oriented solution and seems rather static. To explain what i'm talking about: QSPIF and SPIF for most use cases should be treated the same in this example some code will need to be extended if (strcmp(bd_type, "QSPIF") || strcmp(bd_type, "SPIF")) { I would say solution based on queried characteristics that can be inherited and overwritten when needed would be more in OOP spirit. That being said, it's up to @dannybenor to approve


### Physical BlockDevice:
```
const char * HeapBlockDevice::_type = "HEAP";
Copy link
Member

Choose a reason for hiding this comment

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

Example should return string literal same as the code.

| FlashIAPBlockDevice | "FLASHIAP" |
| DataFlashBlockDevice | "DATAFLASH" |


Copy link
Member

Choose a reason for hiding this comment

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

Nit: Lots of empty lines

Case("Testing contiguous erase, write and read", test_contiguous_erase_write_read, greentea_failure_handler),
Case("Testing BlockDevice::get_erase_value()", test_get_erase_value, greentea_failure_handler),
Case("Testing program read small data sizes", test_program_read_small_data_sizes, greentea_failure_handler)
//Case("Testing read write random blocks", test_random_program_read_erase, greentea_failure_handler),
Copy link
Member

Choose a reason for hiding this comment

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

Why is that commented out?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry, my mistake. I'll fix it

return;
}
const char * bd_type = block_device->get_type();
TEST_ASSERT_NOT_EQUAL(0, bd_type);
Copy link
Member

Choose a reason for hiding this comment

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

Your example, in design docs, suggest NULL is legal value, here you assert on NULL it may be confusing to people.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

NULL may be valid if there is no underlying bd and the blockdevice yet. However its not valid for the test and therefore assert on NULL.

@yossi2le
Copy link
Contributor Author

I'd like to see a real situation how that will be used, it's not extremely object oriented solution and >seems rather static. To explain what i'm talking about: QSPIF and SPIF for most use cases should be >treated the same in this example some code will need to be extended if (strcmp(bd_type, "QSPIF") || >strcmp(bd_type, "SPIF")) { I would say solution based on queried characteristics that can be inherited >and overwritten when needed would be more in OOP spirit. That being said, it's up to @dannybenor >to approve

@bulislaw this solution is being used at PR #9136, you can take a look at it.

@yossi2le
Copy link
Contributor Author

@kjbracey-arm we do expect to use this mechanism for getting the underlying physical block device and not for dynamic casting. Currently, I can't see the need for the dynamic cast mechanism on our side, but actually adding more interfaces in the long-long-term future is not blocked because of this PR.

@@ -283,4 +283,9 @@ bd_size_t ChainingBlockDevice::size() const
return _size;
}

const char * ChainingBlockDevice::get_type()
{
return "CHAINING";

Choose a reason for hiding this comment

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

Chaining is a special case and is not covered in design doc,

Question - Do we allow different type of physical block devices to be chained together?

Copy link
Contributor

@davidsaada davidsaada Dec 19, 2018

Choose a reason for hiding this comment

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

Chaining different physical block devices is currently allowed (there's no way to check such a thing up to this PR). However, the more interesting question is whether it should be allowed. I don't have a definite answer for it. However, if we wish to forbid it, we can change the type in this PR to the underlying one's.
@geky What do you say?

Copy link

@deepikabhavnani deepikabhavnani Dec 19, 2018

Choose a reason for hiding this comment

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

Chaining different physical block devices is currently allowed

Thanks, that answers my query

However, the more interesting question is whether it should be allowed.

Yes, but can keep it outside the scope of this PR.

For this PR, we should document the special case of chaining as note in API. Clearly stating that instead of physical block device, response return value is "chaining" string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right about the documentation. I will do it tomorrow morning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Documentation for ChainingBlockDevice added

@cmonr
Copy link
Contributor

cmonr commented Dec 20, 2018

@bulislaw @kjbracey-arm @deepikabhavnani @davidsaada @ARMmbed/mbed-os-storage @dannybenor
Any chance for a re-review sometime soon?

@deepikabhavnani
Copy link

deepikabhavnani commented Dec 20, 2018

#9135 (comment)

@cmonr - This is pending

Copy link
Contributor

@kjbracey kjbracey left a comment

Choose a reason for hiding this comment

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

I think I'm almost fine - just noticed another missing const though.

*
* @return A string represent the BlockDevice class type.
*/
virtual const char *get_type();
Copy link
Contributor

@kjbracey kjbracey Dec 21, 2018

Choose a reason for hiding this comment

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

Method should presumably be const. Otherwise, approved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@yossi2le
Copy link
Contributor Author

This PR probably will fail CI due to mbed-os-example-bootloader build error. I have issued a PR #94 to fix the example and solve the issue.

@dannybenor
Copy link

#94 seems not the right PR

@yossi2le
Copy link
Contributor Author

yossi2le commented Dec 27, 2018

#94 seems not the right PR

The PR is at mbed-os-example-bootloader repo.
ARMmbed/mbed-os-example-bootloader#95
Please notice that 94 has been closed and 95 was issued instead

@yossi2le
Copy link
Contributor Author

yossi2le commented Jan 6, 2019

mbed-os-example-bootloader PR 94 has been merged instead of 95. It should be OK now. Can we proceed with this PR now?

@0xc0170
Copy link
Contributor

0xc0170 commented Jan 7, 2019

Reviewers please leave feedback

@yogpan01
Copy link
Contributor

yogpan01 commented Jan 7, 2019

@yossi2le @0xc0170 Can this be merged, we need to get list of PRs in so that we can start timely testing on Client side.
@jenia81 @evedon FYI.

@0xc0170
Copy link
Contributor

0xc0170 commented Jan 7, 2019

CI started

@yossi2le @0xc0170 Can this be merged, we need to get list of PRs in so that we can start timely testing on Client side.

It was waiting for review to complete, now in CI and shall be ready soon (note we experienced some CI node failures over the weekend , still waiting for confirmation it is fixed today)

@mbed-ci
Copy link

mbed-ci commented Jan 7, 2019

Test run: SUCCESS

Summary: 11 of 11 test jobs passed
Build number : 1
Build artifacts

@0xc0170
Copy link
Contributor

0xc0170 commented Jan 9, 2019

Release label updated based on the agreement

@screamerbg
Copy link
Contributor

@0xc0170 Why was this merged in a patch release when apparently is a feature and also introduces a breaking change?

@dannybenor
Copy link

@yossi2le can you create a PR for adding the function in https://github.com/OpenNuvoton/NuMaker-mbed-SD-driver?

@0xc0170
Copy link
Contributor

0xc0170 commented Jan 29, 2019

@0xc0170 Why was this merged in a patch release when apparently is a feature and also introduces a breaking change?

The decision was made as noted above on the product level (Release label updated based on the agreement). @ARMmbed/mbed-os-storage can provide more details

@yossi2le
Copy link
Contributor Author

yossi2le commented Jan 29, 2019 via email

@dannybenor
Copy link

dannybenor commented Jan 29, 2019 via email

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

Successfully merging this pull request may close these issues.