Skip to content

drivers/rn2xx3: basic initial implementation (without netdev)#7505

Merged
kaspar030 merged 2 commits intoRIOT-OS:masterfrom
aabadie:driver_lorabee
Jan 18, 2018
Merged

drivers/rn2xx3: basic initial implementation (without netdev)#7505
kaspar030 merged 2 commits intoRIOT-OS:masterfrom
aabadie:driver_lorabee

Conversation

@aabadie
Copy link
Copy Markdown
Contributor

@aabadie aabadie commented Aug 23, 2017

This PR adds basic support for the LoRaBee device based on Microchip RN2483 or RN2903 LoRa modules.

Those modules provides a full LoRaMAC stack + basic LoRa/FSK radio capacities that can be controlled using an UART interface. This is a bit similar to the XBee except that it doesn't use AT commands. Here the commands are sent in text mode and data using their hexadecimal representation.

For the moment, this driver provides a very simple API to initialize the device and methods to send text commands on the UART and wait for network replies.
There's also a test application that provides 3 shells commands: sys, mac, radio. One can directly use them as described in the command reference document: RN2483, RN2903.

My setup for testing is: Arduino-zero + Arduino wireless shield + LoRaBee. One can also use Nucleo144 boards and maybe other Arduino compatible boards.

Future improvements required (in follow-up PRs):

  • Better integrate into netdev
  • Auto init with default parameters (deveui, appeui, appkey, etc)
  • ifconfig integration

Since my module comes from Sodaq, maybe @keestux will be able to test this PR ;)

Depends on #7592

@aabadie aabadie added Area: drivers Area: Device drivers Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Aug 23, 2017
@aabadie aabadie added this to the Release 2017.10 milestone Aug 23, 2017
@miri64
Copy link
Copy Markdown
Member

miri64 commented Aug 23, 2017

Why didn't you use #7084 for this?

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Aug 23, 2017

Why didn't you use #7084 for this?

because the module is not controlled by AT commands...

@aabadie aabadie added the Area: network Area: Networking label Aug 23, 2017
@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Aug 24, 2017

@miri64, I had a look at #7084 and maybe I can reuse things (especially isrpipe, expected replies, timeouts, etc) but it's very related to AT commands behavior. Maybe it can be even more generalized ?

@miri64
Copy link
Copy Markdown
Member

miri64 commented Aug 24, 2017

Ah okay, I just saw device controlled via UART and thought they were AT commands, so nvm. But looking at the code again in more detail: why are you controlling the device purely via the shell? Wouldn't something similar to the xbee driver be better suited?

@miri64
Copy link
Copy Markdown
Member

miri64 commented Aug 24, 2017

(don't get me wrong: as a proof-of-concept this is awesome, but for long-term integration I prefer you to go direct to netdev and not just in future PRs).

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Aug 24, 2017

why are you controlling the device purely via the shell?

It was faster to implement and smaller changes. I wanted to have other people opinion on it before going further.

Wouldn't something similar to the xbee driver be better suited?

The module behaves differently. I guess I can take inspiration on the state machine, provide an API similar to schedule sx127x for radio level and an API for Mac layer.

@miri64
Copy link
Copy Markdown
Member

miri64 commented Aug 24, 2017

The module behaves differently. I guess I can take inspiration on the state machine, provide an API similar to schedule sx127x for radio level and an API for Mac layer.

Well ideally it should implement netdev ;-)

* @param[in] cmd Command to send as string
*
* @return LORABEE_OK on success
* @return -LORABEE_ERR_INVALID_PARAM if command is invalid
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not avoid the minus here (and in _parse_response) and make the enum values explicit negative?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

because I don' t have to explicitly set a value to all enum values. I don't know what's best I admit.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But then I have to ask, why do you need negative numbers at all? Why not just compare for != OK when you want to know if there is an error (instead of looking for negative numbers)?

return 0;
}

int lorabee_write_cmd(lorabee_t *dev, uint8_t *cmd)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd prefer that cmd is a const char*. Every command you send to the RN device is ASCII. No need to pretend it can be binary too. Only where uart_write is being called you need a type cast.

/* buffer and synchronization for command responses */
mutex_t resp_lock; /**< mutex for waiting for command
* response */
uint8_t resp_buf[LORABEE_MAX_MSG_LENGTH]; /**< command response data buffer */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not make this a char[] array. We're only expecting ASCII, don't we?

return;
}
else {
dev->resp_buf[dev->resp_size++] = c;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Buffer overflow protection ??

}

if (lorabee_write_cmd(dev, (uint8_t*)"") < 0) {
return -1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not pass back the error cause?

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Aug 25, 2017

@keestux, thanks for having a look. I think I addressed most of your comment. The uint8_t => char conversion was indeed a pain and is now fixed.

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Aug 28, 2017

@keestux, I updated the PR with a better error management (like you suggested).

You remark regarding the Sodaqone board makes me wonder if it wouldn't be better to call this driver rn2xx3 (for rn2483 and rn2903) instead of lorabee. This is because the microchip module can be used directly on a board and not via a Bee-like pinout. What do you think ?

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Sep 1, 2017

There are quite a few LoRaBee-like modules on the market, the RN2483/RN2903 is one of them. They are all controller by UART but with different commands. The one here uses a kind of custom ascii commands, the others I saw are controlled with AT commands. These ones will be good candidates for #7084 (here and here).

I renamed the driver in this PR to rn2xx3 since it supports rn2483 and rn2903 modules.

@aabadie aabadie changed the title drivers/lorabee: basic initial implementation drivers/rn2xx3: basic initial implementation Sep 1, 2017
@aabadie aabadie force-pushed the driver_lorabee branch 2 times, most recently from aec9024 to fd5ff96 Compare September 6, 2017 15:56
@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 9, 2018

Also I removed the netdev/netopt related part and will open a PR based on this one later.

Copy link
Copy Markdown
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

minors


#if ENABLE_DEBUG
/* we are interested by the debug message in the sleep timer callback */
#define ISR_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Setting this here doesn't change the ISR stacksize

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

what's the best place for this then ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No good place for this. But here it is useless. :)
Maybe a warning comment before the debug.h include is better?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added a comment explaining how to set it via CFLAGS (untested). So not sure if it works or not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tested this morning and modifying the ISR_STACKSIZE has no effect because the debug message is displayed from the idle thread. Modifying THREAD_STACKSIZE_IDLE using CFLAGS works. I updated the comment accordingly.


#define RESP_TIMEOUT_SEC (5U)

const char * closing_seq = "\r\n";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

static?

};
}

void rn2xx3_bytes_to_hex(const uint8_t *byte_array, char *hex, uint8_t max_len)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use fmt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I already read that somewhere ;)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@kaspar030 I opened a PR for fmt: #8343

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

adapted using the fmt functions.

int rn2xx3_cmd_finalize(rn2xx3_t *dev)
{
DEBUG("\n");
_uart_write_str(dev, "\r\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use closing_seq?

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 12, 2018

@smlng @kaspar030 do you still have comments ?
@kYc0o can you confirm that it works for you ?

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Jan 12, 2018

ACK

/**
* @brief Command responses and server replies status codes
*/
enum {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks better now, but you still mix error codes, replies, and others - I would recommend to order/group them, i.e.,

enum {
    RN2XX3_OK,
    RN2XX3_DATA,
    RN2XX3_TIMEOUT,
    RN2XX3_ERR_MAC_INIT,
    /* all other err codes ... */
    RN2XX3_REPLY_TX_MAC_OK,
    /* all other reply codes ... */
}

* @param[out] dev RN2XX3 device to initialize
* @param[in] params parameters for device initialization
*/
void rn2xx3_setup(rn2xx3_t *dev, const rn2xx3_params_t *params);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

okay


/* initialize buffers and locks*/
dev->resp_size = 0;
dev->cmd_buf[0] = '\0';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit-picky: this is inconsistent with the rest of the code, where you set dev->cmd_buf[0] = 0;.

#define RN2XX3_FREQ_BAND (915U)
#endif

#if defined(MODULE_RN2483)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would make this an #if #elif #else for RN2XX3_FREQ_BAND, with an #error in the #else branch.

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 15, 2018

I just addressed your last comments @smlng

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 15, 2018

@aabadie: please squash. @kaspar030 please check if all comments are addressed, so we can get this into the release.

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 15, 2018

@smlng squashed and rebased

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 15, 2018

just missing your approval here @kaspar030 :)

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 16, 2018

ping @kaspar030. After that, it will be straight forward to extend the support of the Sodaq ExpLoRer board with LoRa (see #7733, that needs a small update btw)

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 16, 2018

just wanted to raise this one again, it's ready to be merged.

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 16, 2018

it's still on the list for the release, I'll look into it tomorrow but don't have the hardware, to no testing.

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 16, 2018

@kaspar030 please check if your comments are sufficiently addressed, thx!

Copy link
Copy Markdown
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

some more things.

Please ignore my doxygen indentation comments, while the indentation is a bit off-standard, at least it is consistent.

/**
* @brief RN2483/RN2903 device descriptor
*/
typedef struct {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This struct is massive... And it wastes quite some memory on bad ordering. But I'm ok with improving later.

*
* @return RN2XX3_OK on success
* @return -ENXIO if UART initialization failed
* @return RN2XX3_TIMEOUT if UART communcation failed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

communication

/**
* @brief Restarts the RN2XX2 device
*
* dev->resp_buf contains the module name and version string.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

indent off. Maybe "After calling this function, ..."?

* @brief Resets the module’s configuration data and user EEPPROM to factory
* default values and restarts the module
*
* dev->resp_buf contains the module name and version string.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

again

* @param[in] dev RN2XX3 device descriptor
*
* @return RN2XX3_OK on success
* @return RN2XX3_TIMEOUT if UART communcation failed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

here and below again communication ('i' missing)

ret = rn2xx3_process_response(dev);
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);

DEBUG("RET: %d, RESP: %s\n", ret, dev->resp_buf);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefix with [rn2xx3]?

{
char payload_str[2];
for (unsigned i = 0; i < payload_len; i++) {
fmt_bytes_hex(payload_str, &payload[i], 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wouldn't fmt_byte_hex() make more sense here?


rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);

DEBUG("RET: %d, RESP: %s\n", ret, dev->resp_buf);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefix?

rn2xx3_cmd_finalize(dev);

rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_MAC_TX);
uint8_t ret = rn2xx3_process_response(dev);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

fold this and the return?

@@ -0,0 +1,10 @@
APPLICATION = driver_rn2xx3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the include below sets this to tests_driver_rn2xx3, so remove?

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 17, 2018

@kaspar030, sorry for doxygen comments indentation, I prefer this because it's aligned with input/output parameters.

Otherwise, I addressed your comments, and fixed other spaces misplaced around *.

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 17, 2018

ping @kaspar030, lets get this done.

@kaspar030
Copy link
Copy Markdown
Contributor

sorry for doxygen comments indentation,

The coding conventions say "Line length: aim for no more than 80 characters per line, the absolute maximum should be 100 characters per line."

This PR has 60 lines over 80 characters. More than 50 of that are either @brief lines or have lots of whitespace (some >20) due to your alignment preferences.

I prefer this because it's aligned with input/output parameters.

If this would be "objective readability vs coding conventions", I wouldn't mind. But I think this is more "I prefer this vs. coding conventions".

Also, this PR's doxygen formatting is quite different than in other files.

I think we should go for consistency here...

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 18, 2018

@kaspar030, I updated the doxygen based on how this is already done in other drivers (Si70xx and At86RF2xx), it should be consistent now. I kept the line length below 100 (widest is 99)

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 18, 2018

@kaspar030 do you ACK ?

Copy link
Copy Markdown
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

ACK for the formal things (untested).

@kaspar030
Copy link
Copy Markdown
Contributor

Let's go!

@kaspar030
Copy link
Copy Markdown
Contributor

Gratulations for getting a quite large PR in! ;)

@aabadie
Copy link
Copy Markdown
Contributor Author

aabadie commented Jan 18, 2018

Many thanks @keestux, @smlng and @kaspar030 for the in-depth review and @kYc0o for your tests and advices!
By the way, now there's a sister PR ready: #7733

(edited: added Sebastian)

@aabadie aabadie mentioned this pull request Jan 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: drivers Area: Device drivers Area: LoRa Area: LoRa radio support Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants