-
Notifications
You must be signed in to change notification settings - Fork 282
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
Very rough first draft of radio module related documentation. #305
Conversation
It can be up to 256 (????? CHECK THIS from memory) bytes long. | ||
|
||
The ``queue`` specifies the number of messages that can be stored on the | ||
incoming message queue. |
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 a circular queue? We should probably indicate what happens when receiving more messages than there are spaces left.
See my comment about the API w.r.t bytes/strings #283 (comment) |
At the minimum we should provide a "raw" API whereby it's just bytes sent/received over the air, with no headers or anything added. Then people can use that to implement things however they like. On top of that we can, if needed, add a "friendly" API which does some pickling/unpickling of the data (eg using repr/eval) so that you can send typed data. |
The API offered up by m.pxt.io is fine for all purposes I have seen and
implemented to date - I presume most of this is just built on top of the
DAL and the underlying nordic gazelle layer.
The key feature is the groupid byte, that 'feels' like tuning to a channel,
and makes it easy to implement independently working solutions in the same
room. RSSI measurements, setting the power level, transmitting a byte, a
string, or a keyed value, adding in an optional send timestamp and an
optional micro:bit serial number. Everything is broadcast (or simulated
multicast if you take the group byte into account automatically as PXT
does). Leave everything else up to the user to innovate themselves - this
seems fine to me.
Security for example - I don't see that we need any. Let the inventors of
the future realise the problems of non secure communications by
experiencing it first hand, and coming up with their own solutions to that
learning opportunity. We don't want to pre-join too many of the dots for
them.
|
@dpgeorge What does adding a "raw" protocol gain? If you want to send bytes, just send them. The radio protocol already add channels, headers, data-whitening, lengths and check sums. So there really isn't such thing as raw data. |
So you can communicate simply with non-Python code. The way I implemented it it already does "raw" bytes. Adding typed data is an extra layer on top of that. If we eventually allow to control all the radio parameters then raw bytes are the only thing that makes sense to send. |
It doesn't have to be an extra layer. Bytes is merely one of many possible types that can be transmitted. |
Thanks for the feedback so far. I've made some revisions in light of the conversation above. @whaleygeek - I agree with what you're saying... leave it to the user to discover, explore and play. The most important thing we can do is make it easy and facilitate such playful exploration via a simple and obvious API. I think it important that the API fulfil two functions (IMHO in order of importance):
@dpgeorge @markshannon to fulfil the second requirement we should expose all the various configuration options (as I suggest with the Regarding the first requirement: it should be as simple as possible with the potential for playful exploration built in. From my point of view that simply means sending and receiving strings. Such messages would suffice for most basic use-cases. If an incoming message cannot be converted to a string it should be ignored (although it should be possible to override this behaviour) . It also means sending a message is three lines of code:
Each line is easy to understand and tells an obvious part of the "story of using the radio" in a learner's mind. Why not any other data types? Because realising why we have different types and that they can be represented in different ways is something for kids to learn about, and this module is a good way to introduce some aspects of this area to them. It'll mean they encounter, first hand, the difference between Just using strings for the high level methods keeps the API very very simple. Not doing anything else would also provide an excellent opportunity for a lesson in data serialisation (e.g. via Finally, limiting messages to strings is both conceptually easy for a non-technical 11yo kid to understand (it's like writing a letter that's sent via the radio) yet limited enough that they'll soon realise why it's interesting to drop to the "raw bytes" layer to have more control over the messages being sent. Does this make sense? |
default values are sensible. | ||
|
||
The ``length`` defines the size, in bytes, of a message sent via the radio. | ||
It can be up to 256 (????? CHECK THIS from memory) bytes long. |
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 someone confirm what this upper limit is? I remember reading it somewhere but can't, for the life of me, find where that's referenced.
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's 251 (254 - 3 bytes for S0, LENGTH and S1 preamble).
Errors should never pass silently. You are a very cruel person, if you want the kids to have to figure out why their messages are not being transmitted, even though everything should work. Especially since wireless transmission is involved, and there may be additional problems with range, power, channels, etc. |
# To contain code that demonstrates the radio module. | ||
import radio | ||
|
||
radio.send("Hello, World!") |
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.
radio.on() first?
@deshipu you're right. I wasn't thinking things through (my head was in the "just make it work for the kids no matter what" space). Upon re-reading it's painfully obvious that errors MUST be reported and, to address @dpgeorge's point, it's a good opportunity to introduce the notion of I'll update the docs in light of the above and other recent documents. |
OK... it feels like we're getting there. I'm certainly happy with the way the API is shaping up - it's certainly feels simple enough to get an 11yo sending wireless messages while still providing enough configuration and access to "raw bytes" to facilitate more complicated forms of communication. Thoughts..? |
I really don't think that we need to abandon the "everything is an object" paradigm of Python that we use throughout the rest of the API, just for the radio module. I'm sure that it is good for kids to understand that everything is composed of bytes. For interoperability with DAL based implementations is important that we can send and receive bytes, but strings and ints are more useful objects. Much of the rest of the API is polymorphic, it keeps the API small and memorable. |
|
||
.. py:function:: send(message) | ||
|
||
Sends a message, expressed as a string or bytes. Sending a string is |
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 don't like "expressed as a string or bytes", I would prefer "which can be a string or bytes object". The message (in the context of the API) is an object.
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.
The message (in the context of the API) is an object.
The "message" should be a sequence of bytes, not an object. The ability to send a string (unicode) is a convenience thing.
Most (all?) the other communication entities in the API use bytes objects exclusively: uart, spi and i2c. It should be the same for radio. You might want to add a layer to the uart/spi/i2c interfaces to send and receive arbitrary objects (eg i2c.send(42)) but first and foremost you should support transfer of raw bytes because that's how it works on the wire, and allows you to communicate with arbitrary devices. |
At no point have I suggested we don't support sending and receiving bytes. I just don't see why we need to make it unnecessarily difficult to send other objects. Most (all?) the other communication entities in the API use bytes objects exclusively: uart, spi and i2c. It should be the same for radio. You might want to add a layer to the uart/spi/i2c interfaces to send and receive arbitrary objects (eg i2c.send(42)) but first and foremost you should support transfer of raw bytes because that's how it works on the wire, and allows you to communicate with arbitrary devices. —You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread. |
I disagree with your proposal. I think that bytes should be special and at a lower layer, and typed data/objects at a higher level (and typed bytes objects can also exist at this higher level), building on the low-level bytes send/recv functionality. In particular you can choose to receive anything as bytes, even if it was sent as typed data (then you'd see the encoding scheme). The logical address should be exposed to the user so they can write protocols that are compatible with C/C++ code that uses logical addresses in an arbitrary way. So I would propose something like: # raw bytes protocol
radio.send_bytes(bytes_obj)
bytes_obj = radio.receive_bytes()
# higher-level object protocol
radio.send(obj) # equivalent to radio.send_bytes(bytes(repr(obj), 'utf8'))
obj = radio.receive() # equivalent to obj = eval(str(radio.receive_bytes(), 'utf8')) |
In the most recent push I renamed Also, @dpgeorge I think kids may use the power settings. Evidence: a teacher was recently telling me how interesting it would be to measure the range of the devices given a remote-controlled robot project they had in mind. |
+1 LGTM... I'll update the docs. |
Actually, upon reflection, can we just make this string only for the moment. |
There is still some ambiguity in the docs: if I call on(), then config(...), then off(), then on() again, does the second "on" reset the setting to the defaults, or use the last settings? Stepping back a bit, I think it's a bit convoluted/confusing to have config() with no args reset all the state, and config(...) with a few args reset everything except the given args. I'd propose the following:
|
@dpgeorge given the discussion today on the mailing list I was going to propose more-or-less the same. :-) |
Ah, yes, I see it now! Any tweaks to my proposal? In #306 I suggested config('param') is used for get_config. |
How about |
BTW... my work from this morning is on ntoll/radio. Unfinished and with some documentation re-arrangement too so things a laid out more logically. YMMV but you can see where I was going with it. |
That makes it clear and explicit, but then "config" should be "set_config" (as per the mailing list discussion). Probably "reset" can stay as "reset". Note that the decision here is ultimately the decision for #306... |
I don't know if that helps, but most Python style guides recommend that function and method names should be verbs or verb phrases, such as "get_configuration", "configure" or "reset", while attributes and properties should be nouns or noun phrases, such as "configuration" (they also advise against using shortened words or acronyms). However, Micropython seems to be developing this pattern where a method is used in place of a property (because property is inefficient), and where calling it with a parameter sets the property, while calling it without a parameter gets it. There is also that recommendation that if an operation is costly (in time or otherwise) or has side effects, it should be a method, not a property. So the question is, does setting those properties have significant side effects or time penalties, or does it just set some internal registers, and the actual work is done when calling other methods? By the way, is there any particular reason why it's just a single method to set all of the parameters, and not a separate method or property for each? It seems to me that this would make them easier to discover, especially with tab-completion. Is there a significant memory cost to this? |
A while back, and after much discussion at both PyCon UK and on the mailing list, it was decided to use just method for the microbit related work. BBC based evidence suggested kids found these easier to understand and work with. Personally, I was on the "we should use properties, when they make sense" side of the fence but respect the decision of the group. It's evidence based, brings a certain consistency to things, and we've not had any feedback to the contrary of our decision except from programmers occasionally asking why we don't use properties. 😄 The micro:bit is but a first step. Those that take to it will dive into "wider" Python when given the chance. :-) |
This documentation is ready to be proof-read and (hopefully) merged ASAP. It includes two additions to the docs:
Happy to make modifications. |
radio.rst | ||
random.rst | ||
spi.rst | ||
uart.rst |
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.
Why are random, spi and uart now included twice?
OK... corrections and spelling mistakes sorted (it actually said "the best way to receive a massage" in the tutorial). :-) Merge it! |
READY TO PROOF READ / MERGE
A "straw man" for the new
radio
module. Please annotate, comment and correct. Some of the details may need checking since this was written on a train so some of the specifications about the capabilities of the radio were from memory.I'm not precious about any of the text I've written, so please be merciless. ;-)
Once we're happy with the API we can massage @dpgeorge's code found in #245.