diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml index 1f57727f..3159a42a 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.yml @@ -24,16 +24,14 @@ jobs: - name: Checkout submodules run: git submodule update --init --recursive - - name: Set up Sonar Scanner 4.40 - run: | - export SONAR_SCANNER_VERSION=4.4.0.2170 - export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux - curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ - echo "$SONAR_SCANNER_HOME/bin" >> $GITHUB_PATH - curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip - unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/ - echo "$HOME/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH + # Setup java 17 to be default (sonar-scanner requirement as of 5.x) + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '17' + + - name: Install sonar-scanner and build-wrapper + uses: sonarsource/sonarcloud-github-c-cpp@v2 - name: Download Nordic SDK run: | diff --git a/src/Makefile b/src/Makefile index 2bac34a8..095ff639 100644 --- a/src/Makefile +++ b/src/Makefile @@ -56,6 +56,11 @@ ruuvitag_b: @echo + package next targets/$@/armgcc/package.sh -n ruuvifw_longmem + $(MAKE) -C targets/$@/armgcc clean + $(MAKE) -C targets/$@/armgcc FW_VERSION=-DAPP_FW_VERSION=${VERSION} DEBUG=-DNDEBUG MODE=-DAPPLICATION_MODE_UUID + @echo + package next + targets/$@/armgcc/package.sh -n ruuvifw_uuid + $(MAKE) -C targets/$@/armgcc clean $(MAKE) -C targets/$@/armgcc FW_VERSION=-DAPP_FW_VERSION=${VERSION} DEBUG=-DDEBUG MODE=-DAPPLICATION_MODE_DEBUG \ RUN_TESTS=-DRUUVI_RUN_TESTS OPT="-Og -g3" # gdb information included diff --git a/src/app_comms.c b/src/app_comms.c index 2bc1a62b..316683a5 100644 --- a/src/app_comms.c +++ b/src/app_comms.c @@ -40,6 +40,7 @@ /** @brief Set to long enough to handle existing queue, then as short as possible. */ #define BLOCKING_COMM_TIMEOUT_MS (4000U) #define CONN_PARAM_UPDATE_DELAY_MS (30U * 1000U) //!< Delay before switching to faster conn params in long ops. +#define RUUVI_SERVICE_UUID (0xFC98U) #if APP_COMMS_BIDIR_ENABLED TESTABLE_STATIC bool @@ -612,6 +613,7 @@ static rd_status_t adv_init (void) adv_settings.channels = channels; adv_settings.manufacturer_id = RB_BLE_MANUFACTURER_ID; err_code |= rt_adv_init (&adv_settings); + ri_adv_set_service_uuid (RUUVI_SERVICE_UUID); RD_ERROR_CHECK (err_code, ~RD_ERROR_FATAL); err_code |= ri_adv_type_set (NONCONNECTABLE_NONSCANNABLE); RD_ERROR_CHECK (err_code, ~RD_ERROR_FATAL); diff --git a/src/app_dataformats.c b/src/app_dataformats.c index 2ac48555..a72c6f97 100644 --- a/src/app_dataformats.c +++ b/src/app_dataformats.c @@ -4,6 +4,7 @@ #include "ruuvi_endpoint_3.h" #include "ruuvi_endpoint_5.h" #include "ruuvi_endpoint_8.h" +#include "ruuvi_endpoint_c5.h" #include "ruuvi_endpoint_fa.h" #include "ruuvi_interface_aes.h" #include "ruuvi_interface_communication_ble_advertising.h" @@ -55,8 +56,42 @@ uint32_t app_data_encrypt (const uint8_t * const cleartext, app_dataformat_t app_dataformat_next (const app_dataformats_t formats, const app_dataformat_t state) { - // TODO: Return enabled value instead of hardcoded one - return DF_5; + app_dataformat_t nextState = DF_INVALID; + + if (DF_INVALID != formats.formats) + { + nextState = state; + + do + { + switch (nextState) + { + case DF_3: + nextState = DF_5; + break; + + case DF_5: + nextState = DF_8; + break; + + case DF_8: + nextState = DF_C5; + break; + + case DF_C5: + nextState = DF_FA; + break; + + case DF_FA: + default: + nextState = DF_3; + break; + } + } while (! (nextState & formats.formats)); + } + + ri_adv_enable_uuid (nextState == DF_C5); + return nextState; } #if RE_3_ENABLED @@ -184,6 +219,39 @@ encode_to_8 (uint8_t * const output, } #endif +#if RE_C5_ENABLED +TESTABLE_STATIC rd_status_t +encode_to_c5 (uint8_t * const output, + size_t * const output_length, + const rd_sensor_data_t * const data) +{ + static uint16_t ep_c5_measurement_count = 0; + rd_status_t err_code = RD_SUCCESS; + re_status_t enc_code = RE_SUCCESS; + re_c5_data_t ep_data = {0}; + ep_c5_measurement_count++; + ep_c5_measurement_count %= (RE_C5_SEQCTR_MAX + 1); + ep_data.humidity_rh = rd_sensor_data_parse (data, RD_SENSOR_HUMI_FIELD); + ep_data.pressure_pa = rd_sensor_data_parse (data, RD_SENSOR_PRES_FIELD); + ep_data.temperature_c = rd_sensor_data_parse (data, RD_SENSOR_TEMP_FIELD); + ep_data.measurement_count = ep_c5_measurement_count; + uint8_t mvtctr = (uint8_t) (app_sensor_event_count_get() % (RE_C5_MVTCTR_MAX + 1)); + ep_data.movement_count = mvtctr; + err_code |= ri_radio_address_get (&ep_data.address); + err_code |= ri_adv_tx_power_get (&ep_data.tx_power); + err_code |= rt_adc_vdd_get (&ep_data.battery_v); + enc_code |= re_c5_encode (output, &ep_data); + + if (RE_SUCCESS != enc_code) + { + err_code |= RD_ERROR_INTERNAL; + } + + *output_length = RE_C5_DATA_LENGTH; + return err_code; +} +#endif + #if RE_FA_ENABLED #ifndef APP_FA_KEY #define APP_FA_KEY {00, 11, 22, 33, 44, 55, 66, 77, 88, 99, 11, 12, 13, 14, 15, 16} @@ -253,6 +321,12 @@ rd_status_t app_dataformat_encode (uint8_t * const output, err_code |= encode_to_8 (output, output_length, p_data); break; # endif +# if RE_C5_ENABLED + + case DF_C5: + err_code |= encode_to_c5 (output, output_length, p_data); + break; +# endif # if RE_FA_ENABLED case DF_FA: diff --git a/src/app_dataformats.h b/src/app_dataformats.h index daec5013..c20eacec 100644 --- a/src/app_dataformats.h +++ b/src/app_dataformats.h @@ -26,16 +26,14 @@ typedef enum DF_3 = (1U << 0U), DF_5 = (1U << 1U), DF_8 = (1U << 2U), - DF_FA = (1U << 3U) + DF_C5 = (1U << 3U), + DF_FA = (1U << 4U) } app_dataformat_t; typedef struct { - unsigned int DF_3 : 1; //!< Dataformat 3 enabled - unsigned int DF_5 : 1; //!< Dataformat 5 enabled - unsigned int DF_8 : 1; //!< Dataformat 8 enabled - unsigned int DF_FA : 1; //!< Dataformat fa enabled -} app_dataformats_t; //!< Container for enabled data formats + unsigned int formats; //!< Container for enabled data formats +} app_dataformats_t; /** @@ -43,7 +41,7 @@ typedef struct * * @param[in] formats Enabled formats * @param[in] state Current state of dataformat picker. - * @return Next dataformat to use in app. + * @return Next dataformat to use in app. DF_INVALID if no formats are enabled. */ app_dataformat_t app_dataformat_next (const app_dataformats_t formats, const app_dataformat_t state); diff --git a/src/app_heartbeat.c b/src/app_heartbeat.c index c7c40fe3..10ee7fc0 100644 --- a/src/app_heartbeat.c +++ b/src/app_heartbeat.c @@ -27,10 +27,11 @@ #include "ruuvi_task_nfc.h" #define U8_MASK (0xFFU) -#define APP_DF_3_ENABLED 0 -#define APP_DF_5_ENABLED 1 -#define APP_DF_8_ENABLED 0 -#define APP_DF_FA_ENABLED 0 +#define APP_DF_3_ENABLED RE_3_ENABLED +#define APP_DF_5_ENABLED RE_5_ENABLED +#define APP_DF_8_ENABLED RE_5_ENABLED +#define APP_DF_C5_ENABLED RE_C5_ENABLED +#define APP_DF_FA_ENABLED RE_FA_ENABLED static ri_timer_id_t heart_timer; //!< Timer for updating data. @@ -38,13 +39,15 @@ static uint64_t last_heartbeat_timestamp_ms; //!< Timestamp for heartbeat refres static app_dataformat_t m_dataformat_state; //!< State of heartbeat. -static app_dataformats_t m_dataformats_enabled = +static const app_dataformats_t m_dataformats_enabled = { - .DF_3 = APP_DF_3_ENABLED, - .DF_5 = APP_DF_5_ENABLED, - .DF_8 = APP_DF_8_ENABLED, - .DF_FA = APP_DF_FA_ENABLED -}; //!< Flags of enabled formats + .formats = + + (APP_DF_3_ENABLED ? DF_3 : 0) + + (APP_DF_5_ENABLED ? DF_5 : 0) + + (APP_DF_8_ENABLED ? DF_8 : 0) + + (APP_DF_C5_ENABLED ? DF_C5 : 0) + + (APP_DF_FA_ENABLED ? DF_FA : 0) +}; static rd_status_t send_adv (ri_comm_message_t * const p_msg) { diff --git a/src/application_config/app_config.h b/src/application_config/app_config.h index 753a5d00..f31c0202 100644 --- a/src/application_config/app_config.h +++ b/src/application_config/app_config.h @@ -433,6 +433,13 @@ # define RE_8_ENABLED (0U + ENABLE_ALL_DATAFORMATS) #endif +/** + * @brief Enable dataformat with space for UUID + */ +#ifndef RE_C5_ENABLED +# define RE_C5_ENABLED (0U + ENABLE_ALL_DATAFORMATS) +#endif + /** * @brief Enable legacy encrypted dataformat */ diff --git a/src/application_config/application_mode_longlife.h b/src/application_config/application_mode_longlife.h index 3122bc97..1f0c0807 100644 --- a/src/application_config/application_mode_longlife.h +++ b/src/application_config/application_mode_longlife.h @@ -1,5 +1,5 @@ -#ifndef APPLICATION_MODE_DEBUG_H -#define APPLICATION_MODE_DEBUG_H +#ifndef APPLICATION_MODE_LONGLIFE_H +#define APPLICATION_MODE_LONGLIFE_H #define APP_FW_VARIANT "+longlife" diff --git a/src/application_config/application_mode_uuid.h b/src/application_config/application_mode_uuid.h new file mode 100644 index 00000000..ba3e2845 --- /dev/null +++ b/src/application_config/application_mode_uuid.h @@ -0,0 +1,12 @@ +#ifndef APPLICATION_MODE_UUID_H +#define APPLICATION_MODE_UUID_H + +#define APP_FW_VARIANT "+uuid" + +#define RE_5_ENABLED (0U) +#define RE_C5_ENABLED (1U) + +#define APP_BLE_INTERVAL_MS (1285U) +#define APP_NUM_REPEATS (7U) // ~9 s + +#endif \ No newline at end of file diff --git a/src/application_config/application_modes.h b/src/application_config/application_modes.h index 89d1abda..86583647 100644 --- a/src/application_config/application_modes.h +++ b/src/application_config/application_modes.h @@ -17,6 +17,8 @@ #include "application_mode_longlife.h" #elif APPLICATION_MODE_LONGMEM #include "application_mode_longmem.h" +#elif APPLICATION_MODE_UUID +#include "application_mode_uuid.h" #elif DEBUG #include "application_mode_debug.h" #endif diff --git a/src/gcc_sources.make b/src/gcc_sources.make index 735a984a..20515ae4 100644 --- a/src/gcc_sources.make +++ b/src/gcc_sources.make @@ -272,6 +272,7 @@ RUUVI_LIB_SOURCES= \ $(PROJ_DIR)/ruuvi.endpoints.c/src/ruuvi_endpoint_3.c \ $(PROJ_DIR)/ruuvi.endpoints.c/src/ruuvi_endpoint_5.c \ $(PROJ_DIR)/ruuvi.endpoints.c/src/ruuvi_endpoint_8.c \ + $(PROJ_DIR)/ruuvi.endpoints.c/src/ruuvi_endpoint_c5.c \ $(PROJ_DIR)/ruuvi.endpoints.c/src/ruuvi_endpoint_fa.c \ $(PROJ_DIR)/ruuvi.libraries.c/src/libs/compress/ruuvi_library_compress.c \ $(PROJ_DIR)/ruuvi.libraries.c/src/libs/compress/liblzf-3.6/lzf_c.c \ diff --git a/src/main.h b/src/main.h index 6a6b51b3..aa22306d 100644 --- a/src/main.h +++ b/src/main.h @@ -23,8 +23,8 @@ // Submodule requirements #define RUUVI_BOARDS_REQ "3.7.1" -#define RUUVI_DRIVERS_REQ "3.9.0" -#define RUUVI_ENDPOINTS_REQ "3.2.1" +#define RUUVI_DRIVERS_REQ "3.10.0" +#define RUUVI_ENDPOINTS_REQ "4.1.0" #define RUUVI_LIBRARIES_REQ "3.0.0" #define APP_SELFTEST_OK_DELAY_MS (1000U) //!< time to show "ok" led. diff --git a/src/release.sh b/src/release.sh index 823e4555..f4bb5cdd 100755 --- a/src/release.sh +++ b/src/release.sh @@ -3,8 +3,8 @@ GH_USER="ruuvi" GH_REPO="ruuvi.firmware.c" #$(GH_TOKEN) Set this in environment. -BOARDS=(ruuvitag_b kaarle kalervo keijo) -VARIANTS=(default longlife longmem test) +BOARDS=(ruuvitag_b) +VARIANTS=(default longlife test uuid) TAG=$(git describe --tags --exact-match) if [ -z "$TAG" ]; then echo "Tag is not set, exit"; exit; fi diff --git a/src/ruuvi.drivers.c b/src/ruuvi.drivers.c index 6014f67b..2555fc5c 160000 --- a/src/ruuvi.drivers.c +++ b/src/ruuvi.drivers.c @@ -1 +1 @@ -Subproject commit 6014f67b031996c26e0d4f2a216911b263a95ae3 +Subproject commit 2555fc5c9725747084b1ab7c52b29e4a4b9dedab diff --git a/src/ruuvi.endpoints.c b/src/ruuvi.endpoints.c index e48672d0..a118752d 160000 --- a/src/ruuvi.endpoints.c +++ b/src/ruuvi.endpoints.c @@ -1 +1 @@ -Subproject commit e48672d0517c47cb6d05e32f0cb4729650412ce5 +Subproject commit a118752d812fd5c2af2be0165c11617268d0d2de diff --git a/test/test_app_comms.c b/test/test_app_comms.c index 90bbb0b1..ec6af9d4 100644 --- a/test/test_app_comms.c +++ b/test/test_app_comms.c @@ -119,6 +119,7 @@ static void adv_init_Expect (void) { #if APP_ADV_ENABLED rt_adv_init_ExpectAndReturn (&adv_settings, RD_SUCCESS); + ri_adv_set_service_uuid_Expect (0xFC98); ri_adv_type_set_ExpectAndReturn (NONCONNECTABLE_NONSCANNABLE, RD_SUCCESS); ri_timer_stop_ExpectAndReturn (m_comm_timer, RD_SUCCESS); ri_timer_start_ExpectAndReturn (m_comm_timer, APP_FAST_ADV_TIME_MS, &m_mode_ops, diff --git a/test/test_app_dataformats.c b/test/test_app_dataformats.c index 23d646fa..51a2c34f 100644 --- a/test/test_app_dataformats.c +++ b/test/test_app_dataformats.c @@ -13,6 +13,7 @@ #include "mock_ruuvi_endpoint_3.h" #include "mock_ruuvi_endpoint_5.h" #include "mock_ruuvi_endpoint_8.h" +#include "mock_ruuvi_endpoint_c5.h" #include "mock_ruuvi_endpoint_fa.h" #include "mock_ruuvi_interface_aes.h" #include "mock_ruuvi_interface_communication_ble_advertising.h" @@ -229,6 +230,61 @@ void test_app_dataformat_encode_8_error (void) TEST_ASSERT (RE_8_DATA_LENGTH == output_length); } +void test_app_dataformat_encode_c5_ok (void) +{ + uint8_t output[18] = {0}; + size_t output_length = sizeof (output); + app_dataformat_t format = DF_C5; + float voltage = 2.5F; + uint64_t address = 0x0000AABBCCDDEEFF; + int8_t power = 4; + rd_status_t status = RD_SUCCESS; + rd_sensor_data_t data = {0}; + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + app_sensor_event_count_get_ExpectAndReturn (1); + ri_radio_address_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + ri_radio_address_get_ReturnThruPtr_address (&address); + ri_adv_tx_power_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + ri_adv_tx_power_get_ReturnThruPtr_dbm (&power); + rt_adc_vdd_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + rt_adc_vdd_get_ReturnThruPtr_vdd (&voltage); + re_c5_encode_ExpectAndReturn (NULL, NULL, RE_SUCCESS); + re_c5_encode_IgnoreArg_buffer(); + re_c5_encode_IgnoreArg_data(); + status = app_dataformat_encode (output, &output_length, &data, format); + TEST_ASSERT (RD_SUCCESS == status); + TEST_ASSERT (RE_C5_DATA_LENGTH == output_length); +} + +void test_app_dataformat_encode_c5_error (void) +{ + uint8_t output[18] = {0}; + size_t output_length = sizeof (output); + app_dataformat_t format = DF_C5; + float voltage = 2.5F; + uint64_t address = 0x0000AABBCCDDEEFF; + int8_t power = 4; + rd_status_t status = RD_SUCCESS; + rd_sensor_data_t data = {0}; + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + rd_sensor_data_parse_ExpectAnyArgsAndReturn (0); + app_sensor_event_count_get_ExpectAndReturn (1); + ri_radio_address_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + ri_radio_address_get_ReturnThruPtr_address (&address); + ri_adv_tx_power_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + ri_adv_tx_power_get_ReturnThruPtr_dbm (&power); + rt_adc_vdd_get_ExpectAnyArgsAndReturn (RD_SUCCESS); + rt_adc_vdd_get_ReturnThruPtr_vdd (&voltage); + re_c5_encode_ExpectAndReturn (NULL, NULL, RE_ERROR_ENCODING); + re_c5_encode_IgnoreArg_buffer(); + re_c5_encode_IgnoreArg_data(); + status = app_dataformat_encode (output, &output_length, &data, format); + TEST_ASSERT (RD_ERROR_INTERNAL == status); +} + void test_app_dataformat_encode_fa_ok (void) { uint8_t output[24] = {0}; @@ -289,4 +345,64 @@ void test_app_dataformat_encode_fa_error (void) TEST_ASSERT (RD_ERROR_INTERNAL == status); } +void test_app_dataformat_next_all (void) +{ + const app_dataformats_t formats = { DF_3 | DF_5 | DF_8 | DF_C5 | DF_FA }; + app_dataformat_t format = DF_INVALID; + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_3); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_5); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_8); + ri_adv_enable_uuid_Expect (true); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_C5); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_FA); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_3); +} + +void test_app_dataformat_next_none (void) +{ + const app_dataformats_t formats = { DF_INVALID }; + app_dataformat_t format = DF_5; + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_INVALID); +} + +void test_app_dataformat_next_one (void) +{ + const app_dataformats_t formats = { DF_5 }; + app_dataformat_t format = DF_INVALID; + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_5); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_5); +} + +void test_app_dataformat_next_two (void) +{ + const app_dataformats_t formats = { DF_5 | DF_C5 }; + app_dataformat_t format = DF_INVALID; + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_5); + ri_adv_enable_uuid_Expect (true); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_C5); + ri_adv_enable_uuid_Expect (false); + format = app_dataformat_next (formats, format); + TEST_ASSERT (format == DF_5); +} + #endif // TEST