diff --git a/src/main.rs b/src/main.rs index 66d4101..2c5640d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -211,14 +211,55 @@ impl Event { for m in schedule.matches.iter() { let tuple = tm_tuple_to_struct(m.match_tuple.clone().unwrap()); let Some(field) = get_field_tuple(&m.assigned_field) else {continue;}; + let Some(state) = &m.state else {continue;}; + let Some(scheduled) = m.time_scheduled else {continue;}; + let Some(started) = m.time_started else {continue;}; + let Some(resumed) = m.time_resumed else {continue;}; let red_1 = m.alliances[0].teams[0].number(); let red_2 = m.alliances[0].teams[1].number(); let blue_1 = m.alliances[1].teams[0].number(); let blue_2 = m.alliances[1].teams[1].number(); + let match_state: MatchState; + match state { + 0 => match_state = MatchState{ + state: GameState::Scheduled, + start: scheduled as f64 / 1000.0, + }, + 3 => { // If the match is active, use it's current state + // since I can't find a way to request the auton/driver state + match self.divisions.get(&tuple.division) { + None => match_state = MatchState{ + state: GameState::Scheduled, + start: started as f64 / 1000.0, + }, + Some(division) => { + match division.matches.iter().find(|a| a.tuple == tuple) { + None => match_state = MatchState{ + state: GameState::Scheduled, + start: started as f64 / 1000.0, + }, + Some(event_m) => match_state = event_m.state.clone(), + } + }, + } + }, + 4 => match_state = MatchState{ + state: GameState::Scored, + start: resumed as f64 / 1000.0, + }, + 5 => match_state = MatchState{ + state: GameState::Scored, + start: resumed as f64 / 1000.0, + }, + _ => match_state = MatchState{ + state: GameState::Scheduled, + start: started as f64 / 1000.0, + }, + } match matches.get_mut(&tuple.division) { Some(match_list) => { match_list.push(Match{ - state: None, + state: match_state, info: MatchInfo{ red_teams: [String::from(red_1), String::from(red_2)], blue_teams: [String::from(blue_1), String::from(blue_2)], @@ -231,7 +272,7 @@ impl Event { None => { let mut new_match_list = Vec::new(); new_match_list.push(Match{ - state: None, + state: match_state, info: MatchInfo{ red_teams: [String::from(red_1), String::from(red_2)], blue_teams: [String::from(blue_1), String::from(blue_2)], @@ -293,7 +334,7 @@ struct MatchInfo { #[derive(Serialize, Deserialize, Debug, Clone)] struct Match { - state: Option, + state: MatchState, info: MatchInfo, score: Option, tuple: MatchTuple, @@ -576,7 +617,6 @@ impl TMClient { let data = incoming[0..read].to_vec(); match BackendPacket::from_bytes(data) { Some(packet) => { - log::debug!("Recevied: {:?}", packet); self.last_seq_num = packet.seq_num; match packet.msg_type { // Notice Message @@ -602,6 +642,7 @@ impl TMClient { 3 => { match BackendMessage::from_bytes(packet.data.clone()) { Some(message) => { + log::debug!("Received response: {:#?}", message); match self.responses.send(Box::new(message)) { Ok(_) => log::debug!("Forwarded response to callback engine"), Err(error) => log::error!("Response forward error {:?}", error), @@ -614,6 +655,7 @@ impl TMClient { 2 => { match ConnectMsg::from_bytes(packet.data) { Some(welcome_msg) => { + log::debug!("Received connect message: {:#?}", welcome_msg); if welcome_msg.pw_valid == 0 { let connect_response = ConnectMsg::from_welcome(welcome_msg, &self.password, self.uuid, self.client_name, self.username); let response = BackendPacket::new(packet.header, packet.timestamp, packet.msg_type, self.last_seq_num+1, connect_response.as_bytes()); @@ -881,10 +923,10 @@ fn on_score_set(notice: tm::Notice, event: &mut Event, _connection: &mut TMConne let Some(m) = &mut division.matches.iter_mut().find(|a| a.tuple == tuple) else { return Vec::new() }; m.score = Some(score.clone()); - m.state = Some(MatchState{ + m.state = MatchState{ state: GameState::Scored, start: get_float_time(), - }); + }; let score_serialized = serde_json::to_string_pretty(&m.score).unwrap(); let state_serialized = serde_json::to_string_pretty(&m.state).unwrap(); @@ -997,28 +1039,26 @@ fn on_field_assigned(notice: tm::Notice, event: &mut Event, _connection: &mut TM let Some(field) = get_field(&mut event.field_sets, field_info) else { return Vec::new() }; let Some(m) = get_match(&mut event.divisions, tuple) else { return Vec::new() }; - m.state = Some(MatchState{ + m.state = MatchState{ state: GameState::Scheduled, start: get_float_time(), - }); + }; field.last_known_match = Some(tuple); let mut messages = Vec::new(); - if let Some(state) = &m.state { - let serialized = serde_json::to_string_pretty(&state).unwrap(); - let field_topic = field_info.topic("/state"); - let match_topic = tuple.topic("/state"); - messages.push(MQTTMessage{ - topic: field_topic, - payload: serialized.clone(), - }); + let serialized = serde_json::to_string_pretty(&m.state).unwrap(); + let field_topic = field_info.topic("/state"); + let match_topic = tuple.topic("/state"); + messages.push(MQTTMessage{ + topic: field_topic, + payload: serialized.clone(), + }); - messages.push(MQTTMessage{ - topic: match_topic, - payload: serialized, - }); - } + messages.push(MQTTMessage{ + topic: match_topic, + payload: serialized, + }); if let Some(score) = &m.score { let serialized = serde_json::to_string_pretty(&score).unwrap(); @@ -1040,10 +1080,10 @@ fn on_timer_stop(notice: tm::Notice, event: &mut Event, _connection: &mut TMConn let Some(current_match) = field.last_known_match else { return Vec::new() }; let Some(m) = get_match(&mut event.divisions, current_match) else { return Vec::new() }; - m.state = Some(MatchState{ + m.state = MatchState{ state: GameState::Stopped, start: get_float_time(), - }); + }; let match_state_topic = current_match.topic("/state"); let field_state_topic = field_info.topic("/state"); @@ -1077,10 +1117,10 @@ fn on_timer_start(notice: tm::Notice, event: &mut Event, connection: &mut TMConn let mut messages = Vec::new(); if current_block.r#type == Some(2) { //Auto - m.state = Some(MatchState{ + m.state = MatchState{ state: GameState::Autonomous, start: *current_block_start, - }); + }; let field_state_topic = field_info.topic("/state"); let match_state_topic = tuple.topic("/state"); let payload = serde_json::to_string_pretty(&m.state).unwrap(); @@ -1107,10 +1147,10 @@ fn on_timer_start(notice: tm::Notice, event: &mut Event, connection: &mut TMConn }); connection.state_cancels.insert(field_tuple, cancel_state); } else if current_block.r#type == Some(3) { //Driver - m.state = Some(MatchState{ + m.state = MatchState{ state: GameState::Driver, start: *current_block_start, - }); + }; let field_state_topic = field_info.topic("/state"); let match_state_topic = tuple.topic("/state"); let payload = serde_json::to_string_pretty(&m.state).unwrap(); @@ -1201,15 +1241,18 @@ fn main() { let match_schedule_resp = tm_connection.request(1004, tm::BackendMessageData::default()); event.parse_match_schedule(match_schedule_resp.data.match_schedule.unwrap()); - // For each match, get the score + // For each match, get the score and make the initial publish for (_, division) in &mut event.divisions { for m in &mut division.matches { let serialized = serde_json::to_string_pretty(&m.info).unwrap(); - client.publish(m.tuple.topic(""), QoS::AtLeastOnce, true, serialized).expect("MQTT publish fail"); + client.publish(m.tuple.topic(""), QoS::AtLeastOnce, true, serialized).unwrap(); m.score = get_match_score(&tm_connection, struct_tuple_to_tm(m.tuple)); + + let state_serialized = serde_json::to_string_pretty(&m.state).unwrap(); + client.publish(m.tuple.topic("/state"), QoS::AtLeastOnce, true, state_serialized).unwrap(); if let Some(score) = &m.score { let serialized_score = serde_json::to_string_pretty(score).unwrap(); - client.publish(m.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).expect("MQTT publish fail"); + client.publish(m.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap(); } } } @@ -1225,7 +1268,7 @@ fn main() { let field_resp = tm_connection.request(309, field_req); - match field_resp.data.on_field_match { + match field_resp.data.on_field_match { None => {}, Some(ofm) => match ofm.match_tuple { None => {}, @@ -1235,7 +1278,13 @@ fn main() { None => {}, Some(m) => match field_set.fields.get_mut(&m.info.field.id) { None => {}, - Some(field) => field.last_known_match = Some(tuple), + Some(field) => { + field.last_known_match = Some(tuple); + let serialized_score = serde_json::to_string_pretty(&m.score).unwrap(); + client.publish(field.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap(); + let serialized_state = serde_json::to_string_pretty(&m.state).unwrap(); + client.publish(field.tuple.topic("/state"), QoS::AtLeastOnce, true, serialized_state).unwrap(); + } }, } }, @@ -1274,7 +1323,7 @@ fn main() { match get_match(&mut event.divisions, state_change.tuple) { None => log::warn!("Received state change for unknown match {:#?}", state_change.tuple), Some(m) => { - m.state = Some(state_change.next_state.clone()); + m.state = state_change.next_state.clone(); let field_state_topic = format!("field/{}/{}/state", state_change.field.set, state_change.field.id); let match_state_topic = format!("division/{}/{:?}/{}/score", state_change.tuple.division, state_change.tuple.round, state_change.tuple.match_num); let payload = serde_json::to_vec_pretty(&state_change.next_state).unwrap();