From add86390495cd9ad1bac92eb85ae47e527758626 Mon Sep 17 00:00:00 2001 From: rongli Date: Sat, 24 Sep 2016 02:12:53 +0800 Subject: [PATCH] Support AutoPend for CC2538 (#562) --- examples/platforms/cc2538/cc2538-reg.h | 241 +++++++++++---------- examples/platforms/cc2538/radio.c | 283 ++++++++++++++++++++++++- examples/platforms/posix/radio.c | 43 ++++ include/platform/radio.h | 69 +++++- src/core/common/message.cpp | 3 +- src/core/mac/mac.cpp | 72 ++++++- src/core/mac/mac.hpp | 36 ++++ src/core/net/icmp6.cpp | 5 +- src/core/thread/mesh_forwarder.cpp | 172 ++++++++++++++- src/core/thread/mesh_forwarder.hpp | 6 + src/core/thread/mle_router.cpp | 1 + src/core/thread/topology.hpp | 3 + tests/unit/test_platform.cpp | 46 +++- 13 files changed, 853 insertions(+), 127 deletions(-) diff --git a/examples/platforms/cc2538/cc2538-reg.h b/examples/platforms/cc2538/cc2538-reg.h index 6330bf5ac..1b837dea7 100644 --- a/examples/platforms/cc2538/cc2538-reg.h +++ b/examples/platforms/cc2538/cc2538-reg.h @@ -37,151 +37,168 @@ #include -#define HWREG(x) (*((volatile uint32_t *)(x))) +#define HWREG(x) (*((volatile uint32_t *)(x))) -#define NVIC_ST_CTRL 0xE000E010 // SysTick Control and Status -#define NVIC_ST_RELOAD 0xE000E014 // SysTick Reload Value Register -#define NVIC_EN0 0xE000E100 // Interrupt 0-31 Set Enable +#define NVIC_ST_CTRL 0xE000E010 // SysTick Control and Status +#define NVIC_ST_RELOAD 0xE000E014 // SysTick Reload Value Register +#define NVIC_EN0 0xE000E100 // Interrupt 0-31 Set Enable -#define NVIC_ST_CTRL_COUNT 0x00010000 // Count Flag -#define NVIC_ST_CTRL_CLK_SRC 0x00000004 // Clock Source -#define NVIC_ST_CTRL_INTEN 0x00000002 // Interrupt Enable -#define NVIC_ST_CTRL_ENABLE 0x00000001 // Enable +#define NVIC_ST_CTRL_COUNT 0x00010000 // Count Flag +#define NVIC_ST_CTRL_CLK_SRC 0x00000004 // Clock Source +#define NVIC_ST_CTRL_INTEN 0x00000002 // Interrupt Enable +#define NVIC_ST_CTRL_ENABLE 0x00000001 // Enable -#define INT_UART0 21 // UART0 Rx and Tx +#define RFCORE_XREG_SRCMATCH_EN 0x00000001 // SRCMATCH.SRC_MATCH_EN(1) +#define RFCORE_XREG_SRCMATCH_AUTOPEND 0x00000002 // SRCMATCH.AUTOPEND(1) +#define RFCORE_XREG_SRCMATCH_PEND_DATAREQ_ONLY 0x00000004 // SRCMATCH.PEND_DATAREQ_ONLY(1) -#define IEEE_EUI64 0x00280028 // Address of IEEE EUI-64 address +#define RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE 3 // Num of register for source match enable status +#define RFCORE_XREG_SRCMATCH_SHORT_ENTRIES 24 // 24 short address entries in maximum +#define RFCORE_XREG_SRCMATCH_EXT_ENTRIES 12 // 12 extended address entries in maximum +#define RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET 4 // address offset for one short address entry +#define RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET 8 // address offset for one extended address entry -#define RFCORE_FFSM_EXT_ADDR0 0x400885A8 // Local address information -#define RFCORE_FFSM_PAN_ID0 0x400885C8 // Local address information -#define RFCORE_FFSM_PAN_ID1 0x400885CC // Local address information -#define RFCORE_FFSM_SHORT_ADDR0 0x400885D0 // Local address information -#define RFCORE_FFSM_SHORT_ADDR1 0x400885D4 // Local address information -#define RFCORE_XREG_FRMFILT0 0x40088600 // The frame filtering function -#define RFCORE_XREG_SRCMATCH 0x40088608 // Source address matching and pending bits -#define RFCORE_XREG_FRMCTRL0 0x40088624 // Frame handling -#define RFCORE_XREG_FRMCTRL1 0x40088628 // Frame handling -#define RFCORE_XREG_RXENABLE 0x4008862C // RX enabling -#define RFCORE_XREG_FREQCTRL 0x4008863C // Controls the RF frequency -#define RFCORE_XREG_FSMSTAT1 0x4008864C // Radio status register -#define RFCORE_XREG_FIFOPCTRL 0x40088650 // FIFOP threshold -#define RFCORE_XREG_CCACTRL0 0x40088658 // CCA threshold -#define RFCORE_XREG_RSSISTAT 0x40088664 // RSSI valid status register -#define RFCORE_XREG_AGCCTRL1 0x400886C8 // AGC reference level -#define RFCORE_XREG_TXFILTCFG 0x400887E8 // TX filter configuration -#define RFCORE_XREG_RFRND 0x4008869C // Random data -#define RFCORE_SFR_RFDATA 0x40088828 // The TX FIFO and RX FIFO -#define RFCORE_SFR_RFERRF 0x4008882C // RF error interrupt flags -#define RFCORE_SFR_RFIRQF0 0x40088834 // RF interrupt flags -#define RFCORE_SFR_RFST 0x40088838 // RF CSMA-CA/strobe processor +#define INT_UART0 21 // UART0 Rx and Tx -#define RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN 0x00000001 // Enables frame filtering +#define IEEE_EUI64 0x00280028 // Address of IEEE EUI-64 address -#define RFCORE_XREG_FRMCTRL0_AUTOACK 0x00000020 -#define RFCORE_XREG_FRMCTRL0_AUTOCRC 0x00000040 -#define RFCORE_XREG_FRMCTRL0_INFINITY_RX 0x00000008 +#define RFCORE_FFSM_SRCADDRESS_TABLE 0x40088400 // Source Address Table -#define RFCORE_XREG_FRMCTRL1_PENDING_OR 0x00000004 +#define RFCORE_FFSM_SRCEXTPENDEN0 0x4008858C // Enable/Disable automatic pending per extended address +#define RFCORE_FFSM_SRCSHORTPENDEN0 0x4008859C // Enable/Disable automatic pending per short address +#define RFCORE_FFSM_EXT_ADDR0 0x400885A8 // Local address information +#define RFCORE_FFSM_PAN_ID0 0x400885C8 // Local address information +#define RFCORE_FFSM_PAN_ID1 0x400885CC // Local address information +#define RFCORE_FFSM_SHORT_ADDR0 0x400885D0 // Local address information +#define RFCORE_FFSM_SHORT_ADDR1 0x400885D4 // Local address information +#define RFCORE_XREG_FRMFILT0 0x40088600 // The frame filtering function +#define RFCORE_XREG_SRCMATCH 0x40088608 // Source address matching and pending bits +#define RFCORE_XREG_SRCSHORTEN0 0x4008860C // Short address matching +#define RFCORE_XREG_SRCEXTEN0 0x40088618 // Extended address matching -#define RFCORE_XREG_RFRND_IRND 0x00000001 +#define RFCORE_XREG_FRMCTRL0 0x40088624 // Frame handling +#define RFCORE_XREG_FRMCTRL1 0x40088628 // Frame handling +#define RFCORE_XREG_RXENABLE 0x4008862C // RX enabling +#define RFCORE_XREG_FREQCTRL 0x4008863C // Controls the RF frequency +#define RFCORE_XREG_FSMSTAT1 0x4008864C // Radio status register +#define RFCORE_XREG_FIFOPCTRL 0x40088650 // FIFOP threshold +#define RFCORE_XREG_CCACTRL0 0x40088658 // CCA threshold +#define RFCORE_XREG_RSSISTAT 0x40088664 // RSSI valid status register +#define RFCORE_XREG_AGCCTRL1 0x400886C8 // AGC reference level +#define RFCORE_XREG_TXFILTCFG 0x400887E8 // TX filter configuration +#define RFCORE_XREG_RFRND 0x4008869C // Random data +#define RFCORE_SFR_RFDATA 0x40088828 // The TX FIFO and RX FIFO +#define RFCORE_SFR_RFERRF 0x4008882C // RF error interrupt flags +#define RFCORE_SFR_RFIRQF0 0x40088834 // RF interrupt flags +#define RFCORE_SFR_RFST 0x40088838 // RF CSMA-CA/strobe processor -#define RFCORE_XREG_FSMSTAT1_TX_ACTIVE 0x00000002 -#define RFCORE_XREG_FSMSTAT1_CCA 0x00000010 // Clear channel assessment -#define RFCORE_XREG_FSMSTAT1_SFD 0x00000020 -#define RFCORE_XREG_FSMSTAT1_FIFOP 0x00000040 -#define RFCORE_XREG_FSMSTAT1_FIFO 0x00000080 +#define RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN 0x00000001 // Enables frame filtering -#define RFCORE_XREG_RSSISTAT_RSSI_VALID 0x00000001 // RSSI value is valid. +#define RFCORE_XREG_FRMCTRL0_AUTOACK 0x00000020 +#define RFCORE_XREG_FRMCTRL0_AUTOCRC 0x00000040 +#define RFCORE_XREG_FRMCTRL0_INFINITY_RX 0x00000008 -#define RFCORE_SFR_RFERRF_RXOVERF 0x00000004 // RX FIFO overflowed. +#define RFCORE_XREG_FRMCTRL1_PENDING_OR 0x00000004 -#define RFCORE_SFR_RFST_INSTR_RXON 0xE3 // Instruction set RX on -#define RFCORE_SFR_RFST_INSTR_TXON 0xE9 // Instruction set TX on -#define RFCORE_SFR_RFST_INSTR_RFOFF 0xEF // Instruction set RF off -#define RFCORE_SFR_RFST_INSTR_FLUSHRX 0xED // Instruction set flush rx buffer -#define RFCORE_SFR_RFST_INSTR_FLUSHTX 0xEE // Instruction set flush tx buffer +#define RFCORE_XREG_RFRND_IRND 0x00000001 -#define ANA_REGS_BASE 0x400D6000 // ANA_REGS -#define ANA_REGS_O_IVCTRL 0x00000004 // Analog control register +#define RFCORE_XREG_FSMSTAT1_TX_ACTIVE 0x00000002 +#define RFCORE_XREG_FSMSTAT1_CCA 0x00000010 // Clear channel assessment +#define RFCORE_XREG_FSMSTAT1_SFD 0x00000020 +#define RFCORE_XREG_FSMSTAT1_FIFOP 0x00000040 +#define RFCORE_XREG_FSMSTAT1_FIFO 0x00000080 -#define SYS_CTRL_CLOCK_CTRL 0x400D2000 // The clock control register -#define SYS_CTRL_SYSDIV_32MHZ 0x00000000 // Sys_div for sysclk 32MHz -#define SYS_CTRL_CLOCK_CTRL_AMP_DET 0x00200000 +#define RFCORE_XREG_RSSISTAT_RSSI_VALID 0x00000001 // RSSI value is valid. -#define SYS_CTRL_PWRDBG 0x400D2074 -#define SYS_CTRL_PWRDBG_FORCE_WARM_RESET 0x00000008 +#define RFCORE_SFR_RFERRF_RXOVERF 0x00000004 // RX FIFO overflowed. -#define SYS_CTRL_RCGCUART 0x400D2028 -#define SYS_CTRL_SCGCUART 0x400D202C -#define SYS_CTRL_DCGCUART 0x400D2030 -#define SYS_CTRL_I_MAP 0x400D2098 -#define SYS_CTRL_RCGCRFC 0x400D20A8 -#define SYS_CTRL_SCGCRFC 0x400D20AC -#define SYS_CTRL_DCGCRFC 0x400D20B0 -#define SYS_CTRL_EMUOVR 0x400D20B4 +#define RFCORE_SFR_RFST_INSTR_RXON 0xE3 // Instruction set RX on +#define RFCORE_SFR_RFST_INSTR_TXON 0xE9 // Instruction set TX on +#define RFCORE_SFR_RFST_INSTR_RFOFF 0xEF // Instruction set RF off +#define RFCORE_SFR_RFST_INSTR_FLUSHRX 0xED // Instruction set flush rx buffer +#define RFCORE_SFR_RFST_INSTR_FLUSHTX 0xEE // Instruction set flush tx buffer -#define SYS_CTRL_RCGCRFC_RFC0 0x00000001 -#define SYS_CTRL_SCGCRFC_RFC0 0x00000001 -#define SYS_CTRL_DCGCRFC_RFC0 0x00000001 +#define ANA_REGS_BASE 0x400D6000 // ANA_REGS +#define ANA_REGS_O_IVCTRL 0x00000004 // Analog control register -#define SYS_CTRL_I_MAP_ALTMAP 0x00000001 +#define SYS_CTRL_CLOCK_CTRL 0x400D2000 // The clock control register +#define SYS_CTRL_SYSDIV_32MHZ 0x00000000 // Sys_div for sysclk 32MHz +#define SYS_CTRL_CLOCK_CTRL_AMP_DET 0x00200000 -#define SYS_CTRL_RCGCUART_UART0 0x00000001 -#define SYS_CTRL_SCGCUART_UART0 0x00000001 -#define SYS_CTRL_DCGCUART_UART0 0x00000001 +#define SYS_CTRL_PWRDBG 0x400D2074 +#define SYS_CTRL_PWRDBG_FORCE_WARM_RESET 0x00000008 -#define IOC_PA0_SEL 0x400D4000 // Peripheral select control -#define IOC_PA1_SEL 0x400D4004 // Peripheral select control -#define IOC_UARTRXD_UART0 0x400D4100 +#define SYS_CTRL_RCGCUART 0x400D2028 +#define SYS_CTRL_SCGCUART 0x400D202C +#define SYS_CTRL_DCGCUART 0x400D2030 +#define SYS_CTRL_I_MAP 0x400D2098 +#define SYS_CTRL_RCGCRFC 0x400D20A8 +#define SYS_CTRL_SCGCRFC 0x400D20AC +#define SYS_CTRL_DCGCRFC 0x400D20B0 +#define SYS_CTRL_EMUOVR 0x400D20B4 -#define IOC_PA0_OVER 0x400D4080 -#define IOC_PA1_OVER 0x400D4084 +#define SYS_CTRL_RCGCRFC_RFC0 0x00000001 +#define SYS_CTRL_SCGCRFC_RFC0 0x00000001 +#define SYS_CTRL_DCGCRFC_RFC0 0x00000001 -#define IOC_MUX_OUT_SEL_UART0_TXD 0x00000000 +#define SYS_CTRL_I_MAP_ALTMAP 0x00000001 -#define IOC_OVERRIDE_OE 0x00000008 // PAD Config Override Output Enable -#define IOC_OVERRIDE_DIS 0x00000000 // PAD Config Override Disabled +#define SYS_CTRL_RCGCUART_UART0 0x00000001 +#define SYS_CTRL_SCGCUART_UART0 0x00000001 +#define SYS_CTRL_DCGCUART_UART0 0x00000001 -#define UART0_BASE 0x4000C000 -#define GPIO_A_BASE 0x400D9000 // GPIO +#define IOC_PA0_SEL 0x400D4000 // Peripheral select control +#define IOC_PA1_SEL 0x400D4004 // Peripheral select control +#define IOC_UARTRXD_UART0 0x400D4100 -#define GPIO_O_DIR 0x00000400 -#define GPIO_O_AFSEL 0x00000420 +#define IOC_PA0_OVER 0x400D4080 +#define IOC_PA1_OVER 0x400D4084 -#define GPIO_PIN_0 0x00000001 // GPIO pin 0 -#define GPIO_PIN_1 0x00000002 // GPIO pin 1 +#define IOC_MUX_OUT_SEL_UART0_TXD 0x00000000 -#define UART_O_DR 0x00000000 // UART data -#define UART_O_FR 0x00000018 // UART flag -#define UART_O_IBRD 0x00000024 -#define UART_O_FBRD 0x00000028 -#define UART_O_LCRH 0x0000002C -#define UART_O_CTL 0x00000030 // UART control -#define UART_O_IM 0x00000038 // UART interrupt mask -#define UART_O_MIS 0x00000040 // UART masked interrupt status -#define UART_O_ICR 0x00000044 // UART interrupt clear -#define UART_O_CC 0x00000FC8 // UART clock configuration +#define IOC_OVERRIDE_OE 0x00000008 // PAD Config Override Output Enable +#define IOC_OVERRIDE_DIS 0x00000000 // PAD Config Override Disabled -#define UART_FR_RXFE 0x00000010 // UART receive FIFO empty -#define UART_FR_TXFF 0x00000020 // UART transmit FIFO full -#define UART_FR_RXFF 0x00000040 // UART receive FIFO full +#define UART0_BASE 0x4000C000 +#define GPIO_A_BASE 0x400D9000 // GPIO -#define UART_CONFIG_WLEN_8 0x00000060 // 8 bit data -#define UART_CONFIG_STOP_ONE 0x00000000 // One stop bit -#define UART_CONFIG_PAR_NONE 0x00000000 // No parity +#define GPIO_O_DIR 0x00000400 +#define GPIO_O_AFSEL 0x00000420 -#define UART_CTL_UARTEN 0x00000001 // UART enable -#define UART_CTL_TXE 0x00000100 // UART transmit enable -#define UART_CTL_RXE 0x00000200 // UART receive enable +#define GPIO_PIN_0 0x00000001 // GPIO pin 0 +#define GPIO_PIN_1 0x00000002 // GPIO pin 1 -#define UART_IM_RXIM 0x00000010 // UART receive interrupt mask -#define UART_IM_RTIM 0x00000040 // UART receive time-out interrupt +#define UART_O_DR 0x00000000 // UART data +#define UART_O_FR 0x00000018 // UART flag +#define UART_O_IBRD 0x00000024 +#define UART_O_FBRD 0x00000028 +#define UART_O_LCRH 0x0000002C +#define UART_O_CTL 0x00000030 // UART control +#define UART_O_IM 0x00000038 // UART interrupt mask +#define UART_O_MIS 0x00000040 // UART masked interrupt status +#define UART_O_ICR 0x00000044 // UART interrupt clear +#define UART_O_CC 0x00000FC8 // UART clock configuration -#define SOC_ADC_ADCCON1 0x400D7000 // ADC Control -#define SOC_ADC_RNDL 0x400D7014 // RNG low data -#define SOC_ADC_RNDH 0x400D7018 // RNG high data +#define UART_FR_RXFE 0x00000010 // UART receive FIFO empty +#define UART_FR_TXFF 0x00000020 // UART transmit FIFO full +#define UART_FR_RXFF 0x00000040 // UART receive FIFO full -#define SOC_ADC_ADCCON1_RCTRL0 0x00000004 // ADCCON1 RCTRL bit 0 -#define SOC_ADC_ADCCON1_RCTRL1 0x00000008 // ADCCON1 RCTRL bit 1 +#define UART_CONFIG_WLEN_8 0x00000060 // 8 bit data +#define UART_CONFIG_STOP_ONE 0x00000000 // One stop bit +#define UART_CONFIG_PAR_NONE 0x00000000 // No parity + +#define UART_CTL_UARTEN 0x00000001 // UART enable +#define UART_CTL_TXE 0x00000100 // UART transmit enable +#define UART_CTL_RXE 0x00000200 // UART receive enable + +#define UART_IM_RXIM 0x00000010 // UART receive interrupt mask +#define UART_IM_RTIM 0x00000040 // UART receive time-out interrupt + +#define SOC_ADC_ADCCON1 0x400D7000 // ADC Control +#define SOC_ADC_RNDL 0x400D7014 // RNG low data +#define SOC_ADC_RNDH 0x400D7018 // RNG high data + +#define SOC_ADC_ADCCON1_RCTRL0 0x00000004 // ADCCON1 RCTRL bit 0 +#define SOC_ADC_ADCCON1_RCTRL1 0x00000008 // ADCCON1 RCTRL bit 1 #endif diff --git a/examples/platforms/cc2538/radio.c b/examples/platforms/cc2538/radio.c index 87326940b..02ecf48fa 100644 --- a/examples/platforms/cc2538/radio.c +++ b/examples/platforms/cc2538/radio.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include "platform-cc2538.h" @@ -193,10 +194,9 @@ void cc2538RadioInit(void) HWREG(RFCORE_XREG_FIFOPCTRL) = IEEE802154_MAX_LENGTH; HWREG(RFCORE_XREG_FRMCTRL0) = RFCORE_XREG_FRMCTRL0_AUTOCRC | RFCORE_XREG_FRMCTRL0_AUTOACK; - HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR; - // disable source address matching - HWREG(RFCORE_XREG_SRCMATCH) = 0; + // default: SRCMATCH.SRC_MATCH_EN(1), SRCMATCH.AUTOPEND(1), + // SRCMATCH.PEND_DATAREQ_ONLY(1), RFCORE_XREG_FRMCTRL1_PENDING_OR(0) } ThreadError otPlatRadioEnable(otInstance *aInstance) @@ -460,3 +460,280 @@ void RFCoreErrIntHandler(void) { HWREG(RFCORE_SFR_RFERRF) = 0; } + +uint32_t getSrcMatchEntriesEnableStatus(bool aShort) +{ + uint32_t status = 0; + uint32_t *addr = aShort ? (uint32_t *) RFCORE_XREG_SRCSHORTEN0 : (uint32_t *) RFCORE_XREG_SRCEXTEN0; + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) + { + status |= HWREG(addr++) << (i * 8); + } + + return status; +} + +int8_t findSrcMatchShortEntry(const uint16_t aShortAddress) +{ + int8_t entry = -1; + uint16_t shortAddr; + uint32_t bitMask; + uint32_t *addr = NULL; + uint32_t status = getSrcMatchEntriesEnableStatus(true); + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) + { + bitMask = 0x00000001 << i; + + if ((status & bitMask) == 0) + { + continue; + } + + addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); + + shortAddr = HWREG(addr + 2); + shortAddr |= HWREG(addr + 3) << 8; + + if ((shortAddr == aShortAddress)) + { + ExitNow(entry = i); + } + } + +exit: + return entry; +} + +int8_t findSrcMatchExtEntry(const uint8_t *aExtAddress) +{ + int8_t entry = -1; + uint32_t bitMask; + uint32_t *addr = NULL; + uint32_t status = getSrcMatchEntriesEnableStatus(false); + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) + { + uint8_t j = 0; + bitMask = 0x00000001 << 2 * i; + + if ((status & bitMask) == 0) + { + continue; + } + + addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); + + for (j = 0; j < sizeof(otExtAddress); j++) + { + if (HWREG(addr + j) != aExtAddress[j]) + { + break; + } + } + + if (j == sizeof(otExtAddress)) + { + ExitNow(entry = i); + } + } + +exit: + return entry; +} + +void setSrcMatchEntryEnableStatus(bool aShort, uint8_t aEntry, bool aEnable) +{ + uint8_t entry = aShort ? aEntry : (2 * aEntry); + uint8_t index = entry / 8; + uint32_t *addrEn = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0; + uint32_t *addrAutoPendEn = aShort ? (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0 : (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; + uint32_t bitMask = 0x00000001; + + if (aEnable) + { + HWREG(addrEn + index) |= (bitMask) << (entry % 8); + HWREG(addrAutoPendEn + index) |= (bitMask) << (entry % 8); + } + else + { + HWREG(addrEn + index) &= ~((bitMask) << (entry % 8)); + HWREG(addrAutoPendEn + index) &= ~((bitMask) << (entry % 8)); + } +} + +int8_t findSrcMatchAvailEntry(bool aShort) +{ + int8_t entry = -1; + uint32_t bitMask; + uint32_t shortEnableStatus = getSrcMatchEntriesEnableStatus(true); + uint32_t extEnableStatus = getSrcMatchEntriesEnableStatus(false); + + otLogDebgMac("Short enable status: 0x%x\n", shortEnableStatus); + otLogDebgMac("Ext enable status: 0x%x\n", extEnableStatus); + + if (aShort) + { + bitMask = 0x00000001; + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) + { + if ((extEnableStatus & bitMask) == 0) + { + if ((shortEnableStatus & bitMask) == 0) + { + ExitNow(entry = i); + } + } + + if (i % 2 == 1) + { + extEnableStatus = extEnableStatus >> 2; + } + + shortEnableStatus = shortEnableStatus >> 1; + } + } + else + { + bitMask = 0x00000003; + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) + { + if (((extEnableStatus | shortEnableStatus) & bitMask) == 0) + { + ExitNow(entry = i); + } + + extEnableStatus = extEnableStatus >> 2; + shortEnableStatus = shortEnableStatus >> 2; + } + } + +exit: + return entry; +} + +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + (void)aInstance; + + if (aEnable) + { + // only set FramePending when ack for data poll if there are queued messages + // for entries in the source match table. + HWREG(RFCORE_XREG_FRMCTRL1) &= ~RFCORE_XREG_FRMCTRL1_PENDING_OR; + } + else + { + // set FramePending for all ack. + HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR; + } +} + +ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + ThreadError error = kThreadError_None; + int8_t entry = findSrcMatchAvailEntry(true); + uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; + (void)aInstance; + + otLogDebgMac("Available short address entry: %d\n", entry); + + VerifyOrExit(entry >= 0, error = kThreadError_NoBufs); + + addr += (entry * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); + + HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID0); + HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID1); + HWREG(addr++) = aShortAddress & 0xFF; + HWREG(addr++) = aShortAddress >> 8; + + setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), true); + +exit: + return error; +} + +ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + ThreadError error = kThreadError_None; + int8_t entry = findSrcMatchAvailEntry(false); + uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; + (void)aInstance; + + otLogDebgMac("Available extended address entry: %d\n", entry); + + VerifyOrExit(entry >= 0, error = kThreadError_NoBufs); + + addr += (entry * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); + + for (uint8_t i = 0; i < sizeof(otExtAddress); i++) + { + HWREG(addr++) = aExtAddress[i]; + } + + setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), true); + +exit: + return error; +} + +ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + ThreadError error = kThreadError_None; + int8_t entry = findSrcMatchShortEntry(aShortAddress); + (void)aInstance; + + otLogDebgMac("Found short address entry: %d\n", entry); + + VerifyOrExit(entry >= 0, error = kThreadError_NoAddress); + + setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), false); + +exit: + return error; +} + +ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + ThreadError error = kThreadError_None; + int8_t entry = findSrcMatchExtEntry(aExtAddress); + (void)aInstance; + + otLogDebgMac("Found ext address entry: %d\n", entry); + + VerifyOrExit(entry >= 0, error = kThreadError_NoAddress); + + setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), false); + +exit: + return error; +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCSHORTEN0; + uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0; + (void)aInstance; + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) + { + HWREG(addrEn++) = 0; + HWREG(addrAutoPendEn++) = 0; + } +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCEXTEN0; + uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; + (void)aInstance; + + for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) + { + HWREG(addrEn++) = 0; + HWREG(addrAutoPendEn++) = 0; + } +} diff --git a/examples/platforms/posix/radio.c b/examples/platforms/posix/radio.c index fa5fb86b4..9be10a34c 100644 --- a/examples/platforms/posix/radio.c +++ b/examples/platforms/posix/radio.c @@ -682,3 +682,46 @@ exit: } } +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + (void)aInstance; + (void)aEnable; +} + +ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + (void)aInstance; +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + (void)aInstance; +} diff --git a/include/platform/radio.h b/include/platform/radio.h index fccaecfcf..03c83919f 100644 --- a/include/platform/radio.h +++ b/include/platform/radio.h @@ -254,8 +254,75 @@ ThreadError otPlatRadioSleep(otInstance *aInstance); ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel); /** - * The radio driver calls this method to notify OpenThread of a received packet. + * Enable/Disable source match for AutoPend. * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aEnable Enable/disable source match for automatical pending. + */ +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable); + +/** + * Adding short address to the source match table. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aShortAddress The short address to be added. + * + * @retval ::kThreadError_None Successfully added short address to the source match table. + * @retval ::kThreadError_NoBufs No available entry in the source match table. + */ +ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress); + +/** + * Adding extended address to the source match table. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aExtAddress The extended address to be added. + * + * @retval ::kThreadError_None Successfully added extended address to the source match table. + * @retval ::kThreadError_NoBufs No available entry in the source match table. + */ +ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress); + +/** + * Removing short address to the source match table. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aShortAddress The short address to be removed. + * + * @retval ::kThreadError_None Successfully removed short address from the source match table. + * @retval ::kThreadError_NoAddress The short address is not in source match table. + */ +ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress); + +/** + * Removing extended address to the source match table of the radio. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aExtAddress The extended address to be removed. + * + * @retval ::kThreadError_None Successfully removed the extended address from the source match table. + * @retval ::kThreadError_NoAddress The extended address is not in source match table. + */ +ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress); + +/** + * Removing all the short addresses from the source match table. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance); + +/** + * Removing all the extended addresses from the source match table. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance); + +/** + * The radio driver calls this method to notify OpenThread of a received packet. * * @param[in] aInstance The OpenThread instance structure. * @param[in] aPacket A pointer to the received packet or NULL if the receive operation was aborted. diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 7404cc9f0..c09614516 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include namespace Thread { @@ -84,7 +85,7 @@ Buffer *MessagePool::NewBuffer(void) { Buffer *buffer = NULL; - VerifyOrExit(mFreeBuffers != NULL, ;); + VerifyOrExit(mFreeBuffers != NULL, otLogInfoMac("No available message buffer\n")); buffer = mFreeBuffers; mFreeBuffers = mFreeBuffers->GetNextBuffer(); diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 750a0d824..f5ccea48d 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -692,10 +692,6 @@ void Mac::TransmitDoneTask(bool aRxPending, ThreadError aError) { mReceiveTimer.Start(kDataPollTimeout); } - else - { - mReceiveTimer.Stop(); - } // fall through @@ -907,6 +903,7 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr, aFrame.GetSecurityLevel(securityLevel); aFrame.GetFrameCounter(frameCounter); + otLogDebgMac("Frame counter %u\n", frameCounter); aFrame.GetKeyIdMode(keyIdMode); @@ -1036,6 +1033,8 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) break; case sizeof(ShortAddress): + otLogDebgMac("Received from short address %x\n", srcaddr.mShortAddress); + if (neighbor == NULL) { otLogDebgMac("drop not neighbor\n"); @@ -1272,5 +1271,70 @@ otMacCounters &Mac::GetCounters(void) return mCounters; } +void Mac::EnableSrcMatch(bool aEnable) +{ + otPlatRadioEnableSrcMatch(NULL, aEnable); + otLogDebgMac("Enable SrcMatch -- %d(0:Dis, 1:En)\n", aEnable); +} + +ThreadError Mac::AddSrcMatchEntry(Address &aAddr) +{ + ThreadError error = kThreadError_None; + + if (aAddr.mLength == 2) + { + error = otPlatRadioAddSrcMatchShortEntry(NULL, aAddr.mShortAddress); + otLogDebgMac("Adding short address: 0x%x -- %d (0:Ok, 3:NoBufs)\n", aAddr.mShortAddress, error); + } + else + { + uint8_t buf[8]; + + for (uint8_t i = 0; i < sizeof(buf); i++) + { + buf[i] = aAddr.mExtAddress.m8[7 - i]; + } + + error = otPlatRadioAddSrcMatchExtEntry(NULL, buf); + otLogDebgMac("Adding extended address: 0x%02x%02x%02x%02x%02x%02x%02x%02x -- %d (0:OK, 3:NoBufs)\n", + buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0], error); + } + + return error; +} + +ThreadError Mac::ClearSrcMatchEntry(Address &aAddr) +{ + ThreadError error = kThreadError_None; + + if (aAddr.mLength == 2) + { + error = otPlatRadioClearSrcMatchShortEntry(NULL, aAddr.mShortAddress); + otLogDebgMac("Clearing short address: 0x%x -- %d (0:OK, 10:NoAddress)\n", aAddr.mShortAddress, error); + } + else + { + uint8_t buf[8]; + + for (uint8_t i = 0; i < sizeof(buf); i++) + { + buf[i] = aAddr.mExtAddress.m8[7 - i]; + } + + error = otPlatRadioClearSrcMatchExtEntry(NULL, buf); + otLogDebgMac("Clearing extended address: 0x%02x%02x%02x%02x%02x%02x%02x%02x -- %d (0:OK, 10:NoAddress)\n", + buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0], error); + } + + return error; +} + +void Mac::ClearSrcMatchEntries() +{ + otPlatRadioClearSrcMatchShortEntries(NULL); + otPlatRadioClearSrcMatchExtEntries(NULL); + otLogDebgMac("Clearing source match table"); +} + } // namespace Mac } // namespace Thread diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 865bea9a2..5e8553130 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -502,6 +502,42 @@ public: */ LinkQualityInfo &GetNoiseFloor(void) { return mNoiseFloor; } + /** + * This function enable/disable source match. + * + * @param[in] aEnable Enable/disable source match for automatical pending. + * + */ + void EnableSrcMatch(bool aEnable); + + /** + * This function adds the address into the source match table. + * + * @param[in] aAddr The address to be added into the source match table. + * + * @retval ::kThreadError_None Successfully added the address into the source match table. + * @retval ::kThreadError_NoBufs No available entry in the source match table + * + */ + ThreadError AddSrcMatchEntry(Address &aAddr); + + /** + * This function removes the address from the source match table. + * + * @param[in] aAddr The address to be removed from the source match table. + * + * @retval ::kThreadError_None Successfully removed the address from the source match table. + * @retval ::kThreadError_NoAddress The address is not in the source match table. + * + */ + ThreadError ClearSrcMatchEntry(Address &aAddr); + + /** + * This function emptys the source match table. + * + */ + void ClearSrcMatchEntries(); + private: enum ScanType { diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index 5ddd25538..839bb1fff 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -102,7 +102,7 @@ ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessage aMessage.SetOffset(0); SuccessOrExit(error = mIp6.SendDatagram(aMessage, messageInfoLocal, kProtoIcmp6)); - otLogInfoIcmp("Sent echo request\n"); + otLogInfoIcmp("Sent echo request: (seq = %d)\n", icmpHeader.GetSequence()); exit: return error; @@ -226,7 +226,8 @@ ThreadError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo SuccessOrExit(error = mIp6.SendDatagram(*replyMessage, replyMessageInfo, kProtoIcmp6)); - otLogInfoIcmp("Sent Echo Reply\n"); + replyMessage->Read(replyMessage->GetOffset(), sizeof(icmp6Header), &icmp6Header); + otLogInfoIcmp("Sent Echo Reply (seq = %d)\n", icmp6Header.GetSequence()); exit: diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 072ffa5cf..53293c115 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -78,6 +78,9 @@ MeshForwarder::MeshForwarder(ThreadNetif &aThreadNetif): mMeshDest = Mac::kShortAddrInvalid; mAddMeshHeader = false; + mMac.EnableSrcMatch(true); + mSrcMatchEnabled = true; + mMac.RegisterReceiver(mMacReceiver); } @@ -205,6 +208,116 @@ exit: (void) error; } +ThreadError MeshForwarder::AddPendingSrcMatchEntries() +{ + uint8_t numChildren; + Child *children = NULL; + ThreadError error = kThreadError_NoBufs; + + children = mMle.GetChildren(&numChildren); + + // Add pending short address first + for (uint8_t i = 0; i < numChildren; i++) + { + if (children[i].mState == Child::kStateValid && + children[i].mAddSrcMatchEntryPending && + children[i].mAddSrcMatchEntryShort) + { + VerifyOrExit(((error = AddSrcMatchEntry(children[i])) == kThreadError_None), ;); + } + } + + // Add pending extended address + for (uint8_t i = 0; i < numChildren; i++) + { + if (children[i].mState == Child::kStateValid && + children[i].mAddSrcMatchEntryPending && + !children[i].mAddSrcMatchEntryShort) + { + VerifyOrExit(((error = AddSrcMatchEntry(children[i])) == kThreadError_None), ;); + } + } + +exit: + return error; +} + +ThreadError MeshForwarder::AddSrcMatchEntry(Child &aChild) +{ + ThreadError error = kThreadError_NoBufs; + Mac::Address macAddr; + + otLogDebgMac("Queuing for child (0x%x)\n", aChild.mValid.mRloc16); + otLogDebgMac("SrcMatch %d (0:Dis, 1:En))\n", mSrcMatchEnabled); + + // first queued message, to be added into source match table + if (aChild.mQueuedIndirectMessageCnt == 1) + { + aChild.mAddSrcMatchEntryPending = true; + } + + VerifyOrExit(aChild.mAddSrcMatchEntryPending, ;); + + if (aChild.mAddSrcMatchEntryShort) + { + macAddr.mLength = sizeof(macAddr.mShortAddress); + macAddr.mShortAddress = aChild.mValid.mRloc16; + } + else + { + macAddr.mLength = sizeof(macAddr.mExtAddress); + memcpy(macAddr.mExtAddress.m8, aChild.mMacAddr.m8, sizeof(macAddr.mExtAddress)); + } + + if ((error = mMac.AddSrcMatchEntry(macAddr)) == kThreadError_None) + { + // succeed in adding to source match table + aChild.mAddSrcMatchEntryPending = false; + } + else + { + if (mSrcMatchEnabled) + { + mMac.EnableSrcMatch(false); + mSrcMatchEnabled = false; + } + } + +exit: + return error; +} + +void MeshForwarder::ClearSrcMatchEntry(Child &aChild) +{ + Mac::Address macAddr; + otLogDebgMac("SrcMatch %d (0:Dis, 1:En))\n", mSrcMatchEnabled); + + if (aChild.mAddSrcMatchEntryShort) + { + macAddr.mLength = sizeof(macAddr.mShortAddress); + macAddr.mShortAddress = aChild.mValid.mRloc16; + } + else + { + macAddr.mLength = sizeof(macAddr.mExtAddress); + memcpy(macAddr.mExtAddress.m8, aChild.mMacAddr.m8, sizeof(macAddr.mExtAddress)); + } + + if (mMac.ClearSrcMatchEntry(macAddr) == kThreadError_None) + { + if (!mSrcMatchEnabled && (AddPendingSrcMatchEntries() == kThreadError_None)) + { + mMac.EnableSrcMatch(true); + mSrcMatchEnabled = true; + } + } + else + { + // if finished queued messages for SED which is not added into the source match table + aChild.mAddSrcMatchEntryPending = false; + } +} + ThreadError MeshForwarder::SendMessage(Message &aMessage) { ThreadError error = kThreadError_None; @@ -233,6 +346,8 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) { if (children[i].mState == Neighbor::kStateValid && (children[i].mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) { + children[i].mQueuedIndirectMessageCnt++; + AddSrcMatchEntry(children[i]); aMessage.SetChildMask(i); } } @@ -241,7 +356,11 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) (neighbor->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) { // destined for a sleepy child - aMessage.SetChildMask(mMle.GetChildIndex(*static_cast(neighbor))); + children = static_cast(neighbor); + children->mQueuedIndirectMessageCnt++; + + AddSrcMatchEntry(*children); + aMessage.SetChildMask(mMle.GetChildIndex(*children)); } else { @@ -258,7 +377,11 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) (neighbor->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) { // destined for a sleepy child - aMessage.SetChildMask(mMle.GetChildIndex(*static_cast(neighbor))); + children = static_cast(neighbor); + children->mQueuedIndirectMessageCnt++; + + AddSrcMatchEntry(*children); + aMessage.SetChildMask(mMle.GetChildIndex(*children)); } else { @@ -583,6 +706,11 @@ void MeshForwarder::SetRxOnWhenIdle(bool aRxOnWhenIdle) void MeshForwarder::SetAssignPollPeriod(uint32_t aPeriod) { mAssignPollPeriod = aPeriod; + + if (mPollTimer.IsRunning() && ((mMle.GetDeviceMode() & Mle::ModeTlv::kModeFFD) == 0)) + { + SetPollPeriod(mAssignPollPeriod); + } } uint32_t MeshForwarder::GetAssignPollPeriod() @@ -602,6 +730,8 @@ void MeshForwarder::SetPollPeriod(uint32_t aPeriod) { mPollPeriod = aPeriod; } + + mPollTimer.Start(mPollPeriod); } } @@ -681,6 +811,8 @@ ThreadError MeshForwarder::HandleFrameRequest(void *aContext, Mac::Frame &aFrame ThreadError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame) { + Mac::Address macDest; + Child *child = NULL; mSendBusy = true; assert(mSendMessage != NULL); @@ -719,6 +851,16 @@ ThreadError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame) break; } + // set FramePending if there are more queued messages for the child + aFrame.GetDstAddr(macDest); + + if (((child = mMle.GetChild(macDest)) != NULL) + && ((child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) + && (child->mQueuedIndirectMessageCnt > 1)) + { + aFrame.SetFramePending(true); + } + #if 0 dump("sent frame", aFrame.GetHeader(), aFrame.GetLength()); #endif @@ -1011,6 +1153,18 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame) { child->mFragmentOffset = 0; mSendMessage->ClearChildMask(mMle.GetChildIndex(*child)); + + if ((child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) + { + child->mQueuedIndirectMessageCnt--; + otLogDebgMac("Sent to child (0x%x), still queued message (%d)\n", + child->mValid.mRloc16, child->mQueuedIndirectMessageCnt); + + if (child->mQueuedIndirectMessageCnt == 0) + { + ClearSrcMatchEntry(*child); + } + } } } @@ -1109,6 +1263,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError) uint8_t payloadLength; Ip6::Address destination; uint8_t commandId; + Child *child = NULL; #if 0 dump("received frame", aFrame.GetHeader(), aFrame.GetLength()); @@ -1147,6 +1302,16 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError) } SuccessOrExit(aFrame.GetDstAddr(macDest)); + + if ((child = mMle.GetChild(macSource)) != NULL) + { + if (((child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) && + macSource.mLength == sizeof(otShortAddress)) + { + child->mAddSrcMatchEntryShort = true; + } + } + aFrame.GetSrcPanId(messageInfo.mPanId); messageInfo.mChannel = aFrame.GetChannel(); messageInfo.mRss = aFrame.GetPower(); @@ -1158,7 +1323,8 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError) if (mPollTimer.IsRunning() && aFrame.GetFramePending()) { - HandlePollTimer(); + // add delay to avoid packet loss due to possible switch senarios between transmit/receive status + mPollTimer.Start(OPENTHREAD_CONFIG_ATTACH_DATA_POLL_PERIOD); } switch (aFrame.GetType()) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 018fad269..779f55c3e 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -221,6 +221,10 @@ private: static void ScheduleTransmissionTask(void *aContext); void ScheduleTransmissionTask(void); + ThreadError AddPendingSrcMatchEntries(); + ThreadError AddSrcMatchEntry(Child &aChild); + void ClearSrcMatchEntry(Child &aChild); + Mac::Receiver mMacReceiver; Mac::Sender mMacSender; Timer mDiscoverTimer; @@ -259,6 +263,8 @@ private: Mac::Mac &mMac; Mle::MleRouter &mMle; NetworkData::Leader &mNetworkData; + + bool mSrcMatchEnabled; }; /** diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 459dfcd71..ac2b867db 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2073,6 +2073,7 @@ ThreadError MleRouter::HandleChildUpdateRequest(const Message &aMessage, const I } child->mLastHeard = Timer::GetNow(); + child->mAddSrcMatchEntryShort = true; SendChildUpdateResponse(child, aMessageInfo, tlvs, tlvslength, &challenge); diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index 3e9120fbf..e8b709da3 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -106,6 +106,9 @@ public: uint16_t mFragmentOffset; ///< 6LoWPAN fragment offset uint8_t mRequestTlvs[5]; ///< Requested MLE TLVs uint8_t mNetworkDataVersion; ///< Current Network Data version + uint16_t mQueuedIndirectMessageCnt; ///< Count of queued messages + bool mAddSrcMatchEntryShort; ///< Indicates whether or not to force add short address + bool mAddSrcMatchEntryPending; ///< Indicates whether or not pending to add }; /** diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index be68167ac..bee6d129c 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -165,6 +165,50 @@ extern "C" { return false; } + void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) + { + (void)aInstance; + (void)aEnable; + } + + ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) + { + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; + } + + ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) + { + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; + } + + ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) + { + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; + } + + ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) + { + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; + } + + void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) + { + (void)aInstance; + } + + void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) + { + (void)aInstance; + } + // // Random // @@ -255,4 +299,4 @@ exit: return kPlatResetReason_PowerOn; } -} // extern "C" \ No newline at end of file +} // extern "C"