Skip to content

Commit e1558fb

Browse files
author
Jarkko Paso
authored
Implemented mode switch PHR build and parse (ARMmbed#2665)
1 parent cbd8a15 commit e1558fb

File tree

9 files changed

+334
-14
lines changed

9 files changed

+334
-14
lines changed

source/MAC/IEEE802_15_4/mac_mode_switch.c

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,118 @@
1919
#include "nsconfig.h"
2020
#include "ns_types.h"
2121
#include "ns_trace.h"
22+
#include "common_functions.h"
2223
#include "MAC/IEEE802_15_4/mac_defines.h"
2324
#include "MAC/IEEE802_15_4/mac_mode_switch.h"
2425

2526
#define TRACE_GROUP "mswc"
2627

27-
#define PHR_LEN 2
28-
28+
static uint8_t mac_calculate_mode_switch_parity(uint16_t mode_switch_phr)
29+
{
30+
uint8_t counter = 0;
31+
// Calculate number of 1-bits in (15-bit) input and return modulo-2 of the sum
32+
for (int i = 0; i < 15; i++) {
33+
if (mode_switch_phr & (1 << i)) {
34+
counter++;
35+
}
36+
}
37+
return counter % 2;
38+
}
39+
/*
40+
* 11-bit input must be padded with 4 leading zeroes.
41+
* Reverse the 15-bit result and divide with polynomial X⁴ + X + 1 -> 10011
42+
* Return remainder as checksum
43+
*
44+
* Example:
45+
* Input: xxxxx01000000001
46+
* Padded input: x000001000000001
47+
* Reversed and padded input: 100000000100000x
48+
* Calculated checksum: 0x0f (00001111)
49+
*
50+
* Division:
51+
*
52+
* 10011010101 <- Result
53+
* -----------------
54+
* 10011 | 100000000100000 <- Highest bit (10000) is 1, add 1 in result
55+
* 10011 <- 10011 * 1
56+
* -----
57+
* 00110 <- Highest bit (00110) is 0, add 0 in result
58+
* 00000 <- 10011 * 0
59+
* -----
60+
* .
61+
* .
62+
* .
63+
* -----
64+
* 11100
65+
* 10011
66+
* ----
67+
* 1111 <- Remainder
68+
*
69+
*/
70+
static uint8_t mac_calculate_mode_switch_checksum(uint16_t mode_switch_phr)
71+
{
72+
// X⁴ + X + 1 -> 0b10011 -> 0x13
73+
uint8_t polynomial = 0x13;
74+
// Pad input with four leading zeroes
75+
mode_switch_phr &= ~0x7800;
76+
// Reverse input
77+
uint16_t phr_reversed = 0;
78+
for (int i = 0; i < 16; i++) {
79+
if (mode_switch_phr & (1 << i)) {
80+
phr_reversed |= 1 << (15 - i);
81+
}
82+
}
83+
// Divide 15-bit padded and reversed input, use polynomial 10011 as the divider
84+
uint8_t shift = 11;
85+
uint8_t remainder = phr_reversed >> shift;
86+
for (int i = 0; i < 11; i++) {
87+
// Check highest bit
88+
if (remainder & (1 << 4)) {
89+
remainder ^= polynomial;
90+
} else {
91+
remainder ^= 0;
92+
}
93+
// Division ready, return remainder as checksum
94+
if (!(--shift)) {
95+
return remainder;
96+
}
97+
remainder <<= 1;
98+
if (phr_reversed & (1 << shift)) {
99+
remainder |= 1;
100+
}
101+
}
102+
// Shouldn't go here
103+
return 0;
104+
}
29105

30-
int8_t ms_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id)
106+
/*
107+
* Mode switch PHR format:
108+
*
109+
* | 0 | 1-2 | 3-10 | 11-14 | 15 |
110+
* |Mode Switch|Reserved|New Phy Mode ID|Checksum|Parity|
111+
*
112+
*/
113+
int8_t mac_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id)
31114
{
32-
(void) rf_ptr, (void) phy_mode_id;
115+
(void) rf_ptr;
33116
if (!data_ptr) {
34117
return -1;
35118
}
36-
37119
// - Write mode switch and PHY mode id fields
120+
uint16_t mode_switch_phr = 1 << SHIFT_MODE_SWITCH;
121+
mode_switch_phr |= phy_mode_id << SHIFT_MODE_SWITCH_PHY_MODE;
38122
// - Calculate checksum
123+
mode_switch_phr |= mac_calculate_mode_switch_checksum(mode_switch_phr) << SHIFT_MODE_SWITCH_CHECKSUM;
39124
// - Calculate parity
125+
mode_switch_phr |= mac_calculate_mode_switch_parity(mode_switch_phr) << SHIFT_MODE_SWITCH_PARITY;
126+
127+
common_write_16_bit_inverse(mode_switch_phr, data_ptr);
40128

41129
// - With successful return value, MAC should start CSMA-CA for a mode switch PHR
42130
return 0;
43131
}
44132

45-
int8_t ms_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len)
133+
int8_t mac_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len)
46134
{
47135
(void) rf_ptr;
48136
if (data_len != PHR_LEN) {
@@ -51,11 +139,25 @@ int8_t ms_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const
51139
if (!data_ptr) {
52140
return -1;
53141
}
54-
tr_info("Received mode switch PHR %s", trace_array(data_ptr, data_len));
55142

143+
uint16_t mode_switch_phr = common_read_16_bit_inverse(data_ptr);
144+
if (!(mode_switch_phr & MASK_MODE_SWITCH)) {
145+
// Mode switch not enabled
146+
return -1;
147+
}
56148
// - Validate checksum
149+
if (mac_calculate_mode_switch_checksum(mode_switch_phr) != ((mode_switch_phr & MASK_MODE_SWITCH_CHECKSUM) >> SHIFT_MODE_SWITCH_CHECKSUM)) {
150+
// Invalid checksum, TODO: error correction
151+
return -1;
152+
}
57153
// - Validate parity
154+
if (mac_calculate_mode_switch_parity(mode_switch_phr) != (mode_switch_phr & MASK_MODE_SWITCH_PARITY) >> SHIFT_MODE_SWITCH_PARITY) {
155+
// Invalid parity
156+
return -1;
157+
}
58158
// - Read PHY mode id
159+
uint8_t phy_mode_id = (mode_switch_phr & MASK_MODE_SWITCH_PHY_MODE) >> SHIFT_MODE_SWITCH_PHY_MODE;
160+
(void) phy_mode_id;
59161
// - Store current configuration
60162
// - Resolve new configuration
61163
// - Set new configuration
@@ -65,7 +167,7 @@ int8_t ms_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const
65167
return 0;
66168
}
67169

68-
void ms_update_mode_switch_state(protocol_interface_rf_mac_setup_s *rf_ptr)
170+
void mac_update_mode_switch_state(protocol_interface_rf_mac_setup_s *rf_ptr)
69171
{
70172
(void) rf_ptr;
71173
// MAC should call this after any transmission (TX done) and reception

source/MAC/IEEE802_15_4/mac_mode_switch.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,25 @@
1818
#ifndef MAC_MODE_SWITCH_H_
1919
#define MAC_MODE_SWITCH_H_
2020

21+
#define PHR_LEN 2
22+
23+
#define SHIFT_MODE_SWITCH_PARITY (15)
24+
#define SHIFT_MODE_SWITCH_CHECKSUM (11)
25+
#define SHIFT_MODE_SWITCH_PHY_MODE (3)
26+
#define SHIFT_MODE_SWITCH (0)
27+
#define MASK_MODE_SWITCH_PARITY (0x8000)
28+
#define MASK_MODE_SWITCH_CHECKSUM (0x7800)
29+
#define MASK_MODE_SWITCH_PHY_MODE (0x07F8)
30+
#define MASK_MODE_SWITCH (0x0001)
31+
2132
/**
2233
* @brief Build mode switch PHR.
2334
* @param rf_ptr Pointer to MAC instance.
2435
* @param data_ptr Pointer to data buffer.
2536
* @param phy_mode_id Used PHY mode id.
2637
* @return 0 - success, -1 - failure.
2738
*/
28-
int8_t ms_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id);
39+
int8_t mac_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id);
2940

3041
/**
3142
* @brief Parse mode switch PHR.
@@ -34,6 +45,12 @@ int8_t ms_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8
3445
* @param data_len Data length.
3546
* @return 0 - mode switch PHR found, -1 - mode switch PHR not found.
3647
*/
37-
int8_t ms_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len);
48+
int8_t mac_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len);
49+
50+
/**
51+
* @brief Update mode switch state.
52+
* @param rf_ptr Pointer to MAC instance.
53+
*/
54+
void mac_update_mode_switch_state(protocol_interface_rf_mac_setup_s *rf_ptr);
3855

3956
#endif /* MAC_MODE_SWITCH_H_ */

source/MAC/IEEE802_15_4/mac_pd_sap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
10431043
goto ERROR_HANDLER;
10441044
}
10451045

1046-
if (!ms_parse_mode_switch_phr(rf_ptr, pd_data_ind->data_ptr, pd_data_ind->data_len)) {
1046+
if (!mac_parse_mode_switch_phr(rf_ptr, pd_data_ind->data_ptr, pd_data_ind->data_len)) {
10471047
// TODO: mode switch returned 0, needs some logic to wait frame with new mode
10481048
goto ERROR_HANDLER;
10491049
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
include ../../makefile_defines.txt
2+
3+
COMPONENT_NAME = mac_mode_switch_unit
4+
5+
#This must be changed manually
6+
SRC_FILES = \
7+
../../../../../source/MAC/IEEE802_15_4/mac_mode_switch.c
8+
9+
TEST_SRC_FILES = \
10+
main.cpp \
11+
mac_mode_switch_test.cpp \
12+
test_mac_mode_switch.c \
13+
../../stub/mbed_trace_stub.c \
14+
15+
include ../../MakefileWorker.mk
16+
17+
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
18+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2021, Pelion and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include "CppUTest/TestHarness.h"
18+
#include "test_mac_mode_switch.h"
19+
20+
TEST_GROUP(mac_mode_switch)
21+
{
22+
void setup() {
23+
}
24+
25+
void teardown() {
26+
}
27+
};
28+
29+
TEST(mac_mode_switch, test_mac_calculate_mode_switch_checksum)
30+
{
31+
CHECK(test_mac_calculate_mode_switch_checksum());
32+
}
33+
34+
TEST(mac_mode_switch, test_mac_calculate_mode_switch_parity)
35+
{
36+
CHECK(test_mac_calculate_mode_switch_parity());
37+
}
38+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2021, Pelion and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "CppUTest/CommandLineTestRunner.h"
19+
#include "CppUTest/TestPlugin.h"
20+
#include "CppUTest/TestRegistry.h"
21+
#include "CppUTestExt/MockSupportPlugin.h"
22+
int main(int ac, char **av)
23+
{
24+
return CommandLineTestRunner::RunAllTests(ac, av);
25+
}
26+
27+
IMPORT_TEST_GROUP(mac_mode_switch);
28+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2020, Pelion and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include "nsconfig.h"
18+
#include "test_mac_mode_switch.h"
19+
#include "mac_defines.h"
20+
#include "nsdynmemLIB_stub.h"
21+
#include "MAC/IEEE802_15_4/mac_mode_switch.h"
22+
23+
static protocol_interface_rf_mac_setup_s mac_setup;
24+
25+
uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2])
26+
{
27+
uint16_t temp_16;
28+
temp_16 = *data_buf++;
29+
temp_16 += (uint16_t)(*data_buf++) << 8;
30+
return temp_16;
31+
}
32+
33+
uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2])
34+
{
35+
*ptr++ = value;
36+
*ptr++ = value >> 8;
37+
return ptr;
38+
}
39+
40+
static uint8_t test_parse_checksum(uint16_t mode_switch_phr)
41+
{
42+
return (mode_switch_phr & MASK_MODE_SWITCH_CHECKSUM) >> SHIFT_MODE_SWITCH_CHECKSUM;
43+
}
44+
45+
static uint8_t test_parse_parity(uint16_t mode_switch_phr)
46+
{
47+
return (mode_switch_phr & MASK_MODE_SWITCH_PARITY) >> SHIFT_MODE_SWITCH_PARITY;
48+
}
49+
50+
#define TEST_SEQUENCE_LENGTH 10
51+
52+
bool test_mac_calculate_mode_switch_checksum()
53+
{
54+
uint8_t test_data[2];
55+
uint8_t phy_modes[TEST_SEQUENCE_LENGTH] = {0x40, 0x54, 0x00, 0x01, 0xff, 0x55, 0x80, 0xa5, 0x5a, 0xda};
56+
uint8_t results[TEST_SEQUENCE_LENGTH] = {0x0f, 0x0e, 0x09, 0x07, 0x0d, 0x00, 0x0a, 0x02, 0x06, 0x05};
57+
for (int i = 0; i < TEST_SEQUENCE_LENGTH; i++) {
58+
mac_build_mode_switch_phr(&mac_setup, &test_data, phy_modes[i]);
59+
uint8_t checksum = test_parse_checksum(common_read_16_bit_inverse(test_data));
60+
if (checksum != results[i]) {
61+
printf("Fail: Mode switch PHR, PHY mode id %x, checksum %x, expected %x\r\n", phy_modes[i], checksum, results[i]);
62+
return false;
63+
}
64+
}
65+
return true;
66+
}
67+
68+
bool test_mac_calculate_mode_switch_parity()
69+
{
70+
uint8_t test_data[2];
71+
uint8_t phy_modes[TEST_SEQUENCE_LENGTH] = {0x40, 0x54, 0x00, 0x01, 0xff, 0x55, 0x80, 0xa5, 0x5a, 0xda};
72+
uint8_t results[TEST_SEQUENCE_LENGTH] = {0, 1, 1, 1, 0, 1, 0, 0, 1, 0};
73+
for (int i = 0; i < TEST_SEQUENCE_LENGTH; i++) {
74+
mac_build_mode_switch_phr(&mac_setup, &test_data, phy_modes[i]);
75+
uint8_t parity = test_parse_parity(common_read_16_bit_inverse(test_data));
76+
if (parity != results[i]) {
77+
printf("Fail: Mode switch PHR, PHY mode id %x, parity %x, expected %x\r\n", phy_modes[i], parity, results[i]);
78+
return false;
79+
}
80+
}
81+
return true;
82+
}
83+

0 commit comments

Comments
 (0)