void chrono_start_stop_handler(ClickRecognizerRef recognizer, Window *window) { PblTm time; int seconds; get_time(&time); seconds = get_time_seconds(&time); // The start/stop button was pressed. if (chrono_running) { // If the chronograph is currently running, this means to stop (or // pause). chrono_hold_seconds = seconds - chrono_start_seconds; chrono_running = false; chrono_lap_paused = false; vibes_enqueue_custom_pattern(tap); update_hands(&time); // We change the click config provider according to the chrono run // state. When the chrono is stopped, we listen for a different // set of buttons than when it is started. window_set_click_config_provider(window, (ClickConfigProvider)stopped_click_config_provider); } else { // If the chronograph is not currently running, this means to // start, from the currently showing Chronograph time. chrono_start_seconds = seconds - chrono_hold_seconds; chrono_running = true; vibes_enqueue_custom_pattern(tap); update_hands(&time); window_set_click_config_provider(window, (ClickConfigProvider)started_click_config_provider); } }
void network_throttle::tick() { double time_now = get_time_seconds(); if (!m_any_packet_yet) m_start_time = time_now; // starting now network_time_seconds current_sample_time_slot = time_to_slot( time_now ); // T=13.7 --> 13 (for 1-second smallwindow) network_time_seconds last_sample_time_slot = time_to_slot( m_last_sample_time ); // moving to next position, and filling gaps // !! during this loop the m_last_sample_time and last_sample_time_slot mean the variable moved in +1 // TODO optimize when moving few slots at once while ( (!m_any_packet_yet) || (last_sample_time_slot < current_sample_time_slot)) { _dbg3("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")"); // rotate buffer for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1]; m_history[0] = packet_info(); if (! m_any_packet_yet) { m_last_sample_time = time_now; } m_last_sample_time += 1; last_sample_time_slot = time_to_slot( m_last_sample_time ); // increase and recalculate time, time slot m_any_packet_yet=true; } m_last_sample_time = time_now; // the real exact last time }
// Determines the specific hand bitmaps that should be displayed based // on the current time. void compute_hands(PblTm *time, struct HandPlacement *placement) { int seconds; seconds = get_time_seconds(time); placement->hour_hand_index = ((NUM_STEPS_HOUR * seconds) / (3600 * 12)) % NUM_STEPS_HOUR; placement->minute_hand_index = ((NUM_STEPS_MINUTE * seconds) / 3600) % NUM_STEPS_MINUTE; #ifdef SHOW_SECOND_HAND placement->second_hand_index = ((NUM_STEPS_SECOND * seconds) / 60) % NUM_STEPS_SECOND; #endif // SHOW_SECOND_HAND #ifdef SHOW_DAY_CARD placement->day_index = time->tm_wday; #endif // SHOW_DAY_CARD #ifdef SHOW_DATE_CARD placement->date_value = time->tm_mday; #endif // SHOW_DATE_CARD #ifdef ENABLE_HOUR_BUZZER placement->hour_buzzer = (seconds / 3600) % 24; #endif #ifdef MAKE_CHRONOGRAPH { int chrono_seconds; if (chrono_running && !chrono_lap_paused) { // The chronograph is running. Show the active elapsed time. chrono_seconds = (seconds - chrono_start_seconds + SECONDS_PER_DAY) % SECONDS_PER_DAY; } else { // The chronograph is paused. Show the time it is paused on. chrono_seconds = chrono_hold_seconds; } #ifdef SHOW_CHRONO_MINUTE_HAND // The chronograph minute hand rolls completely around in 30 // minutes (not 60). placement->chrono_minute_hand_index = ((NUM_STEPS_CHRONO_MINUTE * chrono_seconds) / 1800) % NUM_STEPS_CHRONO_MINUTE; #endif // SHOW_CHRONO_MINUTE_HAND #ifdef SHOW_CHRONO_SECOND_HAND placement->chrono_second_hand_index = ((NUM_STEPS_CHRONO_SECOND * chrono_seconds) / 60) % NUM_STEPS_CHRONO_SECOND; #endif // SHOW_CHRONO_SECOND_HAND } #endif // MAKE_CHRONOGRAPH }
void chrono_lap_button() { PblTm time; int seconds; get_time(&time); if (chrono_lap_paused) { // If we were already paused, this resumes the motion, jumping // ahead to the currently elapsed time. chrono_lap_paused = false; vibes_enqueue_custom_pattern(tap); update_hands(&time); } else { // If we were not already paused, this pauses the hands here (but // does not stop the timer). seconds = get_time_seconds(&time); chrono_hold_seconds = seconds - chrono_start_seconds; chrono_lap_paused = true; vibes_enqueue_custom_pattern(tap); update_hands(&time); } }
// MAIN LOGIC: void network_throttle::calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const { const double the_window_size = std::max( (double)m_window_size , ((force_window>0) ? force_window : m_window_size) ); if (!m_any_packet_yet) { cts.window=0; cts.average=0; cts.delay=0; cts.recomendetDataSize = m_network_minimal_segment; // should be overrided by caller anyway return ; // no packet yet, I can not decide about sleep time } network_time_seconds window_len = (the_window_size-1) * m_slot_size ; // -1 since current slot is not finished window_len += (m_last_sample_time - time_to_slot(m_last_sample_time)); // add the time for current slot e.g. 13.7-13 = 0.7 auto time_passed = get_time_seconds() - m_start_time; cts.window = std::max( std::min( window_len , time_passed ) , m_slot_size ) ; // window length resulting from size of history but limited by how long ago history was started, // also at least slot size (e.g. 1 second) to not be ridiculous // window_len e.g. 5.7 because takes into account current slot time size_t Epast = 0; // summ of traffic till now for (auto sample : m_history) Epast += sample.m_size; const size_t E = Epast; const size_t Enow = Epast + packet_size ; // including the data we're about to send now const double M = m_target_speed; // max const double D1 = (Epast - M*cts.window) / M; // delay - how long to sleep to get back to target speed const double D2 = (Enow - M*cts.window) / M; // delay - how long to sleep to get back to target speed (including current packet) cts.delay = (D1*0.80 + D2*0.20); // finall sleep depends on both with/without current packet // update_overheat(); cts.average = Epast/cts.window; // current avg. speed (for info) if (Epast <= 0) { if (cts.delay>=0) cts.delay = 0; // no traffic in history so we will not wait } double Wgood=-1; { // how much data we recommend now to download Wgood = the_window_size + 1; cts.recomendetDataSize = M*cts.window - E; } if (dbg) { std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; std::string history_str = oss.str(); MTRACE((cts.delay > 0 ? "SLEEP" : "") << "dbg " << m_name << ": " << "speed is A=" << std::setw(8) <<cts.average<<" vs " << "Max=" << std::setw(8) <<M<<" " << " so sleep: " << "D=" << std::setw(8) <<cts.delay<<" sec " << "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") " << "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " " << "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " " << "History: " << std::setw(8) << history_str << " " << "m_last_sample_time=" << std::setw(8) << m_last_sample_time ); } }