-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
drivers/wireless: Add support for the RN903 and RN2483 LoRa modules #15828
base: master
Are you sure you want to change the base?
Conversation
[Experimental Bot, please feedback here] Yes, this PR appears to meet the NuttX requirements, although there's room for improvement in the level of detail provided. Strengths:
Areas for Improvement:
Specific Recommendations:
By addressing these points, the PR will be even stronger and provide reviewers with all the necessary information to efficiently evaluate the changes. |
Thanks @linguini1! I suggest we rename the PR Title to "drivers/wireless: Add support for..."? So it looks nicer in the NuttX Release Notes :-) https://nuttx.apache.org/releases/12.8.0/ |
Hi, do you plans to port to STM32WL55 ? |
If that MCU is supported by NuttX, then this driver should work on it. This is a generic driver that should work with any UART interface. |
SX1262 ? |
If NuttX supports the STM32WL55, so long as you connect the RN2xx3 to a UART interface on that chip, you can use this driver with that chip running NuttX. This driver is not for the SX1262. It appears that the WL55 is supported so this driver could be used on that chip. |
d8c2055
to
d9f6ca3
Compare
* | ||
****************************************************************************/ | ||
|
||
static ssize_t read_line(FAR struct rn2xx3_dev_s *priv, FAR char *buf, |
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.
Something still does not quite sit right here with me. You implicitly trust in data returned from the modem.
Can modem send more than 2 lines at a time? Can your driver lead to situation where 2 lines are in uart buffer? What will happend when there are 2 lines in buffer (like 10 char long) and you call it with nbytes == 15
? You will read half of line, and next call will return invalid data.
Second case, what if line in uart buffer is longer than nbytes
? You again will read half of frame - and report success, so at least 2 consecutive calls will return invalid data. I think you should sanitize received frame here to line level. If you did not read whole line, return -1, and discard from uart buffer until you reach \n
.
I think you should implement small (at least 2 times the maximum size of single line modem can throw at you) ring buffer here and use that to read data. You can then call file_read
when buffer gets empty to fill it back in.
Otherwise you will be returning invalid data to userspace.
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.
Thank you for the catch on this case. I have resolved case 2. However, in regards to case 1, no it is not possible with this driver for 2 lines to be present in the UART buffer. All commands to the modem are call/response, and before each call/response sequence I flush the UART buffer to make sure there is no lingering data that will interrupt the regular flow. The modem cannot send more than one line at a time, unless I deliberately issue more than one command at a time.
d9f6ca3
to
9898258
Compare
9898258
to
01adeb5
Compare
include/nuttx/wireless/ioctl.h
Outdated
#define WLIOC_SETSPREAD _WLCIOC(0x0009) /* arg: Pointer to uint8_t, */ | ||
/* spread factor */ | ||
#define WLIOC_GETSPREAD _WLCIOC(0x000a) /* arg: Pointer to uint8_t, */ | ||
/* spread factor */ | ||
#define WLIOC_GETSNR _WLCIOC(0x000b) /* arg: Pointer to int8_t, */ | ||
/* signal to noise ratio */ | ||
#define WLIOC_SETPRLEN _WLCIOC(0x000c) /* arg: uint16_t, */ | ||
/* preamble length */ | ||
#define WLIOC_GETPRLEN _WLCIOC(0x000d) /* arg: Pointer to uint16_t, */ | ||
/* preamble length */ | ||
#define WLIOC_SETMOD _WLCIOC(0x000e) /* arg: enum, */ | ||
/* modulation type */ | ||
#define WLIOC_GETMOD _WLCIOC(0x000f) /* arg: char[10] pointer, */ | ||
/* modulation type */ |
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 we reuse some of sx127x commands ? (include/nuttx/wireless/lpwan/sx127x.h
)
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 thing is that they are all called SX127XIOC_*
. I think that would look confusing to be used on the RN2xx3. That's why I don't think there really should be different naming for "device specific" ioctl commands since they can be re-used by other devices that way.
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.
If desired I could also convert the SX127X commands to general WLIOC commands? That way any module can use them since there would be some sharing between it and the rn2xx3?
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.
If desired I could also convert the SX127X commands to general WLIOC commands? That way any module can use them since there would be some sharing between it and the rn2xx3?
Yes, I think this is the correct way. When I created the sx127x driver there was no other chips for Lora available, now there is much more chips supporting Lora, so some of these should be moved to common ioctl.
Ideally, we should be able to use different Lora chips with the same code.
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.
My thought to implement this would be a separate PR after this merged. I would replace all the SX127 commands with WLIOC commands, just by modifying the #define
statements to be WLIOC commands under a different name. That would avoid breaking some user code. Do you think this is worthwhile or should we just remove the device specific commands entirely since some of the arguments would change?
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.
Yeah i also was thinking of just keeping the old SX127 ones. But turn them into macros that are actually the (to be added) common WLIOC when expanded. No need to go over existing boards using this driver.
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.
personally I'm not a fan of keeping unnecessary legacy code that is trivial to fix on the user side. If there is someone who uses sx127x and thinks we should keep legacy ioctl then ok. If I was the only user of sx127x then I have nothing against breaking change here.
* | ||
****************************************************************************/ | ||
|
||
static int8_t rn2903_txpwrlevel(FAR float *dbm) |
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.
are floats really required here? it's not friendly for MCU without FPU. You should avoid floats in shared code and use something more universal if possible, like fixedmath.h
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 feel like this is more intuitive than fixed math. Is it really that unfriendly for MCUs without an FPU? It is just used in a comparison.
|
||
case WLIOC_SETTXPOWER: | ||
{ | ||
FAR float *txpwr = (FAR float *)(arg); |
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 is wrong, should be int32_t:
#define WLIOC_SETTXPOWER _WLCIOC(0x0005) /* arg: Pointer to int32_t, */
/* output power (in dBm) */
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.
How should I reflect fractional output power? I.e. something like 14.7dBm cannot be represented with an int32_t of units dBm.
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.
Yeah, this one is problematic. How bad would it be for it to NOT use fractional? Setting TX power to 15dBm instead of 14.7dBm?
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.
Yeah, this one is problematic. How bad would it be for it to NOT use fractional? Setting TX power to 15dBm instead of 14.7dBm?
In my case I don't believe it would be possible. For instance, some of the valid txpower levels that can be set for the RN2483 are -1.9, -1.7, -0.6, 0.4, 1.4 dBm. If -2 is passed as an int32_t parameter, I won't know to set -1.9 or -1.7. If -1 is passed, should it be -0.6 or -1.7?
These transceivers only support some specific levels as well, so my idea was to return back within the pointer the true dBm txpower that was set so the user is aware of any deviations from their specified level. It isn't possible to do that with an int32_t either. I think it might be wise to expand the command parameter to a float, as I'm sure this is not the only module that will have these issues.
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 would be extremely careful when changing type to float. While beneficial in this case you will break all userspace programs that are using this. I would suggest to add new request WLIOC_SETTXPOWERF
and add a thin wrapper to common code for WLIOC_SETTXPOWER
, that when called will convert int to float and call WLIOC_SETTXPOWERF
.
Ideally you would also change all driver code that use WLIOC_SETTXPOWER
to actually use WLIOC_SETTXPOWERF
instead. That way backward compatibility would be maintained with single function that should never see the need to be modified.
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.
maybe we have someone experienced in RF who could comment on which unit makes the most sense. Personally, I have not encountered increment smaller than 0.1 dBm. 0.01 dBm is such a small quantity that most likely is not usable in real-life radio applications
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 is indeed a very insignificant unit at lower powers. However, if you go to many dBms, it becomes more and more significant if you convert it to watts. 10dBm=10mW, 20dBm=100mW, 30dBm=1W, 40dBm=10W, 50dBm=100W. But its up to us to decide whether it makes sense to use 100W LoRa... since usually you are limited, even legally to 500mW.
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.
Also to add more to the insignificance. Even if you theoretically could adjust per 0.1dBm, multipath, fading and other RF interfering factors would make such tiny adjustments useless. But considering we got 32bit... 0.01dBm is probably more than enough 🤔
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.
Okay, I can implement this using 0.01dBm then? I will open another PR afterwards to correct the other drivers which use this command to use the updated units, since it appears the sentiment is that this would be okay.
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.
honestly, sounds good to me.
01adeb5
to
ff675e1
Compare
radio transceivers. This initial support includes transmit and receive functionality and configuration and reading of radio parameters like frequency and bandwidth. Signed-off-by: Matteo Golin <[email protected]>
ff675e1
to
88b47b5
Compare
I think we should put some effort into the common API for LORA chips. Here is another PR with LORA chip #15795 and it would be good if all LORA chips use the same API. I don't know if it's even possible because I'm not familiar with these chips, but we want to avoid a situation like in legacy sensors where each sensor has a different interface. This'll most likely introduce some breaking changes for sx127xx but it's fully justified. |
I support this idea |
I like this idea as well. I believe the RN2XX3 chips both use an SX* chip under the hood, they just come with the impedance matching network and an MCU for handling the UART interface and LoRaWAN stuff. I think all the new WLIOC commands introduced in this PR should be compatible with the other PR for that reason. However, I do think introducing this new API requires some conversation and work with many other developers. This seems outside the scope of this PR. Would that delay the merge of this PR or would it be something implemented afterward as a work in progress? |
what about marking this driver as EXPERIMENTAL? to make it clear that in the future there may be some breaking changes in the API |
Good idea. The same can be done to my pr. |
Sure, I'll mark this in the docs and code comments. |
Summary
Add support for the RN903 and RN2483 family of LoRa radio transceivers. This initial support includes transmit and receive functionality and configuration and reading of radio parameters like frequency and bandwidth.
Impact
NuttX users can now use these radio transceivers!
This changes touches the build system, wireless drivers and documentation. The documentation includes examples of how to use the driver and its available commands.
Testing
Testing was performed from an RP2040 based custom flight computer. The chip this code was tested again was the RN2903, but commands for both modules are the same. The only difference is the values allowed for each command, but the radio module does its own error checking so the driver code will not need to change between modules.
The test script that was used to test the commands was:
The output is:
I also performed transmit/receive testing using a second RN2903 which I used to transmit/receive from a Python script. I was able to successfully receive messages sent from the NuttX driver, and I was also able to successfully receive messages with the NuttX driver sent from the Python script controlled transceiver.
The code works with
read/write
functions, so it can beecho
ed into orcat
ted from to transmit and receive in the shell.Documentation was built locally and verified for correct render in the browser.