2525
2626#include "Core/include/ns_address_internal.h"
2727#include "MLE/mle.h"
28+ #include "NWK_INTERFACE/Include/protocol_abstract.h"
2829#include "NWK_INTERFACE/Include/protocol.h"
2930#include "NWK_INTERFACE/Include/protocol_stats.h"
3031#include "Service_Libs/etx/etx.h"
@@ -40,14 +41,21 @@ static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures);
4041static uint16_t etx_dbm_lqi_calc (uint8_t lqi , int8_t dbm );
4142static void etx_value_change_callback_needed_check (uint16_t etx , uint16_t * stored_diff_etx , uint8_t accumulated_failures , uint8_t attribute_index );
4243static void etx_accum_failures_callback_needed_check (etx_storage_t * entry , uint8_t attribute_index );
44+ static void etx_cache_entry_init (uint8_t attribute_index );
45+
4346
4447typedef struct {
45- uint16_t hysteresis ; // 12 bit fraction
46- uint8_t accum_threshold ;
4748 etx_value_change_handler_t * callback_ptr ;
4849 etx_accum_failures_handler_t * accum_cb_ptr ;
4950 etx_storage_t * etx_storage_list ;
51+ etx_sample_storage_t * etx_cache_storage_list ;
52+ uint32_t max_etx_update ;
53+ uint16_t hysteresis ; // 12 bit fraction
54+ uint8_t accum_threshold ;
55+ uint8_t etx_min_sampling_time ;
5056 uint8_t ext_storage_list_size ;
57+ uint8_t min_sample_count ;
58+ bool cache_sample_requested ;
5159 int8_t interface_id ;
5260} ext_info_t ;
5361
@@ -57,10 +65,107 @@ static ext_info_t etx_info = {
5765 .callback_ptr = NULL ,
5866 .accum_cb_ptr = NULL ,
5967 .etx_storage_list = NULL ,
68+ .etx_cache_storage_list = NULL ,
6069 .ext_storage_list_size = 0 ,
70+ .min_sample_count = 0 ,
71+ .max_etx_update = 0 ,
72+ .cache_sample_requested = false,
73+ .etx_min_sampling_time = 0 ,
6174 .interface_id = -1
6275};
6376
77+ static void etx_calculation (etx_storage_t * entry , uint16_t attempts , uint8_t acks_rx , uint8_t attribute_index )
78+ {
79+ if (etx_info .hysteresis && !entry -> stored_diff_etx ) {
80+ entry -> stored_diff_etx = entry -> etx ;
81+ }
82+
83+
84+ uint32_t etx = attempts << (12 - ETX_MOVING_AVERAGE_FRACTION );
85+
86+ if (acks_rx > 1 ) {
87+ etx /= acks_rx ;
88+ }
89+
90+ if ((etx_info .max_etx_update ) && etx > etx_info .max_etx_update ) {
91+ etx = etx_info .max_etx_update ;
92+ }
93+
94+ //Add old etx 7/8 to new one
95+ etx += entry -> etx - (entry -> etx >> ETX_MOVING_AVERAGE_FRACTION );
96+
97+ if (etx > 0xffff ) {
98+ etx = 0xffff ;
99+ }
100+
101+ // If real ETX value has been received do not update based on LQI or dBm
102+ entry -> tmp_etx = false;
103+ entry -> etx = etx ;
104+
105+ etx_cache_entry_init (attribute_index );
106+
107+ // Checks if ETX value change callback is needed
108+ etx_value_change_callback_needed_check (entry -> etx , & (entry -> stored_diff_etx ), entry -> accumulated_failures , attribute_index );
109+ }
110+
111+ static void etx_cache_entry_init (uint8_t attribute_index )
112+ {
113+ if (!etx_info .cache_sample_requested ) {
114+ return ;
115+ }
116+
117+ etx_sample_storage_t * storage = etx_info .etx_cache_storage_list + attribute_index ;
118+ storage -> attempts_count = 0 ;
119+ storage -> etx_timer = etx_info .etx_min_sampling_time ;
120+ storage -> received_acks = 0 ;
121+ storage -> sample_count = 0 ;
122+ }
123+
124+ static bool etx_update_possible (etx_sample_storage_t * storage , etx_storage_t * entry , uint8_t time )
125+ {
126+ if (storage -> etx_timer && time ) {
127+ if (time >= storage -> etx_timer ) {
128+ storage -> etx_timer = 0 ;
129+ } else {
130+ storage -> etx_timer -= time ;
131+ }
132+ }
133+
134+ if (entry -> etx_samples == 7 ) {
135+ //Slower ETX update phase
136+ if (storage -> sample_count < etx_info .min_sample_count || storage -> etx_timer ) {
137+ if (storage -> sample_count < 0xff ) {
138+ return false;
139+ }
140+ }
141+ } else {
142+ //Accelerated ETX at for new neighbor
143+ if (storage -> sample_count < 3 ) {
144+ return false;
145+ }
146+ }
147+
148+ tr_debug ("ETX update possible %u attempts, %u rx ack" , storage -> attempts_count , storage -> received_acks );
149+
150+ return true;
151+
152+ }
153+
154+
155+ static etx_sample_storage_t * etx_cache_sample_update (uint8_t attribute_index , uint8_t attempts , bool ack_rx )
156+ {
157+ etx_sample_storage_t * storage = etx_info .etx_cache_storage_list + attribute_index ;
158+ storage -> attempts_count += attempts ;
159+ if (ack_rx ) {
160+ storage -> received_acks ++ ;
161+ }
162+ storage -> sample_count ++ ;
163+ return storage ;
164+
165+ }
166+
167+
168+
64169/**
65170 * \brief A function to update ETX value based on transmission attempts
66171 *
@@ -74,7 +179,6 @@ static ext_info_t etx_info = {
74179 */
75180void etx_transm_attempts_update (int8_t interface_id , uint8_t attempts , bool success , uint8_t attribute_index )
76181{
77- uint32_t etx ;
78182 uint8_t accumulated_failures ;
79183 // Gets table entry
80184 etx_storage_t * entry = etx_storage_entry_get (interface_id , attribute_index );
@@ -85,6 +189,18 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
85189 entry -> etx_samples ++ ;
86190 }
87191
192+ if (etx_info .cache_sample_requested && !entry -> tmp_etx ) {
193+
194+ etx_sample_storage_t * storage = etx_cache_sample_update (attribute_index , attempts , success );
195+ entry -> accumulated_failures = 0 ;
196+ if (!etx_update_possible (storage , entry , 0 )) {
197+ return ;
198+ }
199+
200+ etx_calculation (entry , storage -> attempts_count , storage -> received_acks , attribute_index );
201+ return ;
202+ }
203+
88204 accumulated_failures = entry -> accumulated_failures ;
89205
90206 if (!success ) {
@@ -104,28 +220,10 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
104220 }
105221
106222 if (entry -> etx ) {
107- // If hysteresis is set stores ETX value for comparison
108- if (etx_info .hysteresis && !entry -> stored_diff_etx ) {
109- entry -> stored_diff_etx = entry -> etx ;
110- }
111223
112224 if (success ) {
113- // ETX = 7/8 * current ETX + 1/8 * ((attempts + failed attempts) << 12)
114- etx = entry -> etx - (entry -> etx >> ETX_MOVING_AVERAGE_FRACTION );
115- etx += (attempts + accumulated_failures ) << (12 - ETX_MOVING_AVERAGE_FRACTION );
116-
117- if (etx > 0xffff ) {
118- entry -> etx = 0xffff ;
119- } else {
120- entry -> etx = etx ;
121- }
225+ etx_calculation (entry , attempts + accumulated_failures , 1 , attribute_index );
122226 }
123-
124- // If real ETX value has been received do not update based on LQI or dBm
125- entry -> tmp_etx = false;
126-
127- // Checks if ETX value change callback is needed
128- etx_value_change_callback_needed_check (entry -> etx , & (entry -> stored_diff_etx ), entry -> accumulated_failures , attribute_index );
129227 }
130228}
131229
@@ -437,6 +535,9 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size)
437535{
438536 if (!etx_storage_size ) {
439537 ns_dyn_mem_free (etx_info .etx_storage_list );
538+ ns_dyn_mem_free (etx_info .etx_cache_storage_list );
539+ etx_info .etx_cache_storage_list = NULL ;
540+ etx_info .cache_sample_requested = false;
440541 etx_info .etx_storage_list = NULL ;
441542 etx_info .ext_storage_list_size = 0 ;
442543 return true;
@@ -447,12 +548,18 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size)
447548 }
448549
449550 ns_dyn_mem_free (etx_info .etx_storage_list );
551+ etx_info .cache_sample_requested = false;
450552 etx_info .ext_storage_list_size = 0 ;
451553 etx_info .etx_storage_list = ns_dyn_mem_alloc (sizeof (etx_storage_t ) * etx_storage_size );
554+
452555 if (!etx_info .etx_storage_list ) {
556+ ns_dyn_mem_free (etx_info .etx_storage_list );
557+ etx_info .etx_storage_list = NULL ;
558+ etx_info .ext_storage_list_size = 0 ;
453559 return false;
454560 }
455561
562+
456563 etx_info .ext_storage_list_size = etx_storage_size ;
457564 etx_info .interface_id = interface_id ;
458565 etx_storage_t * list_ptr = etx_info .etx_storage_list ;
@@ -465,6 +572,52 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size)
465572
466573}
467574
575+ bool etx_cached_etx_parameter_set (uint8_t min_wait_time , uint8_t etx_min_sample_count )
576+ {
577+ //No ini ETX allocation done yet
578+ if (etx_info .ext_storage_list_size == 0 ) {
579+ return false;
580+ }
581+
582+ if (min_wait_time || etx_min_sample_count ) {
583+ if (!etx_info .etx_cache_storage_list ) {
584+ //allocate
585+ etx_info .etx_cache_storage_list = ns_dyn_mem_alloc (sizeof (etx_sample_storage_t ) * etx_info .ext_storage_list_size );
586+
587+ if (!etx_info .etx_cache_storage_list ) {
588+ return false;
589+ }
590+ etx_info .cache_sample_requested = true;
591+ etx_sample_storage_t * sample_list = etx_info .etx_cache_storage_list ;
592+ for (uint8_t i = 0 ; i < etx_info .ext_storage_list_size ; i ++ ) {
593+ memset (sample_list , 0 , sizeof (etx_sample_storage_t ));
594+ sample_list ++ ;
595+ }
596+ }
597+
598+ } else {
599+ //Free Cache table we not need that anymore
600+ etx_info .cache_sample_requested = false;
601+ ns_dyn_mem_free (etx_info .etx_cache_storage_list );
602+ etx_info .etx_cache_storage_list = NULL ;
603+ }
604+
605+ etx_info .min_sample_count = etx_min_sample_count ;
606+ etx_info .etx_min_sampling_time = min_wait_time ;
607+ tr_debug ("ETX cached parameter's %u MinSample, %u MinTime" , etx_info .min_sample_count , etx_info .etx_min_sampling_time );
608+
609+ return true;
610+ }
611+
612+ void etx_max_update_set (uint16_t etx_max_update )
613+ {
614+ if (etx_max_update ) {
615+ etx_info .max_etx_update = (etx_max_update / 128 ) << (12 - ETX_MOVING_AVERAGE_FRACTION );
616+ } else {
617+ etx_info .max_etx_update = 0 ;
618+ }
619+ }
620+
468621etx_storage_t * etx_storage_entry_get (int8_t interface_id , uint8_t attribute_index )
469622{
470623 if (etx_info .interface_id != interface_id || !etx_info .etx_storage_list || attribute_index >= etx_info .ext_storage_list_size ) {
@@ -593,6 +746,12 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index)
593746 }
594747 etx_info .callback_ptr (etx_info .interface_id , stored_diff_etx , 0xffff , attribute_index );
595748 }
749+
750+ if (etx_info .cache_sample_requested ) {
751+ //Clear cached values
752+ etx_sample_storage_t * cache_entry = etx_info .etx_cache_storage_list + attribute_index ;
753+ memset (cache_entry , 0 , sizeof (etx_sample_storage_t ));
754+ }
596755 //Clear all data base back to zero for new user
597756 memset (entry , 0 , sizeof (etx_storage_t ));
598757 }
@@ -626,3 +785,42 @@ void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index)
626785 }
627786 }
628787}
788+
789+ void etx_cache_timer (int8_t interface_id , uint16_t seconds_update )
790+ {
791+ if (!etx_info .cache_sample_requested ) {
792+ return ;
793+ }
794+
795+ protocol_interface_info_entry_t * interface = protocol_stack_interface_info_get_by_id (interface_id );
796+ if (!interface ) {
797+ return ;
798+ }
799+
800+ mac_neighbor_table_t * table_class = mac_neighbor_info (interface );
801+ if (!table_class ) {
802+ return ;
803+ }
804+
805+ uint8_t update_seconds ;
806+ if (seconds_update > 255 ) {
807+ update_seconds = 255 ;
808+ } else {
809+ update_seconds = seconds_update ;
810+ }
811+
812+ ns_list_foreach (mac_neighbor_table_entry_t , neighbour , & table_class -> neighbour_list ) {
813+
814+ etx_storage_t * etx_entry = etx_storage_entry_get (interface_id , neighbour -> index );
815+
816+ if (!etx_entry || etx_entry -> tmp_etx ) {
817+ continue ;
818+ }
819+ etx_sample_storage_t * storage = etx_info .etx_cache_storage_list + neighbour -> index ;
820+
821+ if (etx_update_possible (storage , etx_entry , update_seconds )) {
822+ etx_calculation (etx_entry , storage -> attempts_count , storage -> received_acks , neighbour -> index );
823+ }
824+ }
825+
826+ }
0 commit comments