Skip to content

Commit b7cfe44

Browse files
kapi-nomaje-emb
authored andcommitted
lib: sfloat: add a module for short float type
Added a module for the SFLOAT type that is defined in the IEEE 11073-20601 specification. Signed-off-by: Kamil Piszczek <Kamil.Piszczek@nordicsemi.no> Co-authored-by: Marcin Jeliński <marcin.jelinski@nordicsemi.no>
1 parent 287afa6 commit b7cfe44

File tree

13 files changed

+479
-1
lines changed

13 files changed

+479
-1
lines changed

CODEOWNERS

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Kconfig* @tejlmand
102102
/lib/pdn/ @lemrey @rlubos
103103
/lib/ram_pwrdn/ @mariuszpos @MarekPorwisz
104104
/lib/fatal_error/ @SebastianBoe
105+
/lib/sfloat/ @kapi-no @maje-emb
105106
/lib/sms/ @trantanen @tokangas
106107
/lib/st25r3911b/ @grochu
107108
/lib/supl/ @rlubos @tokangas
@@ -220,6 +221,7 @@ Kconfig* @tejlmand
220221
/tests/lib/modem_jwt/ @SeppoTakalo
221222
/tests/lib/modem_info/ @maxd-nordic
222223
/tests/lib/qos/ @simensrostad
224+
/tests/lib/sfloat/ @kapi-no @maje-emb
223225
/tests/lib/sms/ @trantanen @tokangas
224226
/tests/lib/nrf_modem_lib/ @lemrey @MirkoCovizzi
225227
/tests/lib/nrf_modem_lib/nrf91_sockets/ @MirkoCovizzi

doc/nrf/libraries/others/sfloat.rst

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.. _lib_sfloat:
2+
3+
Short float (SFLOAT)
4+
####################
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
The library provides an implementation of the SFLOAT type, which is used to encode health data
11+
like glucose concentration or blood pressure.
12+
13+
Overview
14+
********
15+
16+
You can use the library to encode numbers that have the fractional part (for example ``10.2``).
17+
This data type is similar to the standard FLOAT type ``float``,
18+
but it is more compact and has a lower resolution.
19+
20+
The IEEE 11073-20601-2008 specification defines the SFLOAT type.
21+
This data type encodes each number in two bytes using the following format:
22+
23+
.. math::
24+
25+
SFLOAT = 10^e * m
26+
27+
Where:
28+
29+
* ``e`` denotes exponent, encoded as a 4-bit integer in two's-complement form, value range ``-8 - 7``.
30+
* ``m`` denotes mantissa, encoded as a 12-bit integer in two's-complement form, value range ``-2048 - 2047``.
31+
32+
The SFLOAT type typically encodes data used in health devices.
33+
For instance, the Glucose Concentration field in the Bluetooth Continuous Glucose Monitoring
34+
service uses the SFLOAT type.
35+
36+
Configuration
37+
*************
38+
39+
To enable the library, set the :kconfig:option:`CONFIG_SFLOAT` Kconfig option to ``y``
40+
in the project configuration file :file:`prj.conf`.
41+
42+
FLOAT conversion
43+
****************
44+
45+
This library provides an API to convert the FLOAT type into SFLOAT type.
46+
The API is only compatible with the FLOAT type from the IEEE 754 specification
47+
that uses the ``binary32`` parameter from the interchange format.
48+
The conversion process may lead to some loss of information about the converted value
49+
as the SFLOAT type has a smaller encoding resolution than the FLOAT Type.
50+
The library always preserves three significant figures of the original value.
51+
Under additional conditions, it also preserves the fourth figure.
52+
You can get four significant figures in the converted value when the four significant
53+
figures of the original value compose a number in the mantissa range: ``-2048 - 2047``.
54+
55+
Dependencies
56+
************
57+
58+
* ``include/zephyr/sys/byteorder.h``
59+
60+
API documentation
61+
*****************
62+
63+
| Header file: :file:`include/sfloat.h`
64+
| Source file: :file:`lib/sfloat/sfloat.c`
65+
66+
.. doxygengroup:: sfloat
67+
:project: nrf
68+
:members:

doc/nrf/releases/release-notes-changelog.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ Libraries for NFC
352352
Other libraries
353353
---------------
354354

355-
|no_changes_yet_note|
355+
* Added:
356+
* :ref:`lib_sfloat` library.
356357

357358
Common Application Framework (CAF)
358359
----------------------------------

include/sfloat.h

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2022 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#ifndef SFLOAT_H_
8+
#define SFLOAT_H_
9+
10+
#include <stdint.h>
11+
#include <zephyr/types.h>
12+
13+
/**
14+
* @file
15+
* @defgroup sfloat Short float (SFLOAT) type.
16+
* @{
17+
*
18+
* @brief API for short float (SFLOAT) type from the IEEE 11073-20601-2008
19+
* specification.
20+
*/
21+
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
26+
/** @brief SFLOAT special values. */
27+
enum sfloat_special {
28+
/** Not a number. */
29+
SFLOAT_NAN = 0x07FF,
30+
31+
/** Not at this resolution. */
32+
SFLOAT_NRES = 0x0800,
33+
34+
/** Positive infinity. */
35+
SFLOAT_POS_INFINITY = 0x07FE,
36+
37+
/** Negative infinity. */
38+
SFLOAT_NEG_INFINITY = 0x0802,
39+
40+
/** Reserved for future use. */
41+
SFLOAT_RESERVED = 0x0801,
42+
};
43+
44+
/** @brief SFLOAT type. */
45+
struct sfloat {
46+
/* SFLOAT type encoded as 16-bit word that consists of the following fields:
47+
* 1. Exponent, encoded as 4-bit integer in two's-complement form.
48+
* 2. Mantissa, encoded as 12-bit integer in two's-complement form.
49+
*/
50+
uint16_t val;
51+
};
52+
53+
/**
54+
* @brief Convert the standard float type into SFLOAT type.
55+
*
56+
* @param[in] float_num Number encoded as a standard float type
57+
* (binary32 notation from the IEEE 754-2008 specification).
58+
*
59+
* @return SFLOAT type (from the IEEE 11073-20601-2008 specification).
60+
*/
61+
struct sfloat sfloat_from_float(float float_num);
62+
63+
#ifdef __cplusplus
64+
}
65+
#endif
66+
67+
/**
68+
* @}
69+
*/
70+
71+
#endif /* SFLOAT_H_ */

lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ add_subdirectory_ifdef(CONFIG_AT_SHELL at_shell)
3737
add_subdirectory_ifdef(CONFIG_MODEM_ANTENNA modem_antenna)
3838
add_subdirectory_ifdef(CONFIG_QOS qos)
3939
add_subdirectory_ifdef(CONFIG_IDENTITY_KEY identity_key)
40+
add_subdirectory_ifdef(CONFIG_SFLOAT sfloat)

lib/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ rsource "at_shell/Kconfig"
3838
rsource "modem_antenna/Kconfig"
3939
rsource "qos/Kconfig"
4040
rsource "identity_key/Kconfig"
41+
rsource "sfloat/Kconfig"
4142

4243
endmenu

lib/sfloat/CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Copyright (c) 2022 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
zephyr_library()
8+
zephyr_library_sources(sfloat.c)

lib/sfloat/Kconfig

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# Copyright (c) 2022 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
config SFLOAT
8+
bool "SFLOAT type"
9+
select EXPERIMENTAL
10+
help
11+
A library for managing SFLOAT type.

lib/sfloat/sfloat.c

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright (c) 2022 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <stdio.h>
8+
9+
#include <sfloat.h>
10+
11+
#include <zephyr/sys/byteorder.h>
12+
13+
/* Maximum mantissa value: 2047. */
14+
#define SFLOAT_MANTISSA_MAX ((1 << 11) - 1)
15+
/* Minimum mantissa value: -2048. */
16+
#define SFLOAT_MANTISSA_MIN (-(1 << 11))
17+
/* Mantissa bit position in the SFLOAT encoding. */
18+
#define SFLOAT_MANTISSA_BIT_POS (0)
19+
/* Mantissa mask in the SFLOAT encoding. */
20+
#define SFLOAT_MANTISSA_MASK (0x0FFF)
21+
22+
/* Minimum exponent value. */
23+
#define SFLOAT_EXP_MIN (-8)
24+
/* Maximum exponent value. */
25+
#define SFLOAT_EXP_MAX (7)
26+
/* Maximum exponentiation (exponent function) value: 10^7. */
27+
#define SFLOAT_EXP_FUNC_MAX (10000000)
28+
/* Exponent bit position in the SFLOAT encoding. */
29+
#define SFLOAT_EXP_BIT_POS (12)
30+
/* Exponent mask in the SFLOAT encoding. */
31+
#define SFLOAT_EXP_MASK (0xF000)
32+
33+
/* Size in bits of the float sign encoding. */
34+
#define FLOAT_SIGN_BIT_SIZE 1
35+
/* Size in bits of the float exponent encoding. */
36+
#define FLOAT_EXP_BIT_SIZE 8
37+
/* Size in bits of the float mantissa encoding. */
38+
#define FLOAT_MANTISSA_BIT_SIZE 23
39+
40+
/* Absolute minimum float resolution. */
41+
#define FLOAT_ABS_MIN (0.000001f)
42+
/* Minimum negative float resolution. */
43+
#define FLOAT_NEG_MIN (SFLOAT_EXP_FUNC_MAX * 1.0f * SFLOAT_MANTISSA_MIN)
44+
/* Maximum positive float resolution. */
45+
#define FLOAT_POS_MAX (SFLOAT_EXP_FUNC_MAX * 1.0f * SFLOAT_MANTISSA_MAX)
46+
47+
/* Helper macro for getting absolute value. */
48+
#define ABS(a) ((a < 0) ? (-a) : (a))
49+
50+
/* Float type should use binary32 notation from the IEEE 754-2008 specification. */
51+
BUILD_ASSERT(sizeof(float) == sizeof(uint32_t));
52+
53+
/* SFLOAT descriptor. */
54+
struct sfloat_desc {
55+
uint8_t exponent;
56+
uint16_t mantissa;
57+
};
58+
59+
/* FLOAT encoding descriptor. */
60+
union float_enc {
61+
uint32_t val;
62+
struct {
63+
uint32_t mantissa: FLOAT_MANTISSA_BIT_SIZE;
64+
uint32_t exp: FLOAT_EXP_BIT_SIZE;
65+
uint32_t sign: FLOAT_SIGN_BIT_SIZE;
66+
};
67+
};
68+
69+
static struct sfloat_desc sfloat_desc_from_float(float float_num)
70+
{
71+
struct sfloat_desc sfloat = {0};
72+
union float_enc float_enc;
73+
uint16_t mantissa_max;
74+
uint16_t mantissa;
75+
float float_abs;
76+
bool inc_exp;
77+
int8_t exp = 0;
78+
79+
float_enc.val = sys_get_le32((uint8_t *) &float_num);
80+
81+
/* Handle zero float values. */
82+
if ((float_enc.exp == 0) && (float_enc.mantissa == 0)) {
83+
return sfloat;
84+
}
85+
86+
/* Handle special float values. */
87+
if (float_enc.exp == UINT8_MAX) {
88+
if (float_enc.mantissa == 0) {
89+
sfloat.mantissa = float_enc.sign ?
90+
SFLOAT_NEG_INFINITY : SFLOAT_POS_INFINITY;
91+
} else {
92+
sfloat.mantissa = SFLOAT_NAN;
93+
}
94+
95+
return sfloat;
96+
}
97+
98+
/* Verify if the SFLOAT has a proper resolution for the conversion. */
99+
float_abs = float_enc.sign ? (-float_num) : float_num;
100+
if ((float_abs < FLOAT_ABS_MIN) ||
101+
(float_num < FLOAT_NEG_MIN) ||
102+
(float_num > FLOAT_POS_MAX)) {
103+
sfloat.mantissa = SFLOAT_NRES;
104+
105+
return sfloat;
106+
}
107+
108+
/* Find mantissa and exponent for the SFLOAT type. */
109+
mantissa_max = float_enc.sign ? ABS(SFLOAT_MANTISSA_MIN) : SFLOAT_MANTISSA_MAX;
110+
inc_exp = float_abs > mantissa_max;
111+
while (exp > SFLOAT_EXP_MIN && exp < SFLOAT_EXP_MAX) {
112+
if (inc_exp) {
113+
if (float_abs <= mantissa_max) {
114+
break;
115+
}
116+
117+
float_abs /= 10;
118+
exp++;
119+
} else {
120+
if ((float_abs * 10) > mantissa_max) {
121+
break;
122+
}
123+
124+
float_abs *= 10;
125+
exp--;
126+
}
127+
}
128+
129+
/* Round up the mantisssa. */
130+
mantissa = (uint16_t) float_abs;
131+
if (((float_abs - mantissa) * 10 >= 5) && (mantissa + 1 <= mantissa_max)) {
132+
mantissa++;
133+
}
134+
135+
/* Encode mantissa and exponent in the two's-complement form. */
136+
if (exp >= 0) {
137+
sfloat.exponent = ((uint8_t) exp) & 0x0F;
138+
} else {
139+
sfloat.exponent = ((uint8_t) -exp) & 0x0F;
140+
sfloat.exponent = (~sfloat.exponent & 0x0F) + 1;
141+
}
142+
143+
sfloat.mantissa = mantissa & SFLOAT_MANTISSA_MASK;
144+
if (float_enc.sign) {
145+
sfloat.mantissa = (~sfloat.mantissa & SFLOAT_MANTISSA_MASK) + 1;
146+
}
147+
148+
return sfloat;
149+
}
150+
151+
static struct sfloat sfloat_encode(const struct sfloat_desc *sfloat_desc)
152+
{
153+
struct sfloat sfloat;
154+
155+
sfloat.val = ((sfloat_desc->exponent << SFLOAT_EXP_BIT_POS) & SFLOAT_EXP_MASK);
156+
sfloat.val |= ((sfloat_desc->mantissa << SFLOAT_MANTISSA_BIT_POS) & SFLOAT_MANTISSA_MASK);
157+
158+
return sfloat;
159+
}
160+
161+
struct sfloat sfloat_from_float(float float_num)
162+
{
163+
struct sfloat sfloat;
164+
struct sfloat_desc sfloat_desc;
165+
166+
sfloat_desc = sfloat_desc_from_float(float_num);
167+
sfloat = sfloat_encode(&sfloat_desc);
168+
169+
return sfloat;
170+
}

tests/lib/sfloat/CMakeLists.txt

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#
2+
# Copyright (c) 2022 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
project(sfloat)
11+
12+
FILE(GLOB app_sources src/main.c)
13+
target_sources(app PRIVATE ${app_sources})

tests/lib/sfloat/prj.conf

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright (c) 2022 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# ZTEST
8+
CONFIG_ZTEST=y
9+
10+
# SFLOAT library
11+
CONFIG_SFLOAT=y
12+
13+
# Enable float printing
14+
CONFIG_CBPRINTF_FP_SUPPORT=y

0 commit comments

Comments
 (0)