-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
ADD: GNSS Driver for U-BLOX M10 & Support for UBX Messages #68350
ADD: GNSS Driver for U-BLOX M10 & Support for UBX Messages #68350
Conversation
25b7de2
to
7f35758
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.
I have quite a few requests, I have limited the review to the u_blox_protocol
related files for now to make it easier to attend to and/or discuss the comments :)
c651f00
to
0bfdf91
Compare
Hi @bjarki-trackunit, thank you for the review. I have addressed the comments. Kindly have a look at your convenience. |
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.
Looking good, a few more requests, and a question:
- Are the definitions in gnss_u_blox_protocol.h and .c generic, as in, match other ublox gnss than the m10?
Yes, they are generic to ublox gnss devices. For example, ublox Neo M8 (if implemented) would use them as well, without any change. Also, modem_ubx.c needs some macros in gnss_ublox_protocol.h, which is why I plan to transfer it to the include directory of gnss in the next commit. |
0bfdf91
to
9059d7b
Compare
Hi @bjarki-trackunit, thank you for the review. I have addressed the comments. Kindly have a look at your convenience. |
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.
Its getting there, but I'm not convinced on the responsibilities of ubx.h
and gnss_u_blox_protocol.h
, more on that in the comments :)
9059d7b
to
7372ac7
Compare
Hi @bjarki-trackunit, thank you for the review. I have addressed the comments. Kindly have a look at your convenience. |
7372ac7
to
5b203f7
Compare
Hi @bjarki-trackunit, I have addressed this comment - #68350 (comment). Kindly review at your convenience. Thank you. |
5b203f7
to
e28e0f8
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.
The code is looking really good, these (hopefully) last requests are quite minor, Nice work!
subsys/modem/modem_ubx.c
Outdated
} | ||
|
||
ubx->pipe = pipe; | ||
(void) modem_pipe_attach(ubx->pipe, modem_ubx_pipe_callback, ubx); |
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.
No need to denote (void) on functions which already return void :) usually it is only done to signal that the function does indeed return something, but it is intentionally ignored, like
(void)k_sem_take(&sem, K_FOREVER);
This is done quite a few places in the PR
include/zephyr/modem/ubx.h
Outdated
#define UBX_PAYLOAD_SZ_MAX 256 | ||
#define UBX_FRM_SZ_MAX UBX_FRM_SZ(UBX_PAYLOAD_SZ_MAX) | ||
|
||
struct ubx_frame_t { |
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 struct should be named struct ubx_frame
, _t
denotes that it is a typedef, like typedef ...
include/zephyr/modem/ubx.h
Outdated
struct ubx_frame_t *request; | ||
struct ubx_frame_t *response; | ||
struct ubx_frame_t *match; |
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 simply add a const pointer to the script here
const struct modem_ubx_script *script;
instead of copying the pointers from the script. The script and the buffers have the same lifetime so it is safe to do so :)
int ubx_create_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t message_class, | ||
uint8_t message_id, const void *data, uint16_t payload_size) | ||
{ | ||
if (ubx_validate_frame(ubx_frame_size, message_class, message_id, payload_size)) { | ||
return -1; | ||
} | ||
|
||
struct ubx_frame_t *frame = (struct ubx_frame_t *) ubx_frame; | ||
|
||
frame->preamble_sync_char_1 = UBX_PREAMBLE_SYNC_CHAR_1; | ||
frame->preamble_sync_char_2 = UBX_PREAMBLE_SYNC_CHAR_2; | ||
frame->message_class = message_class; | ||
frame->message_id = message_id; | ||
frame->payload_size_low = payload_size; | ||
frame->payload_size_high = payload_size >> 8; | ||
|
||
memcpy(frame->payload_and_checksum, (uint8_t *) data, payload_size); | ||
|
||
uint16_t ubx_frame_len = payload_size + UBX_FRM_SZ_WITHOUT_PAYLOAD; | ||
|
||
uint8_t ckA = 0, ckB = 0; | ||
|
||
for (unsigned int i = UBX_FRM_CHECKSUM_START_IDX; | ||
i < (UBX_FRM_CHECKSUM_STOP_IDX(ubx_frame_len)); i++) { | ||
ckA += ubx_frame[i]; | ||
ckB += ckA; | ||
} | ||
|
||
frame->payload_and_checksum[payload_size] = ckA; | ||
frame->payload_and_checksum[payload_size + 1] = ckB; | ||
|
||
return ubx_frame_len; | ||
} |
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 function belongs in modem_ubx.c, there is nothing in it specific to any payload, its just constructing a "generic" ubx frame :)
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.
Hi @bjarki-trackunit, I have moved this to modem_ubx.c
, but please note that payload size couldn't be validated in modem_ubx.c
because details regarding gnss ublox messages is concern of gnss_u_blox_protocol.c
. Hence, I have created a function in ubx_create_and_validate_frame
in gnss_u_blox_protocol.c
that validates the payload size then calls modem_ubx_create_frame
in modem_ubx.c
to create the frame. Please check if this is correct.
frame->payload_size_low = payload_size; | ||
frame->payload_size_high = payload_size >> 8; | ||
|
||
memcpy(frame->payload_and_checksum, (uint8_t *) data, payload_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.
This typecast is not required, memcpy already takes a const void *
, so this is typecasting const void *
-> uint8_t *
-> const void *
, which is probably why the compiler didn't freak out that you are casting const data to non-const data, which is not allowed :)
} | ||
|
||
int ubx_create_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t message_class, | ||
uint8_t message_id, const void *data, uint16_t payload_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.
The data
member should probalby be renamed payload
to match payload_size
subsys/modem/modem_ubx.c
Outdated
|
||
if (modem_ubx_match_frame_full(received, ubx->match) == true) { | ||
k_sem_give(&ubx->script_stopped_sem); | ||
ret = 0; /* Frame matched successfully. Terminate the script. */ |
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.
Please move the comment above and before what it describes occurs :)
/* Frame matched successfully. Terminate the script. */
k_sem_give(&ubx->script_stopped_sem);
ret = 0;
This is easier to follow, prescription then action
subsys/modem/modem_ubx.c
Outdated
ret = 0; /* Frame matched successfully. Terminate the script. */ | ||
} else if (modem_ubx_match_frame_type(received, ubx->request) == true) { | ||
memcpy(ubx->response, ubx->work_buf, ubx->work_buf_len); | ||
ret = -1; /* Response receveid successfully. Script not ended. */ |
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.
Same as above
460800, | ||
}; | ||
|
||
static int ubx_validate_frame(uint16_t ubx_frame_size, uint8_t message_class, uint8_t message_id, |
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 implementation of this function is quite hard to read with switches inside switches, and mixing returns and breaks a bit. I would suggest refactoring it so there is only one switch "level"/"indent" in each scope, like this:
static inline int ubx_validate_ack_frame(uint16_t ubx_frame_size, uint8_t message_class, uint8_t message_id, uint16_t payload_size)
{
switch (message_id) {
case UBX_ACK_ACK:
payload_size_expected = UBX_CFG_ACK_PAYLOAD_SZ;
break;
case UBX_ACK_NAK:
payload_size_expected = UBX_CFG_NAK_PAYLOAD_SZ;
break;
default:
break;
}
return -1;
}
switch (message_class) {
case UBX_CLASS_ACK:
return ubx_validate_ack_frame(...);
case UBX_CLASS_CFG:
return ubx_validate_cfg_frame(...);
default:
return -1;
}
The above code is only an example of course, but splitting it into static inline helpers helps keep the indentations low and code more readable :)
case UBX_CFG_MSG: | ||
payload_size_expected = UBX_CFG_MSG_PAYLOAD_SZ; | ||
break; | ||
default: return -1; |
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 personal preference, but switches especially should keep consistent indentation
default:
return -1;
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's in the coding style https://www.kernel.org/doc/html/v4.10/process/coding-style.html#indentation
Don’t put multiple statements on a single line unless you have something to hide
drivers/gnss/Kconfig.u_blox_m10
Outdated
select GNSS_U_BLOX_PROTOCOL | ||
select UART_USE_RUNTIME_CONFIGURE | ||
help | ||
Enable U-BLOX M10 GNSS modem 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.
nit: indentation is off
drivers/gnss/gnss_u_blox_m10.c
Outdated
.message_id = msg_id, | ||
}; | ||
|
||
(void) ubx_m10_modem_ubx_script_fill(dev); |
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.
(void) ubx_m10_modem_ubx_script_fill(dev); | |
(void)ubx_m10_modem_ubx_script_fill(dev); |
same for the rest of the file
drivers/gnss/gnss_u_blox_m10.c
Outdated
data->script.request = (struct ubx_frame_t *) data->request_buf; | ||
data->script.response = (struct ubx_frame_t *) data->response_buf; | ||
data->script.match = (struct ubx_frame_t *) data->match_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.
data->script.request = (struct ubx_frame_t *) data->request_buf; | |
data->script.response = (struct ubx_frame_t *) data->response_buf; | |
data->script.match = (struct ubx_frame_t *) data->match_buf; | |
data->script.request = (struct ubx_frame_t *)data->request_buf; | |
data->script.response = (struct ubx_frame_t *)data->response_buf; | |
data->script.match = (struct ubx_frame_t *)data->match_buf; |
drivers/gnss/gnss_u_blox_m10.c
Outdated
payload->config_blocks[index].flags = enable | | ||
UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L1C_A; |
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 correct? boolean | value? guess it's fine it just looks odd to me, maybe add a define for the enable/disable bit and use an intermediate variable or something, just for clarity
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.
Hi @fabiobaltieri, i have addressed this comment in the latest push. Kindly check if the resolution is correct.
}; | ||
|
||
enum ubx_utc_standard { | ||
UBX_UTC_AutoUTC = 0, |
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.
UBX_UTC_AutoUTC = 0, | |
UBX_UTC_AUTOUTC = 0, |
case UBX_CFG_MSG: | ||
payload_size_expected = UBX_CFG_MSG_PAYLOAD_SZ; | ||
break; | ||
default: return -1; |
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's in the coding style https://www.kernel.org/doc/html/v4.10/process/coding-style.html#indentation
Don’t put multiple statements on a single line unless you have something to hide
subsys/modem/modem_ubx.c
Outdated
#include <zephyr/logging/log.h> | ||
LOG_MODULE_REGISTER(modem_ubx, CONFIG_MODEM_MODULES_LOG_LEVEL); | ||
|
||
#define MODEM_UBX_STATE_ATTACHED_BIT (0) |
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.
#define MODEM_UBX_STATE_ATTACHED_BIT (0) | |
#define MODEM_UBX_STATE_ATTACHED_BIT 0 |
e28e0f8
to
cfb21fd
Compare
Hi @bjarki-trackunit and @fabiobaltieri, thank you for the review. I have addressed the latest comments. Kindly have a look at your convenience. |
cfb21fd
to
663b3b6
Compare
drivers/gnss/gnss_u_blox_m10.c
Outdated
/* The datasheet of the device doesn't specify boot time. But 1 sec helped significantly. */ | ||
#define UBX_M10_BOOT_TIME_MS 1000 | ||
|
||
enum MODEM_MODULE { |
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.
enum MODEM_MODULE { | |
enum modem_module { |
if you really want an enum here, though to me it looks like you could just replace this with a boolean and everything would be come a tiny bit simpler, do you forsee this getting more values in the future? The whole ubx_m10_modem_module_switch
just looks really really weird right now
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.
@fabiobaltieri We don't foresee more modem modules being used in this driver. We could utilize a boolean macro, but i thought enum improves readability. I would prefer an enum here, but if you want i will change this as you said.
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.
Ok, I think it should be changed, I mean this would maybe make sense if you wanted to do stuff like ubx_m10_modem_module_switch(MODEM_MODULE_CHAT, MODEM_MODULE_CHAT);
, it's just odd to have an enum for what is effectively a boolean and having having switch with default statement and error path for what should just be a if
. @bjarki-trackunit?
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.
Yes @fabiobaltieri, I understand your point now. Passing two arguments to ubx_m10_modem_module_switch
isn't required. Would the following work?
/**
* @brief Changes modem module (chat or ubx) attached to the uart pipe.
* @param dev Dev instance
* @param change_from_to 0 for changing from "chat" to "ubx", 1 for changing from "ubx" to "chat"
* @returns 0 if successful
* @returns negative errno code if failure
*/
static int ubx_m10_modem_module_change(const struct device *dev, bool change_from_to)
{
struct ubx_m10_data *data = dev->data;
int ret;
if (change_from_to == 0) {
modem_chat_release(&data->chat);
ret = modem_ubx_attach(&data->ubx, data->uart_pipe);
} else { /* change_from_to == 1 */
modem_ubx_release(&data->ubx);
ret = modem_chat_attach(&data->chat, data->uart_pipe);
}
if (ret < 0) {
(void)modem_pipe_close(data->uart_pipe);
}
return ret;
}
Ps. I would prefer an enum here (or a couple of macros). Because without these, while calling ubx_m10_modem_module_change
, we have to pass a literal. For now I have pushed the changes as per your comments.
enum modem_module_change {
MODEM_MODULE_CHAT_TO_UBX = 0,
MODEM_MODULE_UBX_TO_CHAT = 1,
};
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 could just call release followed by attach. not sure a helper function is required for this :) I would create two helpers named switch_to_chat and switch_to_ubx, instead of passing arguments to a single function :)
7845805
to
da39d63
Compare
Hi @fabiobaltieri, thank you for the review. I have addressed the comments. |
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.
Heya, just a comment on definitions, sorry I think I asked you to drop the parenthesis to the literal ones before, I meant to ask that only for definitions with a single literal, the others should have them otherwise weird things can happen depending on how they are used.
#define UBX_CFG_NAK_PAYLOAD_SZ 2 | ||
#define UBX_CFG_RATE_PAYLOAD_SZ 6 | ||
#define UBX_CFG_PRT_POLL_PAYLOAD_SZ 1 | ||
#define UBX_CFG_PRT_POLL_FRM_SZ UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_PRT_POLL_PAYLOAD_SZ |
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 and the other defines with operations should be parenthesized, just to be sure there's no hidden operation priority errors
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_1 0U | ||
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_1_HALF BIT(12) | ||
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_2 BIT(13) | ||
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_HALF BIT(12) | BIT(13) |
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.
same for this one, just the ones with multiple operands
#define UBX_CFG_GNSS_FLAG_DISABLE 0U | ||
#define UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT 16 | ||
/* When gnss_id is 0 (GPS) */ | ||
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L1C_A 0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT |
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.
same
MODEM_UBX: Adds Support for UBX Messages in Modem Subsystem. GNSS API Supported: get_supported_systems, set_fix_rate, get_fix_rate, set_enabled_systems, get_enabled_systems, set_navigation_mode, get_navigation_mode. Boards Tested: MIMXRT1062_FMURT6, VMU_RT1170. Note: Partial support for U-BLOX Messages is provided as of now. Signed-off-by: Sumit Batra <sumit.batra@nxp.com> Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
da39d63
to
1be3a1d
Compare
Hi @fabiobaltieri, appreciate the review. I have addressed the comments. Kindly check at your convenience. |
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.
Nice work!
I know I'm a few months late here, but I'm curious how this works given that the Ublox protocol used on the M10 chipsets no longer support the old dedicated The following struct for example no longer exists in the M10 interface description: zephyr/drivers/gnss/gnss_u_blox_protocol/gnss_u_blox_protocol.h Lines 62 to 66 in 2e01266
|
Hi @JordanYates, thank you for the comment. I will look into this and get back to you soon. |
MODEM_UBX: Adds Support for UBX Messages in Modem Subsystem.
GNSS API Supported: get_supported_systems, set_fix_rate, get_fix_rate,
set_enabled_systems, get_enabled_systems, set_navigation_mode,
get_navigation_mode.
Boards Tested: MIMXRT1062_FMURT6, VMU_RT1170.
Note: Partial support for U-BLOX Messages is provided as of now.
Signed-off-by: Sumit Batra sumit.batra@nxp.com
Signed-off-by: Mayank Mahajan mayankmahajan.x@nxp.com