mesh: generic on/off + level server - move transition logic to mesh_access

This commit is contained in:
Matthias Ringwald 2019-11-17 21:54:40 +01:00
parent 8245767ef9
commit 332b525621
4 changed files with 154 additions and 416 deletions

View File

@ -70,9 +70,6 @@ static btstack_timer_source_t mesh_access_acknowledged_timer;
static int mesh_access_acknowledged_timer_active;
// Transitions
static btstack_linked_list_t transitions;
static btstack_timer_source_t transitions_timer;
static uint32_t transition_step_min_ms;
static uint8_t mesh_transaction_id_counter = 0;
void mesh_access_init(void){
@ -249,29 +246,11 @@ static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t c
// Mesh Model Transitions
void mesh_access_transitions_setup_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
transition->transaction_timestamp_ms = btstack_run_loop_get_time_ms();
transition->transaction_identifier = transaction_identifier;
transition->src_address = src_address;
transition->dst_address = dst_address;
}
uint32_t mesh_access_time_gdtt2ms(uint8_t time_gdtt){
uint8_t num_steps = mesh_access_transitions_num_steps_from_gdtt(time_gdtt);
if (num_steps > 0x3E) return 0;
void mesh_access_transitions_abort_transaction(mesh_transition_t * transition){
mesh_access_transitions_remove(transition);
}
static int mesh_access_transitions_transaction_is_expired(mesh_transition_t * transition){
return (btstack_run_loop_get_time_ms() - transition->transaction_timestamp_ms) > MEST_TRANSACTION_TIMEOUT_MS;
}
mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
if (transition->src_address != src_address || transition->dst_address != dst_address) return MESH_TRANSACTION_STATUS_DIFFERENT_DST_OR_SRC;
if (transition->transaction_identifier == transaction_identifier && !mesh_access_transitions_transaction_is_expired(transition)){
return MESH_TRANSACTION_STATUS_RETRANSMISSION;
}
return MESH_TRANSACTION_STATUS_NEW;
return mesh_access_transitions_step_ms_from_gdtt(time_gdtt) * num_steps;
}
uint8_t mesh_access_transitions_num_steps_from_gdtt(uint8_t time_gdtt){
@ -294,122 +273,102 @@ uint32_t mesh_access_transitions_step_ms_from_gdtt(uint8_t time_gdtt){
}
}
uint32_t mesh_access_time_gdtt2ms(uint8_t time_gdtt){
uint8_t num_steps = mesh_access_transitions_num_steps_from_gdtt(time_gdtt);
if (num_steps > 0x3E) return 0;
return mesh_access_transitions_step_ms_from_gdtt(time_gdtt) * num_steps;
}
uint8_t mesh_access_time_as_gdtt(uint32_t step_resolution_ms, uint32_t time_ms){
uint8_t resolution;
switch (step_resolution_ms){
case 100:
resolution = MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_100ms;
break;
case 1000:
resolution = MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_1s;
break;
case 10000:
resolution = MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10s;
break;
case 600000:
resolution = MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10min;
break;
default:
resolution = MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_100ms;
break;
}
uint8_t num_steps = time_ms / step_resolution_ms;
return (resolution << 6) | num_steps;
}
static void mesh_access_transitions_timeout_handler(btstack_timer_source_t * timer){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &transitions);
while (btstack_linked_list_iterator_has_next(&it)){
mesh_transition_t * transition = (mesh_transition_t *)btstack_linked_list_iterator_next(&it);
(transition->transition_callback)(transition, TRANSITION_UPDATE, btstack_run_loop_get_time_ms());
}
if (btstack_linked_list_empty(&transitions)) return;
btstack_run_loop_set_timer(timer, transition_step_min_ms);
btstack_run_loop_add_timer(timer);
}
static void mesh_access_transitions_timer_start(void){
btstack_run_loop_remove_timer(&transitions_timer);
btstack_run_loop_set_timer_handler(&transitions_timer, mesh_access_transitions_timeout_handler);
btstack_run_loop_set_timer(&transitions_timer, transition_step_min_ms);
btstack_run_loop_add_timer(&transitions_timer);
}
static void mesh_access_transitions_timer_stop(void){
btstack_run_loop_remove_timer(&transitions_timer);
}
static uint32_t mesh_access_transitions_get_step_min_ms(void){
uint32_t min_timeout_ms = 0;
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &transitions);
while (btstack_linked_list_iterator_has_next(&it)){
mesh_transition_t * transition = (mesh_transition_t *)btstack_linked_list_iterator_next(&it);
if (min_timeout_ms == 0 || transition->step_duration_ms < min_timeout_ms){
min_timeout_ms = transition->step_duration_ms;
}
}
return min_timeout_ms;
}
void mesh_access_transitions_setup(mesh_transition_t * transition, mesh_model_t * mesh_model,
uint8_t transition_time_gdtt, uint8_t delay_gdtt,
void (* transition_callback)(struct mesh_transition * transition, transition_event_t event, uint32_t current_timestamp)){
// Only values of 0x00 through 0x3E shall be used to specify the value of the Transition Number of Steps field
uint8_t num_steps = mesh_access_transitions_num_steps_from_gdtt(transition_time_gdtt);
if (num_steps >= MESH_TRANSITION_NUM_STEPS_INFINITE) return;
transition->state = MESH_TRANSITION_STATE_IDLE;
transition->phase_start_ms = 0;
transition->mesh_model = mesh_model;
transition->transition_callback = transition_callback;
transition->step_duration_ms = mesh_access_transitions_step_ms_from_gdtt(transition_time_gdtt);
transition->remaining_delay_time_ms = delay_gdtt * 5;
transition->remaining_transition_time_ms = num_steps * transition->step_duration_ms;
transition->num_steps = num_steps;
}
void mesh_access_transitions_add(mesh_transition_t * transition){
if (transition->step_duration_ms == 0) return;
if (btstack_linked_list_empty(&transitions) || transition->step_duration_ms < transition_step_min_ms){
transition_step_min_ms = transition->step_duration_ms;
}
mesh_access_transitions_timer_start();
btstack_linked_list_add(&transitions, (btstack_linked_item_t *) transition);
(transition->transition_callback)(transition, TRANSITION_START, btstack_run_loop_get_time_ms());
}
void mesh_access_transitions_remove(mesh_transition_t * transition){
mesh_access_transitions_setup(transition, NULL, 0, 0, NULL);
btstack_linked_list_remove(&transitions, (btstack_linked_item_t *) transition);
if (btstack_linked_list_empty(&transitions)){
mesh_access_transitions_timer_stop();
} else {
transition_step_min_ms = mesh_access_transitions_get_step_min_ms();
}
}
uint8_t mesh_access_transactions_get_next_transaction_id(void){
mesh_transaction_id_counter++;
if (mesh_transaction_id_counter == 0){
mesh_transaction_id_counter = 1;
}
return mesh_transaction_id_counter;
}
}
static int mesh_access_transitions_transaction_is_expired(mesh_transition_t * transition){
return (btstack_run_loop_get_time_ms() - transition->transaction_timestamp_ms) > MEST_TRANSACTION_TIMEOUT_MS;
}
mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
if (transition->src_address != src_address || transition->dst_address != dst_address) return MESH_TRANSACTION_STATUS_DIFFERENT_DST_OR_SRC;
if (transition->transaction_identifier == transaction_identifier && !mesh_access_transitions_transaction_is_expired(transition)){
return MESH_TRANSACTION_STATUS_RETRANSMISSION;
}
return MESH_TRANSACTION_STATUS_NEW;
}
void mesh_access_transitions_init_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
transition->transaction_timestamp_ms = btstack_run_loop_get_time_ms();
transition->transaction_identifier = transaction_identifier;
transition->src_address = src_address;
transition->dst_address = dst_address;
}
static void mesh_server_transition_timeout(btstack_timer_source_t * ts){
mesh_transition_t * base_transition = (mesh_transition_t*) btstack_run_loop_get_timer_context(ts);
switch (base_transition->state){
case MESH_TRANSITION_STATE_DELAYED:
base_transition->state = MESH_TRANSITION_STATE_ACTIVE;
(*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
if (base_transition->num_steps > 0){
btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
btstack_run_loop_add_timer(&base_transition->timer);
return;
}
base_transition->state = MESH_TRANSITION_STATE_IDLE;
(*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
case MESH_TRANSITION_STATE_ACTIVE:
if (base_transition->num_steps < MESH_TRANSITION_NUM_STEPS_INFINITE){
base_transition->num_steps--;
}
(*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE);
if (base_transition->num_steps > 0){
btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
btstack_run_loop_add_timer(&base_transition->timer);
return;
}
base_transition->state = MESH_TRANSITION_STATE_IDLE;
(*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
default:
break;
}
}
void mesh_access_transition_setup(mesh_model_t *mesh_model, mesh_transition_t * base_transition, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, void (*transition_callback)(mesh_transition_t * base_transition, model_state_update_reason_t event)){
base_transition->mesh_model = mesh_model;
base_transition->num_steps = mesh_access_transitions_num_steps_from_gdtt(transition_time_gdtt);
base_transition->step_resolution = (mesh_default_transition_step_resolution_t) (transition_time_gdtt >> 6);
base_transition->step_duration_ms = mesh_access_transitions_step_ms_from_gdtt(transition_time_gdtt);
base_transition->transition_callback = transition_callback;
btstack_run_loop_set_timer_context(&base_transition->timer, base_transition);
btstack_run_loop_set_timer_handler(&base_transition->timer, &mesh_server_transition_timeout);
// delayed
if (delay_time_gdtt > 0){
base_transition->state = MESH_TRANSITION_STATE_DELAYED;
btstack_run_loop_set_timer(&base_transition->timer, delay_time_gdtt * 5);
btstack_run_loop_add_timer(&base_transition->timer);
return;
}
// started
if (base_transition->num_steps > 0){
base_transition->state = MESH_TRANSITION_STATE_ACTIVE;
btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
btstack_run_loop_add_timer(&base_transition->timer);
return;
}
// instanteneous update
base_transition->state = MESH_TRANSITION_STATE_IDLE;
(*transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_SET);
return;
}
void mesh_access_transitions_abort_transaction(mesh_transition_t * base_transition){
btstack_run_loop_add_timer(&base_transition->timer);
}
uint16_t mesh_pdu_ctl(mesh_pdu_t * pdu){
switch (pdu->pdu_type){

View File

@ -127,7 +127,6 @@ typedef enum {
} mesh_transaction_status_t;
typedef struct mesh_transition {
btstack_linked_item_t item;
btstack_timer_source_t timer;
mesh_transition_state_t state;
@ -138,16 +137,14 @@ typedef struct mesh_transition {
uint16_t dst_address;
uint8_t num_steps;
mesh_default_transition_step_resolution_t step_resolution;
uint32_t step_duration_ms;
uint32_t phase_start_ms;
uint32_t remaining_delay_time_ms;
uint32_t remaining_transition_time_ms;
// to send events and/or publish changes
mesh_model_t * mesh_model;
// to execute transition
void (* transition_callback)(struct mesh_transition * transition, transition_event_t event, uint32_t current_timestamp);
void (* transition_callback)(struct mesh_transition * transition, model_state_update_reason_t event);
} mesh_transition_t;
/**
@ -185,29 +182,23 @@ void mesh_access_send_unacknowledged_pdu(mesh_pdu_t * pdu);
*/
void mesh_access_send_acknowledged_pdu(mesh_pdu_t * pdu, uint8_t retransmissions, uint32_t ack_opcode);
// Mesh Model Transitions
uint32_t mesh_access_transitions_step_ms_from_gdtt(uint8_t time_gdtt);
uint8_t mesh_access_transitions_num_steps_from_gdtt(uint8_t time_gdtt);
uint32_t mesh_access_time_gdtt2ms(uint8_t time_gdtt);
uint8_t mesh_access_time_as_gdtt(uint32_t step_resolution_ms, uint32_t time_ms);
void mesh_access_transitions_init_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address);
void mesh_access_transition_setup(mesh_model_t *mesh_model, mesh_transition_t * base_transition, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, void (*transition_callback)(mesh_transition_t * base_transition, model_state_update_reason_t event));
void mesh_access_transitions_abort_transaction(mesh_transition_t * transition);
uint8_t mesh_access_transactions_get_next_transaction_id(void);
mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address);
void mesh_access_emit_state_update_bool(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
model_state_id_t state_identifier, model_state_update_reason_t reason, uint8_t value);
void mesh_access_emit_state_update_int16(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
void mesh_access_emit_state_update_int16(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
model_state_id_t state_identifier, model_state_update_reason_t reason, int16_t value);
// Mesh Model Transitions
void mesh_access_transitions_setup_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address);
void mesh_access_transitions_abort_transaction(mesh_transition_t * transition);
mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address);
void mesh_access_transitions_setup(mesh_transition_t * transition, mesh_model_t * mesh_model,
uint8_t transition_time_gdtt, uint8_t delay_gdtt,
void (* transition_callback)(struct mesh_transition * transition, transition_event_t event, uint32_t current_timestamp));
void mesh_access_transitions_add(mesh_transition_t * transition);
void mesh_access_transitions_remove(mesh_transition_t * transition);
uint8_t mesh_access_transactions_get_next_transaction_id(void);
// Mesh Model Publicaation
/**

View File

@ -76,133 +76,33 @@ static mesh_transition_t * generic_level_server_get_base_transition(mesh_model_t
return &generic_level_server_state->transition_data.base_transition;
}
static void mesh_server_transition_state_emit_change(mesh_transition_int16_t * transition, model_state_update_reason_t reason){
mesh_model_t * generic_level_server_model = transition->base_transition.mesh_model;
mesh_access_emit_state_update_int16(generic_level_server_model->model_packet_handler,
mesh_access_get_element_index(generic_level_server_model),
generic_level_server_model->model_identifier,
MODEL_STATE_ID_GENERIC_LEVEL,
reason,
transition->current_value);
}
static void mesh_server_transition_state_started(mesh_transition_int16_t * transition, uint32_t current_timestamp_ms){
transition->base_transition.state = MESH_TRANSITION_STATE_ACTIVE;
transition->base_transition.remaining_delay_time_ms = 0;
transition->base_transition.phase_start_ms = current_timestamp_ms;
// notify transition completed
mesh_server_transition_state_emit_change(transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
}
static void mesh_server_transition_state_update_stepwise_value(mesh_transition_int16_t * transition){
transition->current_value = add_and_clip_int16(transition->current_value, transition->stepwise_value_increment);
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// notify transition update
mesh_server_transition_state_emit_change(transition, MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE);
}
static void mesh_server_transition_state_done(mesh_transition_int16_t * transition, uint32_t current_timestamp_ms){
transition->base_transition.state = MESH_TRANSITION_STATE_IDLE;
transition->base_transition.remaining_transition_time_ms = 0;
transition->current_value = transition->target_value;
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// notify transition completed
mesh_server_transition_state_emit_change(transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
// done, stop transition
mesh_access_transitions_remove((mesh_transition_t *)transition);
}
static void mesh_server_transition_state_set(mesh_transition_int16_t * transition, uint32_t current_timestamp_ms){
UNUSED(current_timestamp_ms);
transition->base_transition.state = MESH_TRANSITION_STATE_IDLE;
transition->base_transition.remaining_transition_time_ms = 0;
transition->current_value = transition->target_value;
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// instantaneous update
mesh_server_transition_state_emit_change(transition, MODEL_STATE_UPDATE_REASON_SET);
}
static void mesh_server_transition_handler(mesh_transition_t * base_transition, model_state_update_reason_t event){
mesh_transition_int16_t * transition = (mesh_transition_int16_t*) base_transition;
uint32_t current_timestamp_ms = btstack_run_loop_get_time_ms();
printf("Transition: event %x, current %x, target %x, increment %x, time %u\n", (int) event, transition->current_value, transition->target_value, transition->stepwise_value_increment, btstack_run_loop_get_time_ms());
switch (event){
case MODEL_STATE_UPDATE_REASON_SET:
mesh_server_transition_state_set(transition, current_timestamp_ms);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_START:
mesh_server_transition_state_started(transition, current_timestamp_ms);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE:
mesh_server_transition_state_update_stepwise_value(transition);
transition->current_value = add_and_clip_int16(transition->current_value, transition->stepwise_value_increment);
mesh_access_state_changed(transition->base_transition.mesh_model);
break;
case MODEL_STATE_UPDATE_REASON_SET:
case MODEL_STATE_UPDATE_REASON_TRANSITION_END:
mesh_server_transition_state_done(transition, current_timestamp_ms);
transition->current_value = transition->target_value;
mesh_access_state_changed(transition->base_transition.mesh_model);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_ABORT:
break;
default:
break;
}
}
static void mesh_server_transition_step(mesh_transition_t * base_transition, transition_event_t event, uint32_t current_timestamp_ms){
uint32_t time_step_ms;
mesh_transition_int16_t * transition = (mesh_transition_int16_t*) base_transition;
switch (transition->base_transition.state){
case MESH_TRANSITION_STATE_IDLE:
if (event != TRANSITION_START) break;
transition->base_transition.state = MESH_TRANSITION_STATE_DELAYED;
transition->base_transition.phase_start_ms = current_timestamp_ms;
if (transition->base_transition.remaining_delay_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
if (transition->base_transition.remaining_transition_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
case MESH_TRANSITION_STATE_DELAYED:
if (event != TRANSITION_UPDATE) break;
time_step_ms = current_timestamp_ms - transition->base_transition.phase_start_ms;
if (transition->base_transition.remaining_delay_time_ms > time_step_ms){
transition->base_transition.remaining_delay_time_ms -= time_step_ms;
transition->base_transition.phase_start_ms += time_step_ms;
break;
}
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
if (transition->base_transition.remaining_transition_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
case MESH_TRANSITION_STATE_ACTIVE:
if (event != TRANSITION_UPDATE) break;
time_step_ms = current_timestamp_ms - transition->base_transition.phase_start_ms;
if (transition->base_transition.num_steps == MESH_TRANSITION_NUM_STEPS_INFINITE){
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE);
// done when max value reached
if (transition->current_value > - 32768 && transition->current_value < 32767) break;
} else if (transition->base_transition.remaining_transition_time_ms > time_step_ms){
transition->base_transition.remaining_transition_time_ms -= time_step_ms;
transition->base_transition.phase_start_ms += time_step_ms;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE);
break;
}
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
default:
break;
}
// notify app
mesh_model_t * generic_level_server_model = transition->base_transition.mesh_model;
mesh_access_emit_state_update_int16(generic_level_server_model->model_packet_handler,
mesh_access_get_element_index(generic_level_server_model),
generic_level_server_model->model_identifier,
MODEL_STATE_ID_GENERIC_LEVEL,
event,
transition->current_value);
}
static void mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model_t *mesh_model, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint32_t delta_value){
@ -217,15 +117,9 @@ static void mesh_server_transition_setup_transition_or_instantaneous_update_int1
generic_level_server_state->transition_data.stepwise_value_increment = 0;
}
if (transition_time_gdtt != 0 || delay_time_gdtt != 0) {
// transition
mesh_access_transitions_setup(transition, mesh_model, transition_time_gdtt, delay_time_gdtt, &mesh_server_transition_step);
mesh_access_transitions_add(transition);
} else {
// instantaneous update
mesh_server_transition_handler(transition, MODEL_STATE_UPDATE_REASON_SET);
}
mesh_access_transition_setup(mesh_model, transition, transition_time_gdtt, delay_time_gdtt, &mesh_server_transition_handler);
}
// Generic Level State
void mesh_generic_level_server_register_packet_handler(mesh_model_t *generic_level_server_model, btstack_packet_handler_t transition_events_packet_handler){
@ -248,13 +142,8 @@ static mesh_pdu_t * mesh_generic_level_status_message(mesh_model_t *generic_leve
// setup message
mesh_transport_pdu_t * transport_pdu = NULL;
if (state->transition_data.base_transition.remaining_transition_time_ms != 0) {
uint8_t remaining_time;
if (state->transition_data.base_transition.num_steps == MESH_TRANSITION_NUM_STEPS_INFINITE){
remaining_time = MESH_TRANSITION_NUM_STEPS_INFINITE;
} else {
remaining_time = mesh_access_time_as_gdtt(state->transition_data.base_transition.step_duration_ms, state->transition_data.base_transition.remaining_transition_time_ms);
}
if (state->transition_data.base_transition.num_steps > 0) {
uint8_t remaining_time = (((uint8_t)state->transition_data.base_transition.step_resolution) << 6) | (state->transition_data.base_transition.num_steps);
transport_pdu = mesh_access_setup_segmented_message(&mesh_generic_level_status_transition, state->transition_data.current_value,
state->transition_data.target_value, remaining_time);
} else {
@ -289,7 +178,7 @@ static void generic_level_handle_set_target_level_message(mesh_model_t *mesh_mod
// ignore
break;
default:
mesh_access_transitions_setup_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
generic_level_server_state->transition_data.target_value = level_value;
@ -334,7 +223,7 @@ static void generic_level_handle_set_delta_message(mesh_model_t *mesh_model, mes
break;
case MESH_TRANSACTION_STATUS_NEW:
// start transaction with current value
mesh_access_transitions_setup_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.initial_value, delta_value);
printf("Transaction %u, new, init %x, target %x\n", tid, generic_level_server_state->transition_data.initial_value, generic_level_server_state->transition_data.target_value);
@ -343,7 +232,7 @@ static void generic_level_handle_set_delta_message(mesh_model_t *mesh_model, mes
break;
case MESH_TRANSACTION_STATUS_RETRANSMISSION:
// replace last delta message
mesh_access_transitions_setup_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.initial_value, delta_value);
printf("Transaction %u, retransmission, init %x, target %x\n", tid, generic_level_server_state->transition_data.initial_value, generic_level_server_state->transition_data.target_value);
mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, transition_time_gdtt, delay_time_gdtt, delta_value);
@ -384,7 +273,7 @@ static void generic_level_handle_set_move_message(mesh_model_t *mesh_model, mesh
// ignore retransmission
break;
default:
mesh_access_transitions_setup_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.current_value, delta_value);

View File

@ -54,8 +54,6 @@
#include "mesh/mesh_network.h"
#include "mesh/mesh_upper_transport.h"
static void mesh_server_transition_step_bool(mesh_transition_t * transition, transition_event_t event, uint32_t current_timestamp);
static void generic_server_send_message(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu){
uint8_t ttl = mesh_foundation_default_ttl_get();
mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
@ -69,138 +67,40 @@ static mesh_transition_t * generic_on_off_server_get_base_transition(mesh_model_
return &generic_on_off_server_state->transition_data.base_transition;
}
static void mesh_server_transition_state_emit_change(mesh_transition_bool_t * transition, uint32_t current_timestamp_ms, model_state_update_reason_t reason){
static void mesh_server_transition_handler(mesh_transition_t * base_transition, model_state_update_reason_t event){
mesh_transition_bool_t * transition = (mesh_transition_bool_t*) base_transition;
switch (event){
case MODEL_STATE_UPDATE_REASON_TRANSITION_START:
if (transition->target_value == 1){
transition->current_value = 1;
mesh_access_state_changed(transition->base_transition.mesh_model);
}
break;
case MODEL_STATE_UPDATE_REASON_SET:
case MODEL_STATE_UPDATE_REASON_TRANSITION_END:
transition->current_value = transition->target_value;
mesh_access_state_changed(transition->base_transition.mesh_model);
break;
default:
break;
}
// notify app
mesh_model_t * generic_on_off_server_model = transition->base_transition.mesh_model;
mesh_access_emit_state_update_bool(generic_on_off_server_model->model_packet_handler,
mesh_access_get_element_index(generic_on_off_server_model),
generic_on_off_server_model->model_identifier,
MODEL_STATE_ID_GENERIC_ON_OFF,
reason,
event,
transition->current_value);
}
static void mesh_server_transition_state_started(mesh_transition_bool_t * transition, uint32_t current_timestamp_ms){
transition->base_transition.state = MESH_TRANSITION_STATE_ACTIVE;
transition->base_transition.remaining_delay_time_ms = 0;
transition->base_transition.phase_start_ms = current_timestamp_ms;
if (transition->target_value == 1){
transition->current_value = 1;
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// notify app
mesh_server_transition_state_emit_change(transition, current_timestamp_ms, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
}
}
static void mesh_server_transition_state_done(mesh_transition_bool_t * transition, uint32_t current_timestamp_ms){
transition->base_transition.state = MESH_TRANSITION_STATE_IDLE;
transition->base_transition.remaining_transition_time_ms = 0;
transition->current_value = transition->target_value;
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// notify transition completed
mesh_server_transition_state_emit_change(transition, current_timestamp_ms, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
// done, stop transition
mesh_access_transitions_remove((mesh_transition_t *)transition);
}
static void mesh_server_transition_state_set(mesh_transition_bool_t * transition, uint32_t current_timestamp_ms){
UNUSED(current_timestamp_ms);
transition->base_transition.state = MESH_TRANSITION_STATE_IDLE;
transition->base_transition.remaining_delay_time_ms = 0;
transition->base_transition.remaining_transition_time_ms = 0;
transition->base_transition.phase_start_ms = 0;
transition->current_value = transition->target_value;
// publish new value
mesh_access_state_changed(transition->base_transition.mesh_model);
// notify transition completed
mesh_server_transition_state_emit_change(transition, current_timestamp_ms, MODEL_STATE_UPDATE_REASON_SET);
}
static void mesh_server_transition_handler(mesh_transition_t * base_transition, model_state_update_reason_t event){
mesh_transition_bool_t * transition = (mesh_transition_bool_t*) base_transition;
uint32_t current_timestamp_ms = btstack_run_loop_get_time_ms();
switch (event){
case MODEL_STATE_UPDATE_REASON_SET:
mesh_server_transition_state_set(transition, current_timestamp_ms);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_START:
mesh_server_transition_state_started(transition, current_timestamp_ms);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_END:
mesh_server_transition_state_done(transition, current_timestamp_ms);
break;
case MODEL_STATE_UPDATE_REASON_TRANSITION_ABORT:
break;
default:
break;
}
}
static void mesh_server_transition_step_bool(mesh_transition_t * base_transition, transition_event_t event, uint32_t current_timestamp_ms){
uint32_t time_step_ms;
mesh_transition_bool_t * transition = (mesh_transition_bool_t*) base_transition;
log_info("Transition: state %x, current timestamp %u, remaining delay %u ms, remaining transition %u ms",
transition->base_transition.state, current_timestamp_ms, transition->base_transition.remaining_delay_time_ms, transition->base_transition.remaining_transition_time_ms);
switch (transition->base_transition.state){
case MESH_TRANSITION_STATE_IDLE:
if (event != TRANSITION_START) break;
transition->base_transition.state = MESH_TRANSITION_STATE_DELAYED;
transition->base_transition.phase_start_ms = current_timestamp_ms;
if (transition->base_transition.remaining_delay_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
if (transition->base_transition.remaining_transition_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
case MESH_TRANSITION_STATE_DELAYED:
if (event != TRANSITION_UPDATE) break;
time_step_ms = current_timestamp_ms - transition->base_transition.phase_start_ms;
if (transition->base_transition.remaining_delay_time_ms > time_step_ms){
transition->base_transition.remaining_delay_time_ms -= time_step_ms;
transition->base_transition.phase_start_ms += time_step_ms;
break;
}
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
if (transition->base_transition.remaining_transition_time_ms != 0) break;
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
case MESH_TRANSITION_STATE_ACTIVE:
if (event != TRANSITION_UPDATE) break;
time_step_ms = current_timestamp_ms - transition->base_transition.phase_start_ms;
if (transition->base_transition.remaining_transition_time_ms > time_step_ms){
transition->base_transition.remaining_transition_time_ms -= time_step_ms;
transition->base_transition.phase_start_ms += time_step_ms;
break;
}
mesh_server_transition_handler(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
break;
default:
break;
}
}
static void mesh_server_transition_setup_transition_or_instantaneous_update(mesh_model_t *mesh_model, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt){
mesh_generic_on_off_state_t * generic_on_off_server_state = (mesh_generic_on_off_state_t *)mesh_model->model_data;
mesh_transition_t * transition = &generic_on_off_server_state->transition_data.base_transition;
if ((transition_time_gdtt == 0) && (delay_time_gdtt == 0)){
// instanteneous update
mesh_server_transition_handler(transition, MODEL_STATE_UPDATE_REASON_SET);
} else {
// transaction
mesh_access_transitions_setup(transition, (mesh_model_t *) mesh_model, transition_time_gdtt, delay_time_gdtt, &mesh_server_transition_step_bool);
mesh_access_transitions_add(transition);
}
mesh_access_transition_setup(mesh_model, transition, transition_time_gdtt, delay_time_gdtt, &mesh_server_transition_handler);
}
// Generic On Off State
void mesh_generic_on_off_server_register_packet_handler(mesh_model_t *generic_on_off_server_model, btstack_packet_handler_t transition_events_packet_handler){
@ -223,10 +123,9 @@ static mesh_pdu_t * mesh_generic_on_off_status_message(mesh_model_t *generic_on_
mesh_generic_on_off_state_t * state = (mesh_generic_on_off_state_t *) generic_on_off_server_model->model_data;
// setup message
mesh_transport_pdu_t * transport_pdu = NULL;
if (state->transition_data.base_transition.remaining_transition_time_ms != 0) {
log_info("On/Off Status: value %u, remaining time %u ms", state->transition_data.current_value, state->transition_data.base_transition.remaining_transition_time_ms);
uint8_t remaining_time = mesh_access_time_as_gdtt(state->transition_data.base_transition.step_duration_ms, state->transition_data.base_transition.remaining_transition_time_ms);
transport_pdu = mesh_access_setup_segmented_message(&mesh_generic_on_off_status_transition, state->transition_data.current_value,
if (state->transition_data.base_transition.num_steps > 0) {
uint8_t remaining_time = (((uint8_t)state->transition_data.base_transition.step_resolution) << 6) | (state->transition_data.base_transition.num_steps);
transport_pdu = mesh_access_setup_segmented_message(&mesh_generic_on_off_status_transition, state->transition_data.current_value,
state->transition_data.target_value, remaining_time);
} else {
log_info("On/Off Status: value %u, no transition active", state->transition_data.current_value);
@ -267,7 +166,7 @@ static bool generic_on_off_handle_set_message(mesh_model_t *mesh_model, mesh_pdu
// ignore on retransmission
break;
default:
mesh_access_transitions_setup_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
generic_on_off_server_state->transition_data.target_value = on_off_value;
if (mesh_access_parser_available(&parser) == 2){