// something has gone wrong :( void network_tyrian_halt( unsigned int err, bool attempt_sync ) { #ifdef __BLACKBERRY__ quit = true; #else const char *err_msg[] = { "Quitting...", "Other player quit the game.", "Network connection was lost.", "Network connection failed.", "Network version mismatch.", "Network delay mismatch.", "Network player number conflict.", }; quit = true; if (err >= COUNTOF(err_msg)) err = 0; fade_black(10); VGAScreen = VGAScreenSeg; JE_loadPic(VGAScreen, 2, false); JE_dString(VGAScreen, JE_fontCenter(err_msg[err], SMALL_FONT_SHAPES), 140, err_msg[err], SMALL_FONT_SHAPES); JE_showVGA(); fade_palette(colors, 10, 0, 255); if (attempt_sync) { while (!network_is_sync() && network_is_alive()) { service_SDL_events(false); network_check(); SDL_Delay(16); } } if (err) { while (!JE_anyButton()) SDL_Delay(16); } fade_black(10); SDLNet_Quit(); JE_tyrianHalt(5); #endif }
void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ) { service_SDL_events(false); while ((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)) { SDL_Delay(SDL_POLL_INTERVAL); poll_joysticks(); service_SDL_events(false); if (isNetworkGame) network_check(); } }
void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ) { service_SDL_events(false); while ((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)) { JE_showVGA(); // Must update screen on Android to get new mouse events SDL_Delay(SDL_POLL_INTERVAL); poll_joysticks(); service_SDL_events(false); #ifdef WITH_NETWORK if (isNetworkGame) network_check(); #endif } }
// attempt to punch through firewall by firing off UDP packets at the opponent // exchange game information int network_connect( void ) { #ifdef __BLACKBERRY__ #else SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port); SDLNet_UDP_Bind(socket, 0, &ip); Uint16 episodes = 0, episodes_local = 0; assert(EPISODE_MAX <= 16); for (int i = EPISODE_MAX - 1; i >= 0; i--) { episodes <<= 1; episodes |= (episodeAvail[i] != 0); } episodes_local = episodes; assert(NET_PACKET_SIZE - 12 >= 20 + 1); if (strlen(network_player_name) > 20) network_player_name[20] = '\0'; connect_reset: network_prepare(PACKET_CONNECT); SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); SDLNet_Write16(network_delay, &packet_out_temp->data[6]); SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); strcpy((char *)&packet_out_temp->data[12], network_player_name); network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT // until opponent sends connect packet while (true) { push_joysticks_as_keyboard(); service_SDL_events(false); if (newkey && lastkey_sym == SDLK_ESCAPE) network_tyrian_halt(0, false); // never timeout last_in_tick = SDL_GetTicks(); if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) break; network_update(); network_check(); SDL_Delay(16); } connect_again: if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION) { fprintf(stderr, "error: network version did not match opponent's\n"); network_tyrian_halt(4, true); } if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay) { fprintf(stderr, "error: network delay did not match opponent's\n"); network_tyrian_halt(5, true); } if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum) { fprintf(stderr, "error: player number conflicts with opponent's\n"); network_tyrian_halt(6, true); } episodes = SDLNet_Read16(&packet_in[0]->data[8]); for (int i = 0; i < EPISODE_MAX; i++) { episodeAvail[i] &= (episodes & 1); episodes >>= 1; } network_opponent_name = malloc(packet_in[0]->len - 12 + 1); strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]); network_update(); // until opponent has acknowledged while (!network_is_sync()) { service_SDL_events(false); // got a duplicate packet; process it again (but why?) if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) goto connect_again; network_check(); // maybe opponent didn't get our packet if (SDL_GetTicks() - last_out_tick > NET_RETRY) goto connect_reset; SDL_Delay(16); } // send another packet since sometimes the network syncs without both connect packets exchanged // there should be a better way to handle this network_prepare(PACKET_CONNECT); SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); SDLNet_Write16(network_delay, &packet_out_temp->data[6]); SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); strcpy((char *)&packet_out_temp->data[12], network_player_name); network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT connected = true; #endif return 0; }
// receive state packet, wait until received bool network_state_update( void ) { #ifdef __BLACKBERRY__ return false; #else if (network_state_is_reset()) { return 0; } else { packets_shift_up(packet_state_in, NET_PACKET_QUEUE); packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE); last_state_in_sync++; // current xor packet index int x = network_delay - (last_state_in_sync - 1) % network_delay - 1; // loop until needed packet is available while (!packet_state_in[0]) { // xor the packet from thin air, if possible if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR) { // check for all other required packets bool okay = true; for (int i = 1; i <= x; i++) { if (packet_state_in[i] == NULL) { okay = false; break; } } if (okay) { packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in[0], packet_state_in_xor[x]); for (int i = 1; i <= x; i++) for (int j = 4; j < packet_state_in[0]->len; j++) packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j]; break; } } static Uint32 resend_tick = 0; if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND) { SDLNet_Write16(PACKET_STATE_RESEND, &packet_out_temp->data[0]); SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]); network_send_no_ack(4); // PACKET_RESEND resend_tick = SDL_GetTicks(); } if (network_check() == 0) SDL_Delay(1); } if (network_delay > 1) { // process the current in packet against the xor queue if (packet_state_in_xor[x] == NULL) { packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in_xor[x], packet_state_in[0]); packet_state_in_xor[x]->status = 0; } else { for (int j = 4; j < packet_state_in_xor[x]->len; j++) packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j]; } } last_state_in_tick = SDL_GetTicks(); } return 1; #endif }
int main(void){ /* * Initializations */ cli(); // Make sure interrupts belong to us MCUCR = (1<<IVCE); MCUCR = 0; // Initialize global variables g_ext_ref_present = false; g_gps_present = false; g_switch_pos = PREFER_INTERNAL; g_ref = NO_REF; // Atmega128 setup_atmel_io_ports(); // Reset ClkDist chip reset_TI_CDCE18005(); // GPSDO communication usart_init(); // Ethernet stack network_init(); register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet); register_udp_listener(OCTOCLOCK_UDP_GPSDO_PORT, handle_udp_gpsdo_packet); // Timers TIMER1_INIT(); // Network TIMER3_INIT(); // External reference check // Debug (does nothing when not in debug mode) DEBUG_INIT(); DEBUG_LOG(" "); // Force a newline between runs leds_off(); sei(); // Check if GPS present (should only need to happen once) g_gps_present = (PIND & (1<<DDD4)); // State of previous iteration prev_ref = NO_REF; prev_switch_pos = PREFER_EXTERNAL; cli(); prev_ICR3 = ICR3; sei(); prev_num_overflows = 0; /* * Main loop */ while(true){ // Check switch position g_switch_pos = (PINC & (1<<DDC1)) ? PREFER_EXTERNAL : PREFER_INTERNAL; /* * Check input capture pin for external reference detection. * * 16-bit reads could be corrupted during an interrupt, so * disable interrupts for safety. */ cli(); current_ICR3 = ICR3; current_num_overflows = num_overflows; sei(); // Signal detected, reset timer if(current_ICR3 != prev_ICR3){ cli(); TCNT3 = 0; num_overflows = 0; sei(); g_ext_ref_present = true; } // Timeout, no external reference detected if(current_num_overflows >= EXT_REF_TIMEOUT){ g_ext_ref_present = false; } // Determine and set reference based on state if(!g_gps_present && !g_ext_ref_present) g_ref = NO_REF; else if(g_gps_present && !g_ext_ref_present) g_ref = INTERNAL; else if(!g_gps_present && g_ext_ref_present) g_ref = EXTERNAL; else g_ref = (g_switch_pos == PREFER_INTERNAL) ? INTERNAL : EXTERNAL; if((g_ref != prev_ref) || (g_switch_pos != prev_switch_pos)){ if(g_switch_pos == PREFER_INTERNAL) prefer_internal(); else prefer_external(); } // Record this iteration's state prev_ref = g_ref; prev_switch_pos = g_switch_pos; prev_ICR3 = current_ICR3; prev_num_overflows = current_num_overflows; // Handle incoming Ethernet packets network_check(); } }