Pokemon-Gen3-to-Gen-X/source/communicator.c
2023-04-09 01:27:03 +02:00

959 lines
36 KiB
C

#include "base_include.h"
#include "communicator.h"
#include "sio.h"
#include "sio_buffers.h"
#include "party_handler.h"
#include "useful_qualifiers.h"
#include <stddef.h>
#define GEN2_ENTER_STATES_NUM 4
#define GEN2_START_STATES_NUM 5
#define GEN1_ENTER_STATES_NUM 5
#define GEN1_START_STATES_NUM 2
#define SKIP_SENDS 0x10
#define MAX_WAIT_FOR_SYN 30
#define MIN_WAIT_FOR_SYN 3
#define MAX_NO_NEW_INFO 30
#define NUMBER_OF_ENTITIES 2
void set_start_state(enum START_TRADE_STATE);
void init_received_gen3(void);
u16 get_pos_bytes_from_index(u16);
u16 get_index_from_pos_bytes(u8, u8);
u8 set_received_gen3(u16);
u16 get_first_not_received_gen3(void);
u16 get_not_received_length_gen3(u16);
int increment_last_tranfer(void);
void reset_transfer_data_between_sync(void);
void init_transfer_data(void);
u8 get_offer(u8, u8, u8);
u8 get_accept(u8, u8);
u8 get_success(u8, u8);
int communicate_buffer(u8, u8);
int check_if_continue(u8, const u8*, const u8*, size_t, int, int, u8);
int process_data_arrived_gen1(u8, u8);
int process_data_arrived_gen2(u8, u8);
enum TRADING_STATE prepare_out_data_and_update_gen3(u8*, u8, u16*, u16, u8, enum TRADING_STATE, enum TRADING_STATE);
u32 prepare_out_data_gen3(void);
enum TRADING_STATE check_in_success_data_gen3(u8, u8, u16, u16, enum TRADING_STATE, enum TRADING_STATE, enum TRADING_STATE, u8);
void process_in_data_gen3(u32);
const u8 gen2_start_trade_enter_room[NUMBER_OF_ENTITIES][GEN2_ENTER_STATES_NUM] = {
{ENTER_TRADE_SLAVE, 0x61, 0xD1, 0x00},
{ENTER_TRADE_MASTER, 0x61, 0xD1, 0x00}
};
const u8 gen2_start_trade_enter_room_next[NUMBER_OF_ENTITIES][GEN2_ENTER_STATES_NUM] = {
{ENTER_TRADE_MASTER, 0x61, 0xD1, 0x00},
{0x61, 0xD1, 0x00, 0x00}
};
const u8 gen2_start_trade_start_trade_procedure[NUMBER_OF_ENTITIES][GEN2_START_STATES_NUM] = {
{START_TRADE_BYTE_GEN2, START_TRADE_BYTE_GEN2, 0, 0x76, 0x76},
{START_TRADE_BYTE_GEN2, START_TRADE_BYTE_GEN2, 0x76, SEND_NO_INFO, SEND_NO_INFO}
};
const u8 gen2_start_trade_start_trade_procedure_next[NUMBER_OF_ENTITIES][GEN2_START_STATES_NUM] = {
{START_TRADE_BYTE_GEN2, START_TRADE_BYTE_GEN2, 0x76, 0x76, 0x76},
{START_TRADE_BYTE_GEN2, 0, SYNCHRONIZE_BYTE, SEND_NO_INFO, SEND_NO_INFO}
};
const u8 gen1_start_trade_enter_room[NUMBER_OF_ENTITIES][GEN1_ENTER_STATES_NUM] = {
{ENTER_TRADE_SLAVE, 0x60, CHOICE_BYTE_GEN1, END_CHOICE_BYTE_GEN1, END_CHOICE_BYTE_GEN1},
{ENTER_TRADE_MASTER, 0x60, CHOICE_BYTE_GEN1, END_CHOICE_BYTE_GEN1, SEND_NO_INFO}
};
const u8 gen1_start_trade_enter_room_next[NUMBER_OF_ENTITIES][GEN1_ENTER_STATES_NUM] = {
{ENTER_TRADE_MASTER, 0x60, CHOICE_BYTE_GEN1, CHOICE_BYTE_GEN1, CHOICE_BYTE_GEN1},
{0x60, CHOICE_BYTE_GEN1, CHOICE_BYTE_GEN1, START_TRADE_BYTE_GEN1, SEND_NO_INFO}
};
const u8 gen1_start_trade_start_trade_procedure[NUMBER_OF_ENTITIES][GEN1_START_STATES_NUM] = {
{START_TRADE_BYTE_GEN1, START_TRADE_BYTE_GEN1},
{START_TRADE_BYTE_GEN1, START_TRADE_BYTE_GEN1}
};
const u8 gen1_start_trade_start_trade_procedure_next[NUMBER_OF_ENTITIES][GEN1_START_STATES_NUM] = {
{START_TRADE_BYTE_GEN1, START_TRADE_BYTE_GEN1},
{START_TRADE_BYTE_GEN1, SYNCHRONIZE_BYTE}
};
u8 stored_curr_gen;
u8* out_buffer;
u8* in_buffer;
size_t* transfer_sizes;
u16 base_pos;
u8 sizes_index;
u8 syn_transmitted;
u8 has_transmitted_syn;
volatile u8 next_long_pause = 0;
int last_transfer_counter;
size_t buffer_counter;
size_t buffer_counter_out;
u8 start_state_updated;
enum START_TRADE_STATE start_state;
enum TRADING_STATE trading_state;
u8 trade_offer_out;
u8 trade_offer_in;
u32 prepared_value;
int skip_sends = 0;
u8 base_pos_out = 0;
u8 increment_out = 0;
u8 last_filtered = 0;
u8 received_once = 0;
u8 since_last_recv_gen3 = 0;
u8 schedule_update = 0;
u8 anti_cloning_nybble = 0;
int own_end_gen3;
u16 species_out_gen3;
u16 species_in_gen3;
u32 pid_out_gen3;
u32 pid_in_gen3;
u16 other_pos_gen3;
u16 other_end_gen3;
u8 is_done_gen3;
u8 received_gen3[(sizeof(struct gen3_trade_data)>>4)+1];
void prepare_gen23_success(struct gen3_mon_data_unenc* mon_out, struct gen3_mon_data_unenc* mon_in) {
pid_out_gen3 = mon_out->comm_pid;
pid_in_gen3 = mon_in->comm_pid;
anti_cloning_nybble = 0;
if((mon_in->growth.species == MEW_SPECIES) || (mon_out->growth.species == MEW_SPECIES))
anti_cloning_nybble = 1;
else if((mon_in->growth.species == CELEBI_SPECIES) || (mon_out->growth.species == CELEBI_SPECIES))
anti_cloning_nybble = 2;
}
void prepare_gen3_offer(struct gen3_mon_data_unenc* mon) {
species_out_gen3 = mon->growth.species;
}
u16 get_gen3_offer() {
return species_in_gen3;
}
void try_to_end_trade() {
syn_transmitted = 0;
received_once = 0;
schedule_update = 0;
trade_offer_out = CANCEL_VALUE;
trading_state = HAVE_OFFER;
}
void try_to_offer(u8 index) {
syn_transmitted = 0;
received_once = 0;
schedule_update = 0;
trade_offer_out = (index & 0xF);
trading_state = HAVE_OFFER;
}
void try_to_accept_offer() {
syn_transmitted = 0;
received_once = 0;
schedule_update = 0;
trade_offer_out = ACCEPT_VALUE;
trading_state = HAVE_ACCEPT;
}
void try_to_decline_offer() {
syn_transmitted = 0;
received_once = 0;
schedule_update = 0;
trade_offer_out = DECLINE_VALUE;
trading_state = HAVE_ACCEPT;
}
void try_to_success() {
syn_transmitted = 0;
received_once = 0;
schedule_update = 0;
trading_state = HAVE_SUCCESS;
}
int get_received_trade_offer() {
if((trade_offer_in == CANCEL_VALUE) || (trade_offer_out == CANCEL_VALUE)) {
if(trade_offer_in == trade_offer_out)
return TRADE_CANCELLED;
return WANTS_TO_CANCEL;
}
return trade_offer_in;
}
int has_accepted_offer() {
if((trade_offer_in == DECLINE_VALUE) || (trade_offer_out == DECLINE_VALUE))
return 0;
return 1;
}
IWRAM_CODE void set_start_state(enum START_TRADE_STATE new_val) {
start_state = new_val;
start_state_updated = 1;
}
u16 get_transferred(u8 index) {
if(sizes_index > index)
return get_buffer_size(index);
if(sizes_index < index)
return 0;
if(stored_curr_gen == 3)
return buffer_counter<<1;
return buffer_counter;
}
IWRAM_CODE void init_received_gen3() {
for(size_t i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++)
received_gen3[i] = 0;
buffer_counter = 0;
own_end_gen3 = -1;
is_done_gen3 = 0;
since_last_recv_gen3 = 0;
}
IWRAM_CODE u16 get_pos_bytes_from_index(u16 index) {
int pos_byte = START_SENDING_DATA;
while(index >= DATA_CHUNK_SIZE) {
pos_byte++;
index -= DATA_CHUNK_SIZE;
}
return index | (pos_byte << 8);
}
IWRAM_CODE u16 get_index_from_pos_bytes(u8 position, u8 control_byte) {
u16 final_pos = position;
if(final_pos >= DATA_CHUNK_SIZE)
final_pos = 0;
return final_pos + (DATA_CHUNK_SIZE * ((control_byte&0xF) - START_SENDING_DATA));
}
IWRAM_CODE u8 set_received_gen3(u16 index) {
if(index >= (sizeof(struct gen3_trade_data)>>1))
return 1;
int i = index >> 3;
int j = index & 7;
if((received_gen3[i]>>j)&1)
return 1;
received_gen3[i] |= 1<<j;
return 0;
}
IWRAM_CODE u16 get_first_not_received_gen3() {
for(size_t i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++)
for(int j = 0; j < 8; j++) {
if(((i<<3) + j) >= (sizeof(struct gen3_trade_data)>>1))
return sizeof(struct gen3_trade_data)>>1;
if(!((received_gen3[i]>>j)&1))
return (i<<3) + j;
}
return sizeof(struct gen3_trade_data)>>1;
}
IWRAM_CODE u16 get_not_received_length_gen3(u16 index) {
if(index >= (sizeof(struct gen3_trade_data)>>1))
return 0;
int i_pos = index >> 3;
int j_pos = index & 7;
int j = j_pos;
int total = 0;
for(size_t i = i_pos; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) {
for(; j < 8; j++) {
if(((i<<3) + j) >= (sizeof(struct gen3_trade_data)>>1))
return total;
if(!((received_gen3[i]>>j)&1))
total++;
else
return total;
}
j = 0;
}
return total;
}
IWRAM_CODE int increment_last_tranfer() {
return last_transfer_counter++;
}
enum TRADING_STATE get_trading_state() {
return trading_state;
}
enum START_TRADE_STATE get_start_state() {
if(!start_state_updated)
return START_TRADE_NO_UPDATE;
start_state_updated = 0;
return start_state;
}
IWRAM_CODE void reset_transfer_data_between_sync() {
has_transmitted_syn = 0;
syn_transmitted = 0;
increment_out = 0;
buffer_counter = 0;
buffer_counter_out = 0;
last_transfer_counter = 0;
}
IWRAM_CODE void init_transfer_data() {
base_pos = 0;
reset_transfer_data_between_sync();
sizes_index = 0;
set_start_state(START_TRADE_PAR);
}
IWRAM_CODE enum START_TRADE_STATE get_start_state_raw() {
return start_state;
}
void init_start_state() {
set_start_state(START_TRADE_UNK);
}
IWRAM_CODE u8 get_offer(u8 data, u8 trade_offer_start, u8 end_trade_value) {
next_long_pause = 1;
u8 limit_trade_offer = trade_offer_start + PARTY_SIZE;
if(((data >= trade_offer_start) && (data < limit_trade_offer)) || (data == end_trade_value)) {
if(received_once) {
trade_offer_in = data - trade_offer_start;
trading_state = RECEIVED_OFFER;
}
else
received_once = 1;
}
return trade_offer_start + trade_offer_out;
}
IWRAM_CODE u8 get_accept(u8 data, u8 trade_offer_start) {
next_long_pause = 1;
if((data == (trade_offer_start + DECLINE_VALUE)) || (data == (trade_offer_start + ACCEPT_VALUE))) {
if(received_once) {
trade_offer_in = data - trade_offer_start;
trading_state = RECEIVED_ACCEPT;
}
else
received_once = 1;
}
return trade_offer_start + trade_offer_out;
}
IWRAM_CODE u8 get_success(u8 data, u8 trade_offer_start) {
next_long_pause = 1;
if(((data & 0xF0) == (trade_offer_start & 0xF0))) {
if(received_once)
trading_state = RECEIVED_SUCCESS;
else
received_once = 1;
}
return trade_offer_start;
}
MAX_OPTIMIZE void set_next_vcount_interrupt(void){
int next_stop = REG_VCOUNT + VCOUNT_WAIT_LINES;
if(next_stop >= SCANLINES)
next_stop -= SCANLINES;
__set_next_vcount_interrupt(next_stop);
}
IWRAM_CODE int communicate_buffer(u8 data, u8 is_master) {
u8 ignore_data = 0;
if(!has_transmitted_syn) {
if((syn_transmitted > MAX_WAIT_FOR_SYN) && (!is_master)) {
if(data == SYNCHRONIZE_BYTE) {
base_pos_out = 0;
ignore_data = 1;
}
else
has_transmitted_syn = 1;
}
else {
if((is_master) && (syn_transmitted >= MAX_WAIT_FOR_SYN))
syn_transmitted = MAX_WAIT_FOR_SYN;
if(syn_transmitted < MIN_WAIT_FOR_SYN) {
if((data != SEND_NO_INFO) && (data == SYNCHRONIZE_BYTE))
syn_transmitted++;
return SYNCHRONIZE_BYTE;
}
if((data != SEND_NO_INFO) && (data != SYNCHRONIZE_BYTE)) {
has_transmitted_syn = 1;
base_pos_out = 1;
}
else {
if(data != SEND_NO_INFO)
syn_transmitted++;
return SYNCHRONIZE_BYTE;
}
}
}
if((!ignore_data) && (data != SEND_NO_INFO)) {
in_buffer[buffer_counter + base_pos] = data;
last_transfer_counter = 0;
buffer_counter++;
if((buffer_counter == (transfer_sizes[sizes_index])) || ((!is_master) && (sizes_index == get_number_of_buffers()-1) && (buffer_counter == (transfer_sizes[sizes_index]-base_pos_out)))) {
base_pos += transfer_sizes[sizes_index];
sizes_index++;
reset_transfer_data_between_sync();
if(sizes_index >= get_number_of_buffers()) {
set_start_state(START_TRADE_DON);
trading_state = NO_INFO;
}
if(buffer_counter_out < transfer_sizes[sizes_index-1])
return out_buffer[base_pos-1];
return SEND_0_INFO;
}
}
buffer_counter_out++;
if(buffer_counter_out > transfer_sizes[sizes_index])
buffer_counter_out = transfer_sizes[sizes_index];
return out_buffer[buffer_counter_out - 1 + base_pos];
}
IWRAM_CODE int check_if_continue(u8 data, const u8* sends, const u8* recvs, size_t size, int new_state, int new_send, u8 filter) {
if((filter) && (data >= 0x10))
data = data & 0xF0;
if(data == recvs[buffer_counter]) {
buffer_counter++;
if(((buffer_counter) >= size) || (sends[buffer_counter] == SEND_NO_INFO)) {
buffer_counter = 0;
set_start_state(new_state);
return new_send;
}
}
return sends[buffer_counter];
}
IWRAM_CODE int process_data_arrived_gen1(u8 data, u8 is_master) {
if(is_master)
is_master = 1;
if(start_state != START_TRADE_DON) {
switch(start_state) {
case START_TRADE_ENT:
return check_if_continue(data, gen1_start_trade_enter_room[is_master], gen1_start_trade_enter_room_next[is_master], GEN1_ENTER_STATES_NUM, START_TRADE_WAI, START_TRADE_BYTE_GEN1 | 1, 1);
case START_TRADE_STA:
return check_if_continue(data, gen1_start_trade_start_trade_procedure[is_master], gen1_start_trade_start_trade_procedure_next[is_master], GEN1_START_STATES_NUM, START_TRADE_SYN, SEND_NO_INFO, 1);
case START_TRADE_PAR:
return communicate_buffer(data, is_master);
case START_TRADE_SYN:
if(is_master)
init_transfer_data();
else if((data == SYNCHRONIZE_BYTE) || (buffer_counter == MAX_WAIT_FOR_SYN))
init_transfer_data();
else
buffer_counter++;
return SEND_NO_INFO;
default:
if((data == ENTER_TRADE_MASTER) || (data == ENTER_TRADE_SLAVE)) {
buffer_counter = 0;
last_filtered = 0;
set_start_state(START_TRADE_ENT);
return gen1_start_trade_enter_room[is_master][0];
}
if(data == SYNCHRONIZE_BYTE) {
buffer_counter = 0;
last_filtered = 0;
init_transfer_data();
return SEND_NO_INFO;
}
u8 filtered_data = data & 0xF0;
if(last_filtered != filtered_data) {
buffer_counter = 0;
last_filtered = filtered_data;
}
if((!is_master) && (filtered_data == START_TRADE_BYTE_GEN1)) {
buffer_counter++;
if(buffer_counter >= MAX_WAIT_FOR_SYN) {
buffer_counter = 0;
last_filtered = 0;
init_transfer_data();
}
return data;
}
if((!is_master) && (filtered_data == CHOICE_BYTE_GEN1)) {
buffer_counter++;
if(buffer_counter >= MAX_WAIT_FOR_SYN) {
buffer_counter = 0;
last_filtered = 0;
set_start_state(START_TRADE_STA);
return END_CHOICE_BYTE_GEN1;
}
if(buffer_counter > 4)
return END_CHOICE_BYTE_GEN1;
return CHOICE_BYTE_GEN1;
}
if(is_master && (filtered_data == START_TRADE_BYTE_GEN1)) {
buffer_counter = 0;
return data;
}
if(is_master && (filtered_data == CHOICE_BYTE_GEN1)) {
buffer_counter = 2;
set_start_state(START_TRADE_ENT);
return SEND_NO_INFO;
}
if(is_master) {
if(start_state == START_TRADE_UNK)
return gen1_start_trade_enter_room[is_master][0];
return START_TRADE_BYTE_GEN1 | 1;
}
return SEND_NO_INFO;
}
}
else {
// Space things out
if(syn_transmitted < MIN_WAIT_FOR_SYN) {
syn_transmitted++;
return SEND_NO_INFO;
}
// The actual trading menu logic
switch(trading_state) {
case HAVE_OFFER:
return get_offer(data, GEN1_TRADE_OFFER_START, END_TRADE_BYTE_GEN1);
case HAVE_ACCEPT:
return get_accept(data, GEN1_TRADE_OFFER_START);
case HAVE_SUCCESS:
return get_success(data, GEN1_TRADE_SUCCESS_BASE);
default:
return SEND_NO_INFO;
}
}
}
IWRAM_CODE int process_data_arrived_gen2(u8 data, u8 is_master) {
if(is_master)
is_master = 1;
if(start_state != START_TRADE_DON)
switch(start_state) {
case START_TRADE_ENT:
return check_if_continue(data, gen2_start_trade_enter_room[is_master], gen2_start_trade_enter_room_next[is_master], GEN2_ENTER_STATES_NUM, START_TRADE_WAI, gen2_start_trade_start_trade_procedure[is_master][0], 0);
case START_TRADE_STA:
return check_if_continue(data, gen2_start_trade_start_trade_procedure[is_master], gen2_start_trade_start_trade_procedure_next[is_master], GEN2_START_STATES_NUM, START_TRADE_SYN, SEND_NO_INFO, 0);
case START_TRADE_PAR:
return communicate_buffer(data, is_master);
case START_TRADE_SYN:
if(is_master)
init_transfer_data();
else if((data == SYNCHRONIZE_BYTE) || (buffer_counter == MAX_WAIT_FOR_SYN))
init_transfer_data();
else
buffer_counter++;
return SEND_NO_INFO;
default:
if((data == ENTER_TRADE_MASTER) || (data == ENTER_TRADE_SLAVE)) {
buffer_counter = 0;
set_start_state(START_TRADE_ENT);
return gen2_start_trade_enter_room[is_master][0];
}
if(data == END_TRADE_BYTE_GEN2) {
buffer_counter = 0;
set_start_state(START_TRADE_END);
return END_TRADE_BYTE_GEN2;
}
if(is_master && (data == gen2_start_trade_enter_room_next[is_master][0])) {
buffer_counter = 0;
set_start_state(START_TRADE_ENT);
return gen2_start_trade_enter_room[is_master][0];
}
if(data == START_TRADE_BYTE_GEN2) {
buffer_counter = 0;
set_start_state(START_TRADE_STA);
return gen2_start_trade_start_trade_procedure[is_master][0];
}
if(is_master) {
if(start_state == START_TRADE_UNK)
return gen2_start_trade_enter_room[is_master][0];
return gen2_start_trade_start_trade_procedure[is_master][0];
}
return SEND_NO_INFO;
}
else {
// Space things out
if(syn_transmitted < MIN_WAIT_FOR_SYN) {
syn_transmitted++;
return SEND_NO_INFO;
}
// The actual trading menu logic
switch(trading_state) {
case HAVE_OFFER:
return get_offer(data, GEN2_TRADE_OFFER_START, END_TRADE_BYTE_GEN2);
case HAVE_ACCEPT:
return get_accept(data, GEN2_TRADE_OFFER_START);
case HAVE_SUCCESS:
return get_success(data, GEN2_TRADE_SUCCESS_BASE|anti_cloning_nybble);
default:
return SEND_NO_INFO;
}
}
}
IWRAM_CODE enum TRADING_STATE prepare_out_data_and_update_gen3(u8* out_command_id, u8 new_command_id, u16* out_data, u16 new_data, u8 do_update, enum TRADING_STATE base_trading_state, enum TRADING_STATE success_new_trading_state) {
*out_data = new_data;
*out_command_id = new_command_id;
if(do_update)
base_trading_state = success_new_trading_state;
return base_trading_state;
}
IWRAM_CODE u32 prepare_out_data_gen3() {
u16* out_buffer_gen3 = (u16*)out_buffer;
u8 out_control_byte = 0;
u8 out_position = 0;
u16 out_data = 0;
if(start_state != START_TRADE_DON) {
if(is_done_gen3)
out_control_byte |= DONE_GEN3;
else
out_control_byte |= NOT_DONE_GEN3;
if((own_end_gen3 == -1) && (!is_done_gen3)) {
out_control_byte = (out_control_byte & 0xF0) | ASKING_DATA;
u16 first_not_recv = get_first_not_received_gen3() & 0xFFF;
u16 end_not_recv = (get_not_received_length_gen3(first_not_recv) + first_not_recv) & 0xFFF;
own_end_gen3 = end_not_recv - 1;
// This should NEVER come true
if(first_not_recv == end_not_recv) {
if(are_checksum_same_gen3((struct gen3_trade_data*)in_buffer))
is_done_gen3 = 1;
else
init_received_gen3();
}
out_data = first_not_recv | ((end_not_recv & 0xF)<<12);
out_position = end_not_recv >> 4;
}
else if(other_pos_gen3 != other_end_gen3) {
out_control_byte |= SENDING_DATA_GEN3;
u16 out_pos_control = get_pos_bytes_from_index(other_pos_gen3);
out_position = out_pos_control & 0xFF;
out_control_byte |= out_pos_control >> 8;
out_data = out_buffer_gen3[other_pos_gen3++];
}
return out_data | (out_position<<16) | (out_control_byte<<24);
}
else {
// Do trading stuff here
out_control_byte = (IN_PARTY_TRADE_GEN3 | DONE_GEN3);
u8 out_command_id = 0;
out_data = 0;
switch(trading_state) {
case HAVE_OFFER:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, trade_offer_out|GEN3_TRADE_OFFER_START, &out_data, species_out_gen3, schedule_update, trading_state, RECEIVED_OFFER);
break;
case HAVE_ACCEPT:
case HAVE_ACCEPT_BASE:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, trade_offer_out|GEN3_TRADE_ACCEPT_BASE_START, &out_data, species_out_gen3, schedule_update, trading_state, HAVE_ACCEPT_FINAL);
break;
case HAVE_ACCEPT_FINAL:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, trade_offer_out|GEN3_TRADE_ACCEPT_FINAL_START, &out_data, species_out_gen3, schedule_update, trading_state, RECEIVED_ACCEPT);
break;
case HAVE_SUCCESS:
case HAVE_SUCCESS_SPECIES_OUT:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_SPECIES_OUT, &out_data, species_out_gen3, schedule_update, trading_state, HAVE_SUCCESS_LOW_PID_OUT);
break;
case HAVE_SUCCESS_LOW_PID_OUT:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_LOW_PID_OUT, &out_data, (pid_out_gen3 & 0xFFFF), schedule_update, trading_state, HAVE_SUCCESS_HIGH_PID_OUT);
break;
case HAVE_SUCCESS_HIGH_PID_OUT:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_HIGH_PID_OUT, &out_data, (pid_out_gen3 >> 16), schedule_update, trading_state, HAVE_SUCCESS_SPECIES_IN);
break;
case HAVE_SUCCESS_SPECIES_IN:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_SPECIES_IN, &out_data, species_in_gen3, schedule_update, trading_state, HAVE_SUCCESS_LOW_PID_IN);
break;
case HAVE_SUCCESS_LOW_PID_IN:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_LOW_PID_IN, &out_data, (pid_in_gen3 & 0xFFFF), schedule_update, trading_state, HAVE_SUCCESS_HIGH_PID_IN);
break;
case HAVE_SUCCESS_HIGH_PID_IN:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_HIGH_PID_IN, &out_data, (pid_in_gen3 >> 16), schedule_update, trading_state, HAVE_SUCCESS_COMPLETED);
break;
case HAVE_SUCCESS_COMPLETED:
trading_state = prepare_out_data_and_update_gen3(&out_command_id, GEN3_TRADE_SUCCESS_ALL_OK, &out_data, 0, schedule_update, trading_state, RECEIVED_SUCCESS);
break;
case RECEIVED_SUCCESS:
out_command_id = GEN3_TRADE_SUCCESS_ALL_OK;
out_data = 0;
break;
case FAILED_SUCCESS:
out_command_id = GEN3_TRADE_SUCCESS_FAILED;
out_data = 0;
break;
default:
break;
}
schedule_update = 0;
return out_data | (out_command_id<<16) | (out_control_byte<<24);
}
}
IWRAM_CODE enum TRADING_STATE check_in_success_data_gen3(u8 command_id, u8 cmp_command, u16 recv_data, u16 cmp_data, enum TRADING_STATE base_trading_state, enum TRADING_STATE success_new_trading_state, enum TRADING_STATE failure_new_trading_state, u8 bad_command) {
if(command_id == cmp_command) {
if(recv_data == cmp_data)
base_trading_state = success_new_trading_state;
else
base_trading_state = failure_new_trading_state;
}
else if(command_id == bad_command)
base_trading_state = failure_new_trading_state;
return base_trading_state;
}
IWRAM_CODE void process_in_data_gen3(u32 data) {
last_transfer_counter = 0;
u16* in_buffer_gen3 = (u16*)in_buffer;
u16 recv_data = data & 0xFFFF;
u8 position = (data >> 16) & 0xFF;
u8 control_byte = (data >> 24) & 0xFF;
if(start_state != START_TRADE_DON) {
if((control_byte & 0xF) >= ASKING_DATA) {
control_byte &= ~SENDING_DATA_GEN3;
if(control_byte & NOT_DONE_GEN3) {
other_pos_gen3 = data & 0xFFF;
other_end_gen3 = (data >> 12) & 0xFFF;
if(other_end_gen3 > (sizeof(struct gen3_trade_data) >> 1))
other_end_gen3 = sizeof(struct gen3_trade_data) >> 1;
if(other_pos_gen3 >= other_end_gen3)
other_pos_gen3 = other_end_gen3;
}
else if(control_byte & DONE_GEN3)
other_pos_gen3 = other_end_gen3;
}
if((!is_done_gen3) && (control_byte & SENDING_DATA_GEN3)) {
u16 recv_pos = get_index_from_pos_bytes(position, control_byte);
if(recv_pos >= (sizeof(struct gen3_trade_data) >> 1)) {
recv_pos = 0;
control_byte &= ~SENDING_DATA_GEN3;
}
if(control_byte & SENDING_DATA_GEN3) {
in_buffer_gen3[recv_pos] = recv_data;
if(!set_received_gen3(recv_pos)) {
since_last_recv_gen3 = 0;
buffer_counter++;
}
if(buffer_counter >= (sizeof(struct gen3_trade_data)>>1)) {
if(are_checksum_same_gen3((struct gen3_trade_data*)in_buffer))
is_done_gen3 = 1;
else
init_received_gen3();
}
else if(own_end_gen3 == recv_pos)
own_end_gen3 = -1;
}
}
if(!is_done_gen3) {
since_last_recv_gen3++;
if(since_last_recv_gen3 > MAX_NO_NEW_INFO) {
since_last_recv_gen3 = 0;
own_end_gen3 = -1;
}
}
if((control_byte & DONE_GEN3) && is_done_gen3) {
set_start_state(START_TRADE_DON);
schedule_update = 0;
trading_state = NO_INFO;
}
}
else {
// Do trading stuff here
schedule_update = 0;
if(control_byte == (IN_PARTY_TRADE_GEN3 | DONE_GEN3)) {
enum TRADING_STATE base_trading_state = trading_state;
u8 command_id = (data >> 16) & 0xFF;
switch(trading_state) {
case HAVE_OFFER:
get_offer(command_id, GEN3_TRADE_OFFER_START, END_TRADE_BYTE_GEN3);
if(trading_state != base_trading_state)
species_in_gen3 = recv_data;
break;
case HAVE_ACCEPT:
case HAVE_ACCEPT_BASE:
get_accept(command_id, GEN3_TRADE_ACCEPT_BASE_START);
if(trading_state != base_trading_state) {
trading_state = HAVE_ACCEPT_FINAL;
if(species_in_gen3 != recv_data)
trade_offer_out = DECLINE_VALUE;
}
break;
case HAVE_ACCEPT_FINAL:
get_accept(command_id, GEN3_TRADE_ACCEPT_FINAL_START);
if(trading_state != base_trading_state) {
if(species_in_gen3 != recv_data) {
trade_offer_out = DECLINE_VALUE;
trade_offer_in = DECLINE_VALUE;
}
}
break;
case HAVE_SUCCESS:
case HAVE_SUCCESS_SPECIES_OUT:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_SPECIES_OUT, recv_data, species_in_gen3, trading_state, HAVE_SUCCESS_LOW_PID_OUT, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_LOW_PID_OUT:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_LOW_PID_OUT, recv_data, (pid_in_gen3 & 0xFFFF), trading_state, HAVE_SUCCESS_HIGH_PID_OUT, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_HIGH_PID_OUT:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_HIGH_PID_OUT, recv_data, (pid_in_gen3 >> 16), trading_state, HAVE_SUCCESS_SPECIES_IN, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_SPECIES_IN:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_SPECIES_IN, recv_data, species_out_gen3, trading_state, HAVE_SUCCESS_LOW_PID_IN, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_LOW_PID_IN:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_LOW_PID_IN, recv_data, (pid_out_gen3 & 0xFFFF), trading_state, HAVE_SUCCESS_HIGH_PID_IN, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_HIGH_PID_IN:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_HIGH_PID_IN, recv_data, (pid_out_gen3 >> 16), trading_state, HAVE_SUCCESS_COMPLETED, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
case HAVE_SUCCESS_COMPLETED:
trading_state = check_in_success_data_gen3(command_id, GEN3_TRADE_SUCCESS_ALL_OK, recv_data, 0, trading_state, RECEIVED_SUCCESS, FAILED_SUCCESS, GEN3_TRADE_SUCCESS_FAILED);
break;
default:
break;
}
// Do one more transfer out than needed, to be sure.
// Update once you have the data to send out ready.
// Unless we failed...
if((base_trading_state != trading_state) && (trading_state != FAILED_SUCCESS)) {
trading_state = base_trading_state;
schedule_update = 1;
}
}
}
}
IWRAM_CODE MAX_OPTIMIZE void slave_routine(void) {
#ifdef HAS_SIO
if(!(REG_IF & IRQ_SERIAL)){
REG_IF |= IRQ_SERIAL;
int value;
int data = sio_read(SIO_8);
if(stored_curr_gen == 3){
data = sio_read(SIO_32);
process_in_data_gen3(data);
value = prepare_out_data_gen3();
//PRINT_FUNCTION("0x%08X - 0x%08X\n", value, data);
}
else if(stored_curr_gen == 2)
value = process_data_arrived_gen2(data, 0);
else
value = process_data_arrived_gen1(data, 0);
sio_handle_irq_slave(value);
next_long_pause = 0;
//PRINT_FUNCTION("0x\x0D - 0x\x0D\n", value, 2, data, 2);
//sio_handle_irq_slave(process_data_arrived_gen12(sio_read(SIO_8), 0));
}
#endif
}
IWRAM_CODE MAX_OPTIMIZE void master_routine_gen3(void) {
REG_IF |= IRQ_VCOUNT;
#ifdef HAS_SIO
int data;
u8 success = 0;
data = sio_send_if_ready_master(prepared_value, SIO_32, &success);
if(success) {
//PRINT_FUNCTION("0x%08X - 0x%08X\n", prepared_value, data);
next_long_pause = 0;
process_in_data_gen3(data);
prepared_value = prepare_out_data_gen3();
}
#endif
set_next_vcount_interrupt();
}
IWRAM_CODE MAX_OPTIMIZE void master_routine_gen12(void) {
REG_IF |= IRQ_VCOUNT;
#ifdef HAS_SIO
int data;
if(!skip_sends) {
data = sio_send_master(prepared_value, SIO_8);
next_long_pause = 0;
if(data != SEND_NO_INFO) {
//PRINT_FUNCTION("0x\x0D - 0x\x0D\n", prepared_value, 2, data, 2);
if(stored_curr_gen == 2)
prepared_value = process_data_arrived_gen2(data, 1);
else
prepared_value = process_data_arrived_gen1(data, 1);
if(next_long_pause)
skip_sends = SKIP_SENDS;
}
else
skip_sends = SKIP_SENDS;
}
else
skip_sends--;
#endif
set_next_vcount_interrupt();
}
void start_transfer(u8 is_master, u8 curr_gen)
{
out_buffer = (u8*)get_communication_buffer(OWN_BUFFER);
in_buffer = (u8*)get_communication_buffer(OTHER_BUFFER);
buffer_counter = 0;
skip_sends = 0;
transfer_sizes = get_buffer_sizes();
base_pos = 0;
sizes_index = 0;
syn_transmitted = 0;
has_transmitted_syn = 0;
last_filtered = 0;
other_pos_gen3 = 0;
other_end_gen3 = 0;
last_transfer_counter = 0;
stored_curr_gen = curr_gen;
if(curr_gen != 3) {
if(!is_master) {
#ifdef HAS_SIO
init_sio_normal(SIO_SLAVE, SIO_8);
irqSet(IRQ_SERIAL, slave_routine);
irqEnable(IRQ_SERIAL);
sio_normal_prepare_irq_slave(SEND_NO_INFO);
#endif
}
else{
set_next_vcount_interrupt();
#ifdef HAS_SIO
init_sio_normal(SIO_MASTER, SIO_8);
#endif
irqSet(IRQ_VCOUNT, master_routine_gen12);
prepared_value = ENTER_TRADE_MASTER;
irqEnable(IRQ_VCOUNT);
REG_DISPSTAT |= SCANLINE_IRQ_BIT;
}
}
else {
init_received_gen3();
set_start_state(START_TRADE_PAR);
if(!is_master) {
#ifdef HAS_SIO
init_sio_normal(SIO_SLAVE, SIO_32);
irqSet(IRQ_SERIAL, slave_routine);
irqEnable(IRQ_SERIAL);
sio_normal_prepare_irq_slave(SEND_0_INFO);
#endif
}
else {
set_next_vcount_interrupt();
#ifdef HAS_SIO
init_sio_normal(SIO_MASTER, SIO_32);
#endif
irqSet(IRQ_VCOUNT, master_routine_gen3);
prepared_value = SEND_0_INFO;
irqEnable(IRQ_VCOUNT);
REG_DISPSTAT |= SCANLINE_IRQ_BIT;
}
}
}
void base_stop_transfer(u8 is_master) {
if(!is_master) {
#ifdef HAS_SIO
irqDisable(IRQ_SERIAL);
sio_stop_irq_slave();
#endif
}
else{
irqDisable(IRQ_VCOUNT);
REG_DISPSTAT &= ~SCANLINE_IRQ_BIT;
}
}
void stop_transfer(u8 is_master) {
buffer_counter = 0;
while(next_long_pause);
base_stop_transfer(is_master);
}