static int test_request(void) { uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH); plug_in_source(0, 0); task_wake(PD_PORT_TO_TASK_ID(0)); task_wait_event(2 * PD_T_CC_DEBOUNCE + 100 * MSEC); TEST_ASSERT(pd_port[0].polarity == 0); /* We're in SNK_DISCOVERY now. Let's send the source cap. */ simulate_source_cap(0); task_wait_event(30 * MSEC); TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[0].msg_rx_id)); /* Wait for the power request */ task_wake(PD_PORT_TO_TASK_ID(0)); task_wait_event(35 * MSEC); /* tSenderResponse: 24~30 ms */ inc_rx_id(0); /* Process the request */ TEST_ASSERT(pd_test_tx_msg_verify_sop(0)); TEST_ASSERT(pd_test_tx_msg_verify_short(0, PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP, pd_port[0].msg_tx_id, 1))); TEST_ASSERT(pd_test_tx_msg_verify_word(0, expected_rdo)); TEST_ASSERT(pd_test_tx_msg_verify_crc(0)); TEST_ASSERT(pd_test_tx_msg_verify_eop(0)); inc_tx_id(0); /* We're done */ unplug(0); return EC_SUCCESS; }
static int test_sink(void) { int i; plug_in_sink(1, 1); task_wake(PD_PORT_TO_TASK_ID(1)); task_wait_event(250 * MSEC); /* tTypeCSinkWaitCap: 210~250 ms */ TEST_ASSERT(pd_port[1].polarity == 1); /* The source cap should be sent */ TEST_ASSERT(pd_test_tx_msg_verify_sop(1)); TEST_ASSERT(pd_test_tx_msg_verify_short(1, PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE, PD_ROLE_DFP, pd_port[1].msg_tx_id, pd_src_pdo_cnt))); for (i = 0; i < pd_src_pdo_cnt; ++i) TEST_ASSERT(pd_test_tx_msg_verify_word(1, pd_src_pdo[i])); TEST_ASSERT(pd_test_tx_msg_verify_crc(1)); TEST_ASSERT(pd_test_tx_msg_verify_eop(1)); /* Looks good. Ack the source cap. */ simulate_goodcrc(1, PD_ROLE_SINK, pd_port[1].msg_tx_id); task_wake(PD_PORT_TO_TASK_ID(1)); usleep(30 * MSEC); inc_tx_id(1); /* We're done */ unplug(1); return EC_SUCCESS; }
static int test_partial_load(void) { /* We have a 3A charger, but we just want 1.5A */ system_load_current_ma = 1500; plug_charger(CHARGE_SUPPLIER_TEST4, 0, 500, 3000, 2500); /* We should end up with a little bit more than 1.5A */ TEST_ASSERT(wait_stable_no_overcurrent()); TEST_ASSERT(is_in_range(charge_limit_ma, 1500, 1600)); /* Ok someone just started watching YouTube */ system_load_current_ma = 2000; TEST_ASSERT(wait_stable_no_overcurrent()); TEST_ASSERT(is_in_range(charge_limit_ma, 2000, 2100)); /* Somehow the system load increases again */ system_load_current_ma = 2600; while (task_wait_event(RAMP_STABLE_DELAY) == TASK_EVENT_OVERCURRENT) { /* Charger goes away but comes back after 0.6 seconds */ unplug_charger(); usleep(MSEC * 600); plug_charger(CHARGE_SUPPLIER_TEST4, 0, 500, 3000, 2500); usleep(CHARGE_DETECT_DELAY_TEST); /* Ramp restarts at 500 mA */ TEST_ASSERT(is_in_range(charge_limit_ma, 500, 700)); } /* Alright the charger isn't powerful enough, so we'll stop at 2.5A */ TEST_ASSERT(is_in_range(charge_limit_ma, 2300, 2500)); TEST_ASSERT(unplug_charger_and_check()); return EC_SUCCESS; }
void power_button_task(void) { uint64_t t; uint64_t tsleep; while (1) { t = get_time().val; /* Update state machine */ CPRINTS("PB task %d = %s", pwrbtn_state, state_names[pwrbtn_state]); state_machine(t); /* Sleep until our next timeout */ tsleep = -1; if (tnext_state && tnext_state < tsleep) tsleep = tnext_state; t = get_time().val; if (tsleep > t) { unsigned d = tsleep == -1 ? -1 : (unsigned)(tsleep - t); /* * (Yes, the conversion from uint64_t to unsigned could * theoretically overflow if we wanted to sleep for * more than 2^32 us, but our timeouts are small enough * that can't happen - and even if it did, we'd just go * back to sleep after deciding that we woke up too * early.) */ CPRINTS("PB task %d = %s, wait %d", pwrbtn_state, state_names[pwrbtn_state], d); task_wait_event(d); } } }
void usb_spi_task(void) { /* Remap SPI2 to DMA channels 6 and 7 */ STM32_SYSCFG_CFGR1 |= (1 << 24); gpio_config_module(MODULE_SPI_MASTER, 1); /* Set all four SPI pins to high speed */ STM32_GPIO_OSPEEDR(GPIO_B) |= 0xff000000; /* Enable clocks to SPI2 module */ STM32_RCC_APB1ENR |= STM32_RCC_PB1_SPI2; /* Reset SPI2 */ STM32_RCC_APB1RSTR |= STM32_RCC_PB1_SPI2; STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_SPI2; spi_enable(1); while (1) { task_wait_event(-1); while (usb_spi_service_request(&usb_spi)) ; } }
static enum power_state power_wait_s5_rtc_reset(void) { static int s5_exit_tries; /* Wait for S5 exit and then attempt RTC reset */ while ((power_get_signals() & IN_PCH_SLP_S4_DEASSERTED) == 0) { /* Handle RSMRST passthru event while waiting */ handle_rsmrst(POWER_S5); if (task_wait_event(SECOND*4) == TASK_EVENT_TIMER) { CPRINTS("timeout waiting for S5 exit"); chipset_force_g3(); /* Assert RTCRST# and retry 5 times */ board_rtc_reset(); if (++s5_exit_tries > 4) { s5_exit_tries = 0; return POWER_G3; /* Stay off */ } udelay(10 * MSEC); return POWER_G3S5; /* Power up again */ } } s5_exit_tries = 0; return POWER_S5S3; /* Power up to next state */ }
uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us) { uint64_t deadline = get_time().val + timeout_us; uint32_t events = 0; int time_remaining_us = timeout_us; /* Add the timer event to the mask so we can indicate a timeout */ event_mask |= TASK_EVENT_TIMER; while (!(events & event_mask)) { /* Collect events to re-post later */ events |= task_wait_event(time_remaining_us); time_remaining_us = deadline - get_time().val; if (timeout_us > 0 && time_remaining_us <= 0) { /* Ensure we return a TIMER event if we timeout */ events |= TASK_EVENT_TIMER; break; } } /* Re-post any other events collected */ if (events & ~event_mask) tasks[task_get_current()].event |= events & ~event_mask; return events & event_mask; }
static int command_accel_read_xyz(int argc, char **argv) { char *e; int id, n = 1, ret; struct motion_sensor_t *sensor; vector_3_t v; if (argc < 2) return EC_ERROR_PARAM_COUNT; /* First argument is sensor id. */ id = strtoi(argv[1], &e, 0); if (*e || id < 0 || id >= motion_sensor_count) return EC_ERROR_PARAM1; if (argc >= 3) n = strtoi(argv[2], &e, 0); sensor = &motion_sensors[id]; while ((n == -1) || (n-- > 0)) { ret = sensor->drv->read(sensor, v); if (ret == 0) ccprintf("Current data %d: %-5d %-5d %-5d\n", id, v[X], v[Y], v[Z]); else ccprintf("vector not ready\n"); ccprintf("Last calib. data %d: %-5d %-5d %-5d\n", id, sensor->xyz[X], sensor->xyz[Y], sensor->xyz[Z]); task_wait_event(MIN_MOTION_SENSE_WAIT_TIME); } return EC_SUCCESS; }
uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait) { tasks[tskid].event = event; if (wait) return task_wait_event(-1); return 0; }
void usb_charger_task(void) { int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1); uint32_t evt; /* Initialize chip and enable interrupts */ pi3usb9281_init(port); usb_charger_bc12_detect(port); while (1) { /* Wait for interrupt */ evt = task_wait_event(-1); /* Interrupt from the Pericom chip, determine charger type */ if (evt & USB_CHG_EVENT_BC12) usb_charger_bc12_detect(port); /* * Re-enable interrupts on pericom charger detector since the * chip may periodically reset itself, and come back up with * registers in default state. TODO(crosbug.com/p/33823): Fix * these unwanted resets. */ if (evt & USB_CHG_EVENT_VBUS) { pi3usb9281_enable_interrupts(port); #ifndef CONFIG_USB_PD_TCPM_VBUS CPRINTS("VBUS p%d %d", port, pd_snk_is_vbus_provided(port)); #endif } } }
static enum cts_rc timer_calibration_test(void) { /* Error margin: +/-2 msec (0.2% for one second) */ const int32_t margin = 2 * MSEC; int32_t elapsed, delta; timestamp_t t0, t1; gpio_enable_interrupt(GPIO_CTS_NOTIFY); interrupt_enable(); sync(); t0 = get_time(); /* Wait for interrupt */ task_wait_event(-1); t1 = get_time(); elapsed = (int32_t)(t1.val - t0.val); delta = elapsed - SECOND; if (delta < -margin) { CPRINTS("DUT clock runs too fast: %+d usec", delta); return CTS_RC_FAILURE; } if (margin < delta) { CPRINTS("DUT clock runs too slow: %+d usec", delta); return CTS_RC_FAILURE; } return CTS_RC_SUCCESS; }
enum cts_rc test_task_priority(void) { uint32_t event; repeat_count = 2; task_wake(TASK_ID_A); task_wake(TASK_ID_C); event = task_wait_event(5 * SECOND); if (event != TASK_EVENT_WAKE) { CPRINTS("Woken up by unexpected event: 0x%08x", event); return CTS_RC_FAILURE; } if (wake_count[0] != repeat_count - 1 || wake_count[1] != repeat_count - 1) { CPRINTS("Unexpected counter values: %d %d %d", wake_count[0], wake_count[1], wake_count[2]); return CTS_RC_FAILURE; } /* TODO: Verify no tasks are ready, no events are pending. */ if (*task_get_event_bitmap(TASK_ID_A) || *task_get_event_bitmap(TASK_ID_B) || *task_get_event_bitmap(TASK_ID_C)) { CPRINTS("Events are pending"); return CTS_RC_FAILURE; } return CTS_RC_SUCCESS; }
static int test_overcurrent_after_switch_outlet(void) { system_load_current_ma = 3000; /* Here's a less powerful charger */ plug_charger(CHARGE_SUPPLIER_TEST5, 0, 500, 3000, 1500); usleep(SECOND * 5); /* Now the user decides to move it to a nearby outlet */ unplug_charger(); usleep(SECOND * 1.5); plug_charger(CHARGE_SUPPLIER_TEST5, 0, 500, 3000, 1500); /* Okay the user is satisified */ while (task_wait_event(RAMP_STABLE_DELAY) == TASK_EVENT_OVERCURRENT) { /* Charger goes away but comes back after 0.6 seconds */ unplug_charger(); usleep(MSEC * 600); plug_charger(CHARGE_SUPPLIER_TEST5, 0, 500, 3000, 1500); usleep(CHARGE_DETECT_DELAY_TEST); /* Ramp restarts at 500 mA */ TEST_ASSERT(is_in_range(charge_limit_ma, 500, 700)); } TEST_ASSERT(is_in_range(charge_limit_ma, 1300, 1500)); TEST_ASSERT(unplug_charger_and_check()); return EC_SUCCESS; }
void *_task_start_impl(void *a) { long tid = (long)a; struct task_args *arg = task_info + tid; my_task_id = tid; pthread_mutex_lock(&run_lock); /* Wait for scheduler */ task_wait_event(1); tasks[tid].event = 0; /* Start the task routine */ (arg->routine)(arg->d); /* Catch exited routine */ while (1) task_wait_event(-1); }
void task_tick(void *data) { task_wait_event(-1); ccprintf("\n[starting Task T]\n"); /* Wake up every tick */ while (1) /* Wait for timer interrupt message */ usleep(3000); }
static void key_test(va_list args) { word c; do { c = *(word *)task_wait_event(E_KEYBOARD); } while ((c & 0xff) !='!'); puts("\x7"); }
CONFIG_TASK_LIST CONFIG_TEST_TASK_LIST #undef TASK /* Idle task */ void __idle(void *d) { while (1) task_wait_event(-1); }
void elan_tp_task(void) { elan_tp_init(); gpio_enable_interrupt(GPIO_TOUCHPAD_INT); while (1) { task_wait_event(-1); elan_tp_read_report(); } }
/** * Wait for the power button to be released * * @param timeout_us Timeout in microseconds, or -1 to wait forever * @return EC_SUCCESS if ok, or * EC_ERROR_TIMEOUT if power button failed to release */ int power_button_wait_for_release(int timeout_us) { timestamp_t deadline; timestamp_t now = get_time(); deadline.val = now.val + timeout_us; while (!power_button_is_stable || power_button_is_pressed()) { now = get_time(); if (timeout_us < 0) { task_wait_event(-1); } else if (timestamp_expired(deadline, &now) || (task_wait_event(deadline.val - now.val) == TASK_EVENT_TIMER)) { CPRINTS("power button not released in time"); return EC_ERROR_TIMEOUT; } } CPRINTS("power button released in time"); return EC_SUCCESS; }
/* * This is for NOT having enough hibernate (more precisely, the stand-by mode) * wake-up source pin. STM32L100 supports 3 wake-up source pins: * * WKUP1 (PA0) -- used for ACOK_PMU * WKUP2 (PC13) -- used for LID_OPEN * WKUP3 (PE6) -- cannot be used due to IC package. * * However, we need the power button as a wake-up source as well and there is * no available pin for us (we don't want to move the ACOK_PMU pin). * * Fortunately, the STM32L is low-power enough so that we don't need the * super-low-power mode. So, we fake this hibernate mode and accept the * following wake-up source. * * RTC alarm (faked as well). * Power button * Lid open * AC detected * * The original issue is here: crosbug.com/p/25435. */ void __enter_hibernate(uint32_t seconds, uint32_t microseconds) { int i; fake_hibernate = 1; #ifdef CONFIG_POWER_COMMON /* * A quick hack to stop annoying messages from charger task. * * When the battery is under 3%, the power task would call * power_off() to shutdown AP. However, the power_off() would * notify the HOOK_CHIPSET_SHUTDOWN, where the last hook is * charge_shutdown() and it hibernates the power task (infinite * loop -- not real CPU hibernate mode). Unfortunately, the * charger task is still running. It keeps generating annoying * log message. * * Thus, the hack is to set the power state machine (before we * enter infinite loop) so that the charger task thinks the AP * is off and stops generating messages. */ power_set_state(POWER_G3); #endif /* * Change keyboard outputs to high-Z to reduce power draw. * We don't need corresponding code to change them back, * because fake hibernate is always exited with a reboot. * * A little hacky to do this here. */ for (i = GPIO_KB_OUT00; i < GPIO_KB_OUT00 + KEYBOARD_COLS; i++) gpio_set_flags(i, GPIO_INPUT); ccprints("fake hibernate. waits for power button/lid/RTC/AC"); cflush(); if (seconds || microseconds) { if (seconds) sleep(seconds); if (microseconds) usleep(microseconds); } else { while (1) task_wait_event(-1); } ccprints("fake RTC alarm fires. resets EC"); cflush(); system_reset(SYSTEM_RESET_HARD); }
void gesture_calc(void) { /* Only check for gesture if lid is closed and tap detection is on */ if (!tap_detection || lid_is_open()) return; if (gesture_tap_for_battery()) { CPRINTS("Double Tap!"); lightbar_sequence(LIGHTBAR_TAP); /* Don't need to run motion sense task for a while */ task_wait_event(500 * MSEC); } }
void pd_command_task(void) { /* On startup exchange status with the PD */ pd_exchange_status(); while (1) { /* Wait for the next command event */ int evt = task_wait_event(-1); /* Process event to send status to PD */ if (evt & TASK_EVENT_EXCHANGE_PD_STATUS) pd_exchange_status(); } }
void als_task(void) { int i, val; uint16_t *mapped = (uint16_t *)host_get_memmap(EC_MEMMAP_ALS); uint16_t als_data; while (1) { for (i = 0; i < EC_ALS_ENTRIES && i < ALS_COUNT; i++) { als_data = als_read(i, &val) == EC_SUCCESS ? val : 0; mapped[i] = als_data; } task_wait_event(SECOND); } }
void host_command_task(void) { host_command_init(); while (1) { /* Wait for the next command event */ int evt = task_wait_event(-1); /* Process it */ if ((evt & TASK_EVENT_CMD_PENDING) && pending_args) { pending_args->result = host_command_process(pending_args); host_send_response(pending_args); } } }
enum cts_rc test_task_disable_irq(void) { uint32_t event; wake_me_up = 1; task_disable_irq(CTS_IRQ_NUMBER); /* Sleep and wait for interrupt. This should time out. */ event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2); if (event != TASK_EVENT_TIMER) { CPRINTS("Woken up by unexpected event: 0x%08x", event); return CTS_RC_FAILURE; } task_enable_irq(CTS_IRQ_NUMBER); return CTS_RC_SUCCESS; }
enum cts_rc test_nested_interrupt_high_low(void) { uint32_t event; event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 4); if (event != TASK_EVENT_TIMER) { CPRINTS("Woken up by unexpected event: 0x%08x", event); return CTS_RC_FAILURE; } if (memcmp(state, "BCAD", sizeof(state))) { CPRINTS("State transition differs from expectation"); return CTS_RC_FAILURE; } return CTS_RC_SUCCESS; }
enum cts_rc test_task_wait_event(void) { uint32_t event; wake_me_up = 1; /* Sleep and wait for interrupt. This shouldn't time out. */ event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2); if (event != TASK_EVENT_WAKE) { CPRINTS("Woken up by unexpected event: 0x%08x", event); return CTS_RC_FAILURE; } if (!got_interrupt) { CPRINTS("Interrupt context not detected"); return CTS_RC_TIMEOUT; } return CTS_RC_SUCCESS; }
static int i2c_write_raw_slave(int port, void *buf, int len) { stm32_dma_chan_t *chan; int rv; /* we don't want to race with TxE interrupt event */ disable_i2c_interrupt(port); /* Configuring DMA1 channel DMAC_SLAVE_TX */ enable_ack(port); chan = dma_get_channel(DMAC_SLAVE_TX); dma_prepare_tx(dma_tx_option + port, len, buf); /* Start the DMA */ dma_go(chan); /* Configuring i2c to use DMA */ STM32_I2C_CR2(port) |= (1 << 11); if (in_interrupt_context()) { /* Poll for the transmission complete flag */ dma_wait(DMAC_SLAVE_TX); dma_clear_isr(DMAC_SLAVE_TX); } else { /* Wait for the transmission complete Interrupt */ dma_enable_tc_interrupt(DMAC_SLAVE_TX); rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable_tc_interrupt(DMAC_SLAVE_TX); if (!(rv & TASK_EVENT_WAKE)) { CPRINTS("Slave timeout, resetting i2c"); i2c_init_port(port); } } dma_disable(DMAC_SLAVE_TX); STM32_I2C_CR2(port) &= ~(1 << 11); enable_i2c_interrupt(port); return len; }
void cts_task(void) { enum cts_rc rc; int i; task_wake(TASK_ID_TICK); for (i = 0; i < CTS_TEST_ID_COUNT; i++) { clear_state(); rc = tests[i].run(); CPRINTF("\n%s %d\n", tests[i].name, rc); cflush(); } CPRINTS("Task test suite finished"); cflush(); /* Sleep forever */ task_wait_event(-1); }
void task_abc(void *data) { int task_id = task_get_current(); int id = task_id - TASK_ID_A; task_id_t next = task_id + 1; if (next > TASK_ID_C) next = TASK_ID_A; task_wait_event(-1); CPRINTS("%c Starting", 'A' + id); cflush(); while (1) { wake_count[id]++; if (id == 2 && wake_count[id] == repeat_count) task_set_event(TASK_ID_CTS, TASK_EVENT_WAKE, 1); else task_set_event(next, TASK_EVENT_WAKE, 1); } }