u32 InputWait() { static u64 delay = 0; u32 pad_state_old = HID_STATE; delay = (delay) ? 72 : 128; timer_start(); while (true) { u32 pad_state = HID_STATE; if (!(pad_state & BUTTON_ANY)) { // no buttons pressed u32 special_key = i2cReadRegister(I2C_DEV_MCU, 0x10); if (special_key == 0x01) return pad_state | BUTTON_POWER; else if (special_key == 0x04) return pad_state | BUTTON_HOME; pad_state_old = pad_state; delay = 0; continue; } if ((pad_state == pad_state_old) && (!(pad_state & BUTTON_ARROW) || (delay && (timer_msec() < delay)))) continue; // make sure the key is pressed u32 t_pressed = 0; for(; (t_pressed < 0x13000) && (pad_state == HID_STATE); t_pressed++); if (t_pressed >= 0x13000) return pad_state; } }
bool uart_consume_timeout(uint8_t* buffer, uint16_t timeout) { timer_reset(); while (uart_rx_start == uart_rx_end) { if (timer_msec() >= timeout) { return false; } } *buffer = uart_rx_buf[uart_rx_start]; uart_rx_start = (uart_rx_start +1) % UART_RING_LEN; return true; }
/** * Play one round of the contention game. If neither side received the force_master flag, * they each wait a random amount of time before sending the ping packet. The first to acknowledge * the other side's ping is the slave. If the two packets conflict, the came ends in a conflict and * must be run again. * If after a timeout passes no token has been received, the device assumes that the pad has * been snapped and is disconnected from its twin. * @param usb_present gives the usb-connected side precedence if force_master is not set. */ ConnectionState uart_play_round(bool force_master, bool usb_present) { timer_reset(); uint16_t ms = 0; while (timer_msec() < 1) {} // let uarts settle if (!force_master) { hwrng_start(); timer_reset(); while (timer_msec() < 2) {} // wait 2 ms while (!hwrng_done()) {} // wait for random data to become available if (!usb_present) { ms = 3+(hwrng_bits()[0] & 0x3f); // additional delay of 3-67 ms } else { ms = 0; // skip additional delay on usb-connected end } } timer_reset(); while (timer_msec() < ms) { if (uart_has_data()) { uint8_t b = uart_consume(); if (b == UTOK_GAME_PING) { uart_send_byte(UTOK_GAME_ACK); return CS_TWINNED_SLAVE; } else if (b == UTOK_GAME_ACK) { return CS_TWINNED_COLLISION; } } } uart_send_byte(UTOK_GAME_PING); timer_reset(); ms = 1000 - ms; while (timer_msec() < ms) { if (uart_has_data()) { uint8_t b = uart_consume(); if (b == UTOK_GAME_ACK) { return CS_TWINNED_MASTER; } else if (b == UTOK_GAME_PING) { return CS_TWINNED_COLLISION; } } } return CS_SINGLE; }