From a5b2a26eb2199b3558d5284fe15924626b37a5dc Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Wed, 16 Dec 2020 08:33:15 +0200 Subject: [PATCH] WS: API to set PHY mode and Channel plan IDs as defined by FAN 1.1 (#2520) --- nanostack/ws_management_api.h | 77 +++++++++++++++++ source/6LoWPAN/ws/ws_bootstrap.c | 24 +++++- source/6LoWPAN/ws/ws_cfg_settings.c | 34 +++++++- source/6LoWPAN/ws/ws_cfg_settings.h | 2 + source/6LoWPAN/ws/ws_common.c | 86 +++++++++++++++++++ source/6LoWPAN/ws/ws_common.h | 6 ++ source/6LoWPAN/ws/ws_common_defines.h | 2 + source/6LoWPAN/ws/ws_management_api.c | 68 +++++++++++++++ .../ws_cfg_settings/test_ws_cfg_settings.c | 10 +++ 9 files changed, 302 insertions(+), 7 deletions(-) diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index 300f2cab2c7b..78ee06650343 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -184,6 +184,83 @@ int ws_management_network_name_validate( int8_t interface_id, char *network_name_ptr); +/** + * Configure PHY mode ID of Wi-SUN stack as defined by Wi-SUN FAN 1.1. + * + * Change the default configuration for Wi-SUN PHY operation. + * + * Supported values: + * FSK without FEC: + * PHY mode ID | Symbol Rate (kbps) | Modulation Index + * 1 50 0.5 + * 2 50 1.0 + * 3 100 0.5 + * 4 100 1.0 + * 5 150 0.5 + * 6 200 0.5 + * 7 200 1.0 + * 8 300 0.5 + * + * FSK with FEC: + * PHY mode ID | Symbol Rate (kbps) | Modulation Index + * 17 50 0.5 + * 18 50 1.0 + * 19 100 0.5 + * 20 100 1.0 + * 21 150 0.5 + * 22 200 0.5 + * 23 200 1.0 + * 24 300 0.5 + * + * OFDM: + * PHY mode ID | Option | MCS | Data rate (kbps) + * 34 1 2 400 + * 35 1 3 800 + * 36 1 4 1200 + * 37 1 5 1600 + * 38 1 6 2400 + * 51 2 3 400 + * 52 2 4 600 + * 53 2 5 800 + * 54 2 6 1200 + * 68 3 4 300 + * 69 3 5 400 + * 70 3 6 600 + * 84 4 4 150 + * 85 4 5 200 + * 86 4 6 300 + * + * if value of 255 is given then previous value is used. + * + * \param interface_id Network interface ID. + * \param phy_mode_id PHY mode ID. Default 255 (not used). + * + * \return 0, Init OK. + * \return <0 Init fail. + */ +int ws_management_phy_mode_id_set( + int8_t interface_id, + uint8_t phy_mode_id); + +/** + * Configure Channel plan ID of Wi-SUN stack as defined by Wi-SUN FAN 1.1. + * + * Change the default channel configuration for Wi-SUN. + * + * Supported values: TBD + * + * if value of 255 is given then previous value is used. + * + * \param interface_id Network interface ID. + * \param channel_plan_id Channel plan ID. Default 255 (not used). + * + * \return 0, Init OK. + * \return <0 Init fail. + */ +int ws_management_channel_plan_id_set( + int8_t interface_id, + uint8_t channel_plan_id); + /** * Configure regulatory domain of Wi-SUN stack. * diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 8fc1120d1383..0c7a5756a7bf 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -2397,11 +2397,29 @@ static int ws_bootstrap_set_domain_rf_config(protocol_interface_info_entry_t *cu { phy_rf_channel_configuration_s rf_configs; memset(&rf_configs, 0, sizeof(phy_rf_channel_configuration_s)); + + uint8_t phy_mode_id = cur->ws_info->hopping_schdule.phy_mode_id; + if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || + ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || + ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || + ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + rf_configs.modulation = M_OFDM; + rf_configs.datarate = ws_get_datarate_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); + rf_configs.ofdm_option = ws_get_ofdm_option_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); + rf_configs.ofdm_mcs = ws_get_ofdm_mcs_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); + } else { + if ((phy_mode_id >= 17) && (phy_mode_id <= 24)) { + rf_configs.fec = true; + } else { + rf_configs.fec = false; + } + rf_configs.modulation = M_2FSK; + rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + } + rf_configs.channel_0_center_frequency = (uint32_t)cur->ws_info->hopping_schdule.ch0_freq * 100000; rf_configs.channel_spacing = ws_decode_channel_spacing(cur->ws_info->hopping_schdule.channel_spacing); - rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); - rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); - rf_configs.modulation = M_2FSK; rf_configs.number_of_channels = cur->ws_info->hopping_schdule.number_of_channels; ws_bootstrap_set_rf_config(cur, rf_configs); return 0; diff --git a/source/6LoWPAN/ws/ws_cfg_settings.c b/source/6LoWPAN/ws/ws_cfg_settings.c index 8366204e52a9..0ebbf71cd3e2 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/source/6LoWPAN/ws/ws_cfg_settings.c @@ -651,6 +651,8 @@ int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg) cfg->regulatory_domain = REG_DOMAIN_EU; cfg->operating_mode = OPERATING_MODE_3; cfg->operating_class = 2; + cfg->phy_mode_id = 255; + cfg->channel_plan_id = 255; return CFG_SETTINGS_OK; } @@ -671,12 +673,16 @@ int8_t ws_cfg_phy_validate(ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg) // Regulator domain, operating mode or class has changed if (cfg->regulatory_domain != new_cfg->regulatory_domain || cfg->operating_mode != new_cfg->operating_mode || - cfg->operating_class != new_cfg->operating_class) { + cfg->operating_class != new_cfg->operating_class || + cfg->phy_mode_id != new_cfg->phy_mode_id || + cfg->channel_plan_id != new_cfg->channel_plan_id) { ws_hopping_schedule_t hopping_schdule = { .regulatory_domain = new_cfg->regulatory_domain, .operating_mode = new_cfg->operating_mode, - .operating_class = new_cfg->operating_class + .operating_class = new_cfg->operating_class, + .phy_mode_id = new_cfg->phy_mode_id, + .channel_plan_id = new_cfg->channel_plan_id }; // Check that new settings are valid @@ -698,11 +704,31 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w if (ret != CFG_SETTINGS_CHANGED) { return ret; } - // Check settings and configure interface if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + // Set operating mode for FSK if given with PHY mode ID + if ((new_cfg->phy_mode_id == 1) || (new_cfg->phy_mode_id == 17)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_1a; + } else if ((new_cfg->phy_mode_id == 2) || (new_cfg->phy_mode_id == 18)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_1b; + } else if ((new_cfg->phy_mode_id == 3) || (new_cfg->phy_mode_id == 19)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_2a; + } else if ((new_cfg->phy_mode_id == 4) || (new_cfg->phy_mode_id == 20)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_2b; + } else if ((new_cfg->phy_mode_id == 5) || (new_cfg->phy_mode_id == 21)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3; + } else if ((new_cfg->phy_mode_id == 6) || (new_cfg->phy_mode_id == 22)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_4a; + } else if ((new_cfg->phy_mode_id == 7) || (new_cfg->phy_mode_id == 23)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_4b; + } else if ((new_cfg->phy_mode_id == 8) || (new_cfg->phy_mode_id == 24)) { + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_5; + } else { + cur->ws_info->hopping_schdule.operating_mode = new_cfg->operating_mode; + } + cur->ws_info->hopping_schdule.phy_mode_id = new_cfg->phy_mode_id; + cur->ws_info->hopping_schdule.channel_plan_id = new_cfg->channel_plan_id; cur->ws_info->hopping_schdule.regulatory_domain = new_cfg->regulatory_domain; - cur->ws_info->hopping_schdule.operating_mode = new_cfg->operating_mode; cur->ws_info->hopping_schdule.operating_class = new_cfg->operating_class; if (ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule) < 0) { diff --git a/source/6LoWPAN/ws/ws_cfg_settings.h b/source/6LoWPAN/ws/ws_cfg_settings.h index 35490e332696..d7dc9d21c627 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/source/6LoWPAN/ws/ws_cfg_settings.h @@ -38,6 +38,8 @@ typedef struct ws_phy_cfg_s { uint8_t regulatory_domain; /**< PHY regulatory domain; default "KR" 0x09 */ uint8_t operating_class; /**< PHY operating class; default 1 */ uint8_t operating_mode; /**< PHY operating mode; default "1b" symbol rate 50, modulation index 1 */ + uint8_t phy_mode_id; /**< PHY mode ID; default 255 (not used) */ + uint8_t channel_plan_id; /**< Channel plan ID; default 255 (not used) */ } ws_phy_cfg_t; /** diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 11532e41ad40..06c73c88e2d6 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -129,6 +129,60 @@ uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode) return 0; } +uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (84 == phy_mode_id) { + return 150000; + } else if (85 == phy_mode_id) { + return 200000; + } else if ((68 == phy_mode_id) || (86 == phy_mode_id)) { + return 300000; + } else if ((34 == phy_mode_id) || (51 == phy_mode_id) || (69 == phy_mode_id)) { + return 400000; + } else if ((52 == phy_mode_id) || (70 == phy_mode_id)) { + return 600000; + } else if ((35 == phy_mode_id) || (53 == phy_mode_id)) { + return 800000; + } else if ((36 == phy_mode_id) || (54 == phy_mode_id)) { + return 1200000; + } else if (37 == phy_mode_id) { + return 1600000; + } else if (38 == phy_mode_id) { + return 2400000; + } + return 0; +} + +uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id) +{ + if ((phy_mode_id >= 34) && (phy_mode_id <= 38)) { + return OFDM_OPTION_1; + } else if ((phy_mode_id >= 51) && (phy_mode_id <= 54)) { + return OFDM_OPTION_2; + } else if ((phy_mode_id >= 68) && (phy_mode_id <= 70)) { + return OFDM_OPTION_3; + } else if ((phy_mode_id >= 84) && (phy_mode_id <= 86)) { + return OFDM_OPTION_4; + } + return 0; +} + +uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (34 == phy_mode_id) { + return OFDM_MCS_2; + } else if ((35 == phy_mode_id) || (51 == phy_mode_id)) { + return OFDM_MCS_3; + } else if ((36 == phy_mode_id) || (52 == phy_mode_id) || (68 == phy_mode_id) || (84 == phy_mode_id)) { + return OFDM_MCS_4; + } else if ((37 == phy_mode_id) || (53 == phy_mode_id) || (69 == phy_mode_id) || (85 == phy_mode_id)) { + return OFDM_MCS_5; + } else if ((38 == phy_mode_id) || (54 == phy_mode_id) || (70 == phy_mode_id) || (86 == phy_mode_id)) { + return OFDM_MCS_6; + } + return 0; +} + phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode) { if ((OPERATING_MODE_1b == operating_mode) || (OPERATING_MODE_2b == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { @@ -146,6 +200,38 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, return -1; } + // Validate PHY mode ID + if (hopping_schdule->phy_mode_id != 255) { + uint8_t phy_mode_id = hopping_schdule->phy_mode_id; + uint8_t phy_type = phy_mode_id >> 4; + uint8_t phy_mode = phy_mode_id & 0x0f; + // Invalid PHY type + if (phy_type > 5) { + return -1; + } + // Invalid OFDM mode + if (phy_type >= 2 && phy_mode > 6) { + return -1; + } + // Skip if PHY mode is for FSK modulation + if (!phy_mode_id || ((phy_mode_id > 8) && (phy_mode_id < 17)) || phy_mode_id > 24) { + // Validate OFDM configurations + if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || + ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || + ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || + ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + if (ws_get_datarate_using_phy_mode_id(phy_mode_id) == 0 || + ws_get_ofdm_option_using_phy_mode_id(phy_mode_id) == 0 || + ws_get_ofdm_mcs_using_phy_mode_id(phy_mode_id) == 0) { + //Unsupported PHY mode + return -1; + } + } else { + // Invalid PHY mode ID + return -1; + } + } + } hopping_schdule->channel_plan = 0; if (hopping_schdule->regulatory_domain == REG_DOMAIN_KR) { diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index f0aaf9fde03c..6a57cc793b72 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -130,6 +130,12 @@ uint32_t ws_decode_channel_spacing(uint8_t channel_spacing); uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode); +uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id); + +uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id); + +uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id); + phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode); int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, ws_hopping_schedule_t *hopping_schdule); diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 7ce70d0146ef..89a698b3d3c3 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -100,6 +100,8 @@ typedef struct ws_hopping_schedule_s { uint8_t regulatory_domain; /**< PHY regulatory domain default to "KR" 0x09 */ uint8_t operating_class; /**< PHY operating class default to 1 */ uint8_t operating_mode; /**< PHY operating mode default to "1b" symbol rate 50, modulation index 1 */ + uint8_t phy_mode_id; /**< PHY mode ID, default to 255 */ + uint8_t channel_plan_id; /**< Channel plan ID, default to 255 */ uint8_t channel_plan; /**< 0: use regulatory domain values 1: application defined plan */ uint8_t uc_channel_function; /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */ uint8_t bc_channel_function; /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */ diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index 10fcebf54928..bdd2aadc9a55 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -156,6 +156,74 @@ int ws_management_network_name_validate( return 0; } +int ws_management_phy_mode_id_set( + int8_t interface_id, + uint8_t phy_mode_id) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (interface_id >= 0 && (!cur || !ws_info(cur))) { + return -1; + } + + ws_phy_cfg_t cfg; + ws_phy_cfg_t cfg_default; + if (ws_cfg_phy_get(&cfg, NULL) < 0) { + return -3; + } + + if (ws_cfg_phy_default_set(&cfg_default) < 0) { + return -3; + } + + if (phy_mode_id != 255) { + cfg.phy_mode_id = phy_mode_id; + } else { + cfg.phy_mode_id = cfg_default.phy_mode_id; + } + + if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { + return -4; + } + + return 0; +} + +int ws_management_channel_plan_id_set( + int8_t interface_id, + uint8_t channel_plan_id) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (interface_id >= 0 && (!cur || !ws_info(cur))) { + return -1; + } + + ws_phy_cfg_t cfg; + ws_phy_cfg_t cfg_default; + if (ws_cfg_phy_get(&cfg, NULL) < 0) { + return -3; + } + + if (ws_cfg_phy_default_set(&cfg_default) < 0) { + return -3; + } + + if (channel_plan_id != 255) { + cfg.channel_plan_id = channel_plan_id; + } else { + cfg.channel_plan_id = cfg_default.channel_plan_id; + } + + if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { + return -4; + } + + return 0; +} + int ws_management_regulatory_domain_set( int8_t interface_id, uint8_t regulatory_domain, diff --git a/test/nanostack/unittest/6LoWPAN/ws_cfg_settings/test_ws_cfg_settings.c b/test/nanostack/unittest/6LoWPAN/ws_cfg_settings/test_ws_cfg_settings.c index 9cf8aaab667f..370fef16f7ae 100644 --- a/test/nanostack/unittest/6LoWPAN/ws_cfg_settings/test_ws_cfg_settings.c +++ b/test/nanostack/unittest/6LoWPAN/ws_cfg_settings/test_ws_cfg_settings.c @@ -93,6 +93,8 @@ static const ws_cfg_t ws_cfg_defaults_medium = { .phy.regulatory_domain = 3, .phy.operating_class = 2, .phy.operating_mode = 3, + .phy.phy_mode_id = 255, + .phy.channel_plan_id = 255, .timing.disc_trickle_imin = 60, // network size affects .timing.disc_trickle_imax = 960, // network size affects @@ -162,6 +164,8 @@ static const ws_cfg_t ws_cfg_defaults_small = { .phy.regulatory_domain = 3, .phy.operating_class = 2, .phy.operating_mode = 3, + .phy.phy_mode_id = 255, + .phy.channel_plan_id = 255, .timing.disc_trickle_imin = 15, // network size affects .timing.disc_trickle_imax = 60, // network size affects @@ -231,6 +235,8 @@ static const ws_cfg_t ws_cfg_defaults_large = { .phy.regulatory_domain = 3, .phy.operating_class = 2, .phy.operating_mode = 3, + .phy.phy_mode_id = 255, + .phy.channel_plan_id = 255, .timing.disc_trickle_imin = 240, // network size affects .timing.disc_trickle_imax = 1536, // network size affects @@ -300,6 +306,8 @@ static const ws_cfg_t ws_cfg_defaults_xlarge = { .phy.regulatory_domain = 3, .phy.operating_class = 2, .phy.operating_mode = 3, + .phy.phy_mode_id = 255, + .phy.channel_plan_id = 255, .timing.disc_trickle_imin = 240, // network size affects .timing.disc_trickle_imax = 1920, // network size affects @@ -369,6 +377,8 @@ static const ws_cfg_t ws_cfg_defaults_certification = { .phy.regulatory_domain = 3, .phy.operating_class = 2, .phy.operating_mode = 3, + .phy.phy_mode_id = 255, + .phy.channel_plan_id = 255, .timing.disc_trickle_imin = 15, // network size affects .timing.disc_trickle_imax = 60, // network size affects