Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/sensor/sensirion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0

# zephyr-keep-sorted-start
add_subdirectory(common)
add_subdirectory_ifdef(CONFIG_SCD4X scd4x)
add_subdirectory_ifdef(CONFIG_SGP40 sgp40)
add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd)
Expand Down
2 changes: 1 addition & 1 deletion drivers/sensor/sensirion/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2025 Sensirion
# Copyright (c) 2026 Sensirion
#
# SPDX-License-Identifier: Apache-2.0
#
Expand Down
26 changes: 14 additions & 12 deletions drivers/sensor/sensirion/common/conversions.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
* Copyright (c) 2025 Sensirion
* Copyright (c) 2026 Sensirion
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "conversions.h"

float sensirion_common_bytes_to_float(const uint8_t *bytes)
float sensirion_conversions_bytes_to_float(const uint8_t *bytes)
{
union {
uint32_t u32_value;
Expand All @@ -17,7 +17,7 @@ float sensirion_common_bytes_to_float(const uint8_t *bytes)
return tmp.float32;
}

void sensirion_common_float_to_bytes(const float value, uint8_t *bytes)
void sensirion_conversions_float_to_bytes(const float value, uint8_t *bytes)
{
union {
uint32_t u32_value;
Expand All @@ -27,19 +27,21 @@ void sensirion_common_float_to_bytes(const float value, uint8_t *bytes)
sys_put_be32(tmp.u32_value, bytes);
}

void sensirion_common_to_integer(const uint8_t *source, uint8_t *destination, INT_TYPE int_type,
uint8_t data_length)
void sensirion_conversions_to_integer(const uint8_t *source, uint8_t *destination,
size_t destination_size, uint8_t data_length)
{
if (data_length > int_type) {
data_length = int_type;
if (data_length > destination_size) {
data_length = destination_size;
}
// set all bytes in destination to 0 to make sure that the value is correct even if the data_length is smaller than the size of the integer type
/* set all bytes in destination to 0 to make sure that the value is correct even if the
* data_length is smaller than the size of the integer type */
memset(destination, 0, data_length);
uint8_t offset = int_type - data_length;

// copy the bytes from source to destination. The source is in big-endian/MSB-first format, so the first byte of the source is the most significant byte.
// The destination should be filled in the correct order for the system endianness.
/* copy the bytes from source to destination. The source is in big-endian/MSB-first format,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we have to consider the byte order of the host. In case the host has the same byte order (BE) this code is wrong.
I'm aware that his is also the case for the code we have in sensirion_common :-(

* so the first byte of the source is the most significant byte. The destination should be
* filled in the correct order for the system endianness.
*/
for (uint8_t i = 1; i <= data_length; i++) {
destination[int_type - offset - i] = source[i - 1];
destination[data_length - i] = source[i - 1];
}
}
24 changes: 12 additions & 12 deletions drivers/sensor/sensirion/common/conversions.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Sensirion
* Copyright (c) 2026 Sensirion
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -29,11 +29,11 @@ extern "C" {
* conversions from byte arrays to basic data types.
* Since Zephyr does not provide a function for converting big-endian
* (MSB-first) byte arrays to floating-point values, the function
* sensirion_common_bytes_to_float() is
* sensirion_conversions_bytes_to_float() is
* provided for this purpose.
* To maintain a consistent naming scheme for all functions that convert byte
* arrays to basic types, the functions
* sensirion_common_bytes_to_<integer>() are also provided,
* sensirion_conversions_bytes_to_<integer>() are also provided,
* even in cases where Zephyr already provides equivalent functions for
* specific integer
* types.
Expand All @@ -49,14 +49,14 @@ extern "C" {
* @param bytes An array of at least four bytes (MSB first)
* @return The byte array represented as float
*/
float sensirion_common_bytes_to_float(const uint8_t *bytes);
float sensirion_conversions_bytes_to_float(const uint8_t *bytes);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

could also be const uint8_t const*


#define sensirion_common_bytes_to_int16_t(bytes) ((int16_t)sys_get_be16(bytes))
#define sensirion_common_bytes_to_uint16_t(bytes) ((uint16_t)sys_get_be16(bytes))
#define sensirion_common_bytes_to_int32_t(bytes) ((int32_t)sys_get_be32(bytes))
#define sensirion_common_bytes_to_uint32_t(bytes) ((uint32_t)sys_get_be32(bytes))
#define sensirion_common_bytes_to_int64_t(bytes) ((int64_t)sys_get_be64(bytes))
#define sensirion_common_bytes_to_uint64_t(bytes) ((uint64_t)sys_get_be64(bytes))
#define sensirion_conversions_bytes_to_int16_t(bytes) ((int16_t)sys_get_be16(bytes))
#define sensirion_conversions_bytes_to_uint16_t(bytes) ((uint16_t)sys_get_be16(bytes))
#define sensirion_conversions_bytes_to_int32_t(bytes) ((int32_t)sys_get_be32(bytes))
#define sensirion_conversions_bytes_to_uint32_t(bytes) ((uint32_t)sys_get_be32(bytes))
#define sensirion_conversions_bytes_to_int64_t(bytes) ((int64_t)sys_get_be64(bytes))
#define sensirion_conversions_bytes_to_uint64_t(bytes) ((uint64_t)sys_get_be64(bytes))

/** @} */

Expand All @@ -77,8 +77,8 @@ float sensirion_common_bytes_to_float(const uint8_t *bytes);
* @param destination_size Size of the destination integer in bytes.
* @param data_length Number of available bytes in source to copy.
*/
void sensirion_common_to_integer(const uint8_t *source, uint8_t *destination,
size_t destination_size, uint8_t data_length);
void sensirion_conversions_to_integer(const uint8_t *source, uint8_t *destination,
size_t destination_size, uint8_t data_length);

#ifdef __cplusplus
}
Expand Down
9 changes: 9 additions & 0 deletions drivers/sensor/sensirion/common/i2c_general_call_reset.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright (c) 2026 Sensirion
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "i2c_general_call_reset.h"
#include <zephyr/device.h>

int sensirion_i2c_general_call_reset(const struct i2c_dt_spec *i2c_spec)
{
const uint8_t data = 0x06;
Expand Down
124 changes: 72 additions & 52 deletions drivers/sensor/sensirion/common/i2c_packet.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Sensirion
* Copyright (c) 2026 Sensirion
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -10,140 +10,160 @@
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/crc.h>

#define SENSIRION_WORD_SIZE 2u
#define SENSIRION_CRC8_LEN 1u

#define SENSIRION_WORD_SIZE 2
#define SENSIRION_CRC8_LEN 1


uint8_t sensirion_i2c_packet_get_crc(const i2c_packet *packet, uint16_t index)
uint8_t sensirion_i2c_packet_get_crc(const i2c_packet_t *i2c_packet, uint16_t index)
{
return crc8(&packet->data[index], SENSIRION_WORD_SIZE,
packet->crc8_poly, packet->crc8_init, false);
return crc8(&i2c_packet->data[index], SENSIRION_WORD_SIZE, i2c_packet->crc8_poly,
i2c_packet->crc8_init, false);
}

bool sensirion_i2c_packet_check_crc(const i2c_packet *packet, uint16_t index)
bool sensirion_i2c_packet_check_crc(const i2c_packet_t *i2c_packet, uint16_t index)
{
if (sensirion_i2c_packet_get_crc(packet, index) != packet->data[index + SENSIRION_WORD_SIZE]) {
if (sensirion_i2c_packet_get_crc(i2c_packet, index) !=
i2c_packet->data[index + SENSIRION_WORD_SIZE]) {
return false;
}
return true;
}



uint16_t sensirion_i2c_packet_add_command16(i2c_packet *packet, uint16_t offset, uint16_t command)
uint16_t sensirion_i2c_packet_add_command16(i2c_packet_t *i2c_packet, uint16_t offset,
uint16_t command)
{
sys_put_be16(command, &packet->data[offset]);
sys_put_be16(command, &i2c_packet->data[offset]);
offset += 2;
return offset;
}

uint16_t sensirion_i2c_packet_add_command8(i2c_packet *packet, uint16_t offset, uint8_t command)
uint16_t sensirion_i2c_packet_add_command8(i2c_packet_t *i2c_packet, uint16_t offset,
uint8_t command)
{
packet->data[offset++] = command;
i2c_packet->data[offset++] = command;
return offset;
}

uint16_t sensirion_i2c_packet_add_uint64_t(i2c_packet *packet, uint16_t offset, uint64_t data)
uint16_t sensirion_i2c_packet_add_uint64_t(i2c_packet_t *i2c_packet, uint16_t offset, uint64_t data)
{
offset = sensirion_i2c_packet_add_uint32_t(packet, offset, data >> 32);
offset = sensirion_i2c_packet_add_uint32_t(packet, offset, data & 0xFFFFFFFF);
offset = sensirion_i2c_packet_add_uint32_t(i2c_packet, offset, data >> 32u);
offset = sensirion_i2c_packet_add_uint32_t(i2c_packet, offset, data & 0xFFFFFFFFu);
return offset;
}

uint16_t sensirion_i2c_packet_add_int64_t(i2c_packet *packet, uint16_t offset, int64_t data)
uint16_t sensirion_i2c_packet_add_int64_t(i2c_packet_t *i2c_packet, uint16_t offset, int64_t data)
{
return sensirion_i2c_packet_add_uint64_t(packet, offset, (uint64_t)data);
return sensirion_i2c_packet_add_uint64_t(i2c_packet, offset, (uint64_t)data);
}

uint16_t sensirion_i2c_packet_add_uint32_t(i2c_packet *packet, uint16_t offset, uint32_t data)
uint16_t sensirion_i2c_packet_add_uint32_t(i2c_packet_t *i2c_packet, uint16_t offset, uint32_t data)
{
offset = sensirion_i2c_packet_add_uint16_t(packet, offset, data >> 16);
offset = sensirion_i2c_packet_add_uint16_t(packet, offset, data & 0xFFFF);
offset = sensirion_i2c_packet_add_uint16_t(i2c_packet, offset, data >> 16u);
offset = sensirion_i2c_packet_add_uint16_t(i2c_packet, offset, data & 0xFFFFu);

return offset;
}

uint16_t sensirion_i2c_packet_add_int32_t(i2c_packet *packet, uint16_t offset, int32_t data)
uint16_t sensirion_i2c_packet_add_int32_t(i2c_packet_t *i2c_packet, uint16_t offset, int32_t data)
{
return sensirion_i2c_packet_add_uint32_t(packet, offset, (uint32_t)data);
return sensirion_i2c_packet_add_uint32_t(i2c_packet, offset, (uint32_t)data);
}

uint16_t sensirion_i2c_packet_add_uint16_t(i2c_packet *packet, uint16_t offset, uint16_t data)
uint16_t sensirion_i2c_packet_add_uint16_t(i2c_packet_t *i2c_packet, uint16_t offset, uint16_t data)
{
sys_put_be16(data, &packet->data[offset]);
sys_put_be16(data, &i2c_packet->data[offset]);
offset += 2;
if (packet->crc8_poly != 0) {
packet->data[offset] = sensirion_i2c_packet_get_crc(packet, offset - SENSIRION_WORD_SIZE);
if (i2c_packet->crc8_poly != 0) {
i2c_packet->data[offset] =
sensirion_i2c_packet_get_crc(i2c_packet, offset - SENSIRION_WORD_SIZE);
offset++;
}
return offset;
}

uint16_t sensirion_i2c_packet_add_int16_t(i2c_packet *packet, uint16_t offset, int16_t data)
uint16_t sensirion_i2c_packet_add_int16_t(i2c_packet_t *i2c_packet, uint16_t offset, int16_t data)
{
return sensirion_i2c_packet_add_uint16_t(packet, offset, (uint16_t)data);
return sensirion_i2c_packet_add_uint16_t(i2c_packet, offset, (uint16_t)data);
}

uint16_t sensirion_i2c_packet_add_float(i2c_packet *packet, uint16_t offset, float data)
uint16_t sensirion_i2c_packet_add_float(i2c_packet_t *i2c_packet, uint16_t offset, float data)
{
union {
uint32_t uint32_data;
float float_data;
} convert;

convert.float_data = data;
return sensirion_i2c_packet_add_uint32_t(packet, offset, convert.uint32_data);
return sensirion_i2c_packet_add_uint32_t(i2c_packet, offset, convert.uint32_data);
}

uint16_t sensirion_i2c_packet_add_bytes(i2c_packet *packet, uint16_t offset, const uint8_t *data,
uint16_t data_length)
uint16_t sensirion_i2c_packet_add_bytes(i2c_packet_t *i2c_packet, uint16_t offset,
const uint8_t *data, uint16_t data_length)
{
uint16_t i;

if (data_length % SENSIRION_WORD_SIZE != 0) {
if (data_length % SENSIRION_WORD_SIZE != 0u) {
return -EINVAL;
}

for (i = 0; i < data_length; i += 2) {
packet->data[offset++] = data[i];
packet->data[offset++] = data[i + 1];
if (packet->crc8_poly != 0) {
packet->data[offset] = sensirion_i2c_packet_get_crc(packet, offset - SENSIRION_WORD_SIZE);
for (i = 0; i < data_length; i += 2u) {
i2c_packet->data[offset++] = data[i];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

how about of doing a memcpy?

i2c_packet->data[offset++] = data[i + 1u];
if (i2c_packet->crc8_poly != 0u) {
i2c_packet->data[offset] = sensirion_i2c_packet_get_crc(
i2c_packet, offset - SENSIRION_WORD_SIZE);
offset++;
}
}
return offset;
}

int sensirion_i2c_packet_write(const struct i2c_dt_spec *i2c_spec, const i2c_packet_t *i2c_packet,
uint16_t data_length)
{
uint8_t has_8bit_command = (float)(data_length / 2.0f) != 0.0f;
uint16_t num_words = (data_length + has_8bit_command) / SENSIRION_WORD_SIZE;
uint8_t tx_buffer[SENSIRION_WORD_SIZE * num_words + SENSIRION_CRC8_LEN * num_words];

/*skips the first word (command) because the command does not have a CRC*/
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

if we consistently use the i2c_packet_add_ there is no need to add a crc again. I also think the i2c_packet* should be the first arguement and the i2c_spec the last one!

for (uint16_t i = 1; i < num_words; i++) {
tx_buffer[i * (SENSIRION_WORD_SIZE + SENSIRION_CRC8_LEN)] =
i2c_packet->data[i * SENSIRION_WORD_SIZE];
tx_buffer[i * (SENSIRION_WORD_SIZE + SENSIRION_CRC8_LEN) + 1] =
i2c_packet->data[i * SENSIRION_WORD_SIZE + 1];
tx_buffer[i * (SENSIRION_WORD_SIZE + SENSIRION_CRC8_LEN) + 2] =
sensirion_i2c_packet_get_crc(i2c_packet, i * SENSIRION_WORD_SIZE);
}

return i2c_write_dt(i2c_spec, tx_buffer, sizeof(tx_buffer));
}

int sensirion_i2c_packet_read(const struct i2c_dt_spec *i2c_spec, i2c_packet *packet,
uint16_t expected_data_length)
int sensirion_i2c_packet_read(const struct i2c_dt_spec *i2c_spec, i2c_packet_t *i2c_packet,
uint16_t expected_data_length)
{
int ret;
uint16_t i, j;
uint16_t crc_len = (packet->crc8_poly != 0) ? SENSIRION_CRC8_LEN : 0;
uint16_t size = (expected_data_length / SENSIRION_WORD_SIZE) *
(SENSIRION_WORD_SIZE + crc_len);
uint16_t crc_len = (i2c_packet->crc8_poly != 0) ? SENSIRION_CRC8_LEN : 0;
uint16_t size =
(expected_data_length / SENSIRION_WORD_SIZE) * (SENSIRION_WORD_SIZE + crc_len);

if (expected_data_length % SENSIRION_WORD_SIZE != 0) {
return -EINVAL;
}

ret = i2c_read_dt(i2c_spec, packet->data, size);
ret = i2c_read_dt(i2c_spec, i2c_packet->data, size);
if (ret != 0) {
return ret;
}

for (i = 0, j = 0; i < size; i += SENSIRION_WORD_SIZE + crc_len) {

if (packet->crc8_poly != 0) {
if (!sensirion_i2c_packet_check_crc(packet, i)) {
if (i2c_packet->crc8_poly != 0) {
if (!sensirion_i2c_packet_check_crc(i2c_packet, i)) {
return -EIO;
}
}
packet->data[j++] = packet->data[i];
packet->data[j++] = packet->data[i + 1];
i2c_packet->data[j++] = i2c_packet->data[i];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

also here we may use a memcpy

i2c_packet->data[j++] = i2c_packet->data[i + 1];
}

return 0;
Expand Down
Loading