Added initial publish to state topics

master
noah metz 2024-01-22 11:23:11 -07:00
parent d8ad2c7bd2
commit c98d2bd531
1 changed files with 82 additions and 33 deletions

@ -211,14 +211,55 @@ impl Event {
for m in schedule.matches.iter() { for m in schedule.matches.iter() {
let tuple = tm_tuple_to_struct(m.match_tuple.clone().unwrap()); let tuple = tm_tuple_to_struct(m.match_tuple.clone().unwrap());
let Some(field) = get_field_tuple(&m.assigned_field) else {continue;}; 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_1 = m.alliances[0].teams[0].number();
let red_2 = m.alliances[0].teams[1].number(); let red_2 = m.alliances[0].teams[1].number();
let blue_1 = m.alliances[1].teams[0].number(); let blue_1 = m.alliances[1].teams[0].number();
let blue_2 = m.alliances[1].teams[1].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) { match matches.get_mut(&tuple.division) {
Some(match_list) => { Some(match_list) => {
match_list.push(Match{ match_list.push(Match{
state: None, state: match_state,
info: MatchInfo{ info: MatchInfo{
red_teams: [String::from(red_1), String::from(red_2)], red_teams: [String::from(red_1), String::from(red_2)],
blue_teams: [String::from(blue_1), String::from(blue_2)], blue_teams: [String::from(blue_1), String::from(blue_2)],
@ -231,7 +272,7 @@ impl Event {
None => { None => {
let mut new_match_list = Vec::new(); let mut new_match_list = Vec::new();
new_match_list.push(Match{ new_match_list.push(Match{
state: None, state: match_state,
info: MatchInfo{ info: MatchInfo{
red_teams: [String::from(red_1), String::from(red_2)], red_teams: [String::from(red_1), String::from(red_2)],
blue_teams: [String::from(blue_1), String::from(blue_2)], blue_teams: [String::from(blue_1), String::from(blue_2)],
@ -293,7 +334,7 @@ struct MatchInfo {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
struct Match { struct Match {
state: Option<MatchState>, state: MatchState,
info: MatchInfo, info: MatchInfo,
score: Option<MatchScore>, score: Option<MatchScore>,
tuple: MatchTuple, tuple: MatchTuple,
@ -576,7 +617,6 @@ impl TMClient {
let data = incoming[0..read].to_vec(); let data = incoming[0..read].to_vec();
match BackendPacket::from_bytes(data) { match BackendPacket::from_bytes(data) {
Some(packet) => { Some(packet) => {
log::debug!("Recevied: {:?}", packet);
self.last_seq_num = packet.seq_num; self.last_seq_num = packet.seq_num;
match packet.msg_type { match packet.msg_type {
// Notice Message // Notice Message
@ -602,6 +642,7 @@ impl TMClient {
3 => { 3 => {
match BackendMessage::from_bytes(packet.data.clone()) { match BackendMessage::from_bytes(packet.data.clone()) {
Some(message) => { Some(message) => {
log::debug!("Received response: {:#?}", message);
match self.responses.send(Box::new(message)) { match self.responses.send(Box::new(message)) {
Ok(_) => log::debug!("Forwarded response to callback engine"), Ok(_) => log::debug!("Forwarded response to callback engine"),
Err(error) => log::error!("Response forward error {:?}", error), Err(error) => log::error!("Response forward error {:?}", error),
@ -614,6 +655,7 @@ impl TMClient {
2 => { 2 => {
match ConnectMsg::from_bytes(packet.data) { match ConnectMsg::from_bytes(packet.data) {
Some(welcome_msg) => { Some(welcome_msg) => {
log::debug!("Received connect message: {:#?}", welcome_msg);
if welcome_msg.pw_valid == 0 { if welcome_msg.pw_valid == 0 {
let connect_response = ConnectMsg::from_welcome(welcome_msg, &self.password, self.uuid, self.client_name, self.username); 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()); 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() }; let Some(m) = &mut division.matches.iter_mut().find(|a| a.tuple == tuple) else { return Vec::new() };
m.score = Some(score.clone()); m.score = Some(score.clone());
m.state = Some(MatchState{ m.state = MatchState{
state: GameState::Scored, state: GameState::Scored,
start: get_float_time(), start: get_float_time(),
}); };
let score_serialized = serde_json::to_string_pretty(&m.score).unwrap(); let score_serialized = serde_json::to_string_pretty(&m.score).unwrap();
let state_serialized = serde_json::to_string_pretty(&m.state).unwrap(); let state_serialized = serde_json::to_string_pretty(&m.state).unwrap();
@ -997,16 +1039,15 @@ 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(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() }; let Some(m) = get_match(&mut event.divisions, tuple) else { return Vec::new() };
m.state = Some(MatchState{ m.state = MatchState{
state: GameState::Scheduled, state: GameState::Scheduled,
start: get_float_time(), start: get_float_time(),
}); };
field.last_known_match = Some(tuple); field.last_known_match = Some(tuple);
let mut messages = Vec::new(); let mut messages = Vec::new();
if let Some(state) = &m.state { let serialized = serde_json::to_string_pretty(&m.state).unwrap();
let serialized = serde_json::to_string_pretty(&state).unwrap();
let field_topic = field_info.topic("/state"); let field_topic = field_info.topic("/state");
let match_topic = tuple.topic("/state"); let match_topic = tuple.topic("/state");
messages.push(MQTTMessage{ messages.push(MQTTMessage{
@ -1018,7 +1059,6 @@ fn on_field_assigned(notice: tm::Notice, event: &mut Event, _connection: &mut TM
topic: match_topic, topic: match_topic,
payload: serialized, payload: serialized,
}); });
}
if let Some(score) = &m.score { if let Some(score) = &m.score {
let serialized = serde_json::to_string_pretty(&score).unwrap(); 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(current_match) = field.last_known_match else { return Vec::new() };
let Some(m) = get_match(&mut event.divisions, current_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, state: GameState::Stopped,
start: get_float_time(), start: get_float_time(),
}); };
let match_state_topic = current_match.topic("/state"); let match_state_topic = current_match.topic("/state");
let field_state_topic = field_info.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(); let mut messages = Vec::new();
if current_block.r#type == Some(2) { //Auto if current_block.r#type == Some(2) { //Auto
m.state = Some(MatchState{ m.state = MatchState{
state: GameState::Autonomous, state: GameState::Autonomous,
start: *current_block_start, start: *current_block_start,
}); };
let field_state_topic = field_info.topic("/state"); let field_state_topic = field_info.topic("/state");
let match_state_topic = tuple.topic("/state"); let match_state_topic = tuple.topic("/state");
let payload = serde_json::to_string_pretty(&m.state).unwrap(); 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); connection.state_cancels.insert(field_tuple, cancel_state);
} else if current_block.r#type == Some(3) { //Driver } else if current_block.r#type == Some(3) { //Driver
m.state = Some(MatchState{ m.state = MatchState{
state: GameState::Driver, state: GameState::Driver,
start: *current_block_start, start: *current_block_start,
}); };
let field_state_topic = field_info.topic("/state"); let field_state_topic = field_info.topic("/state");
let match_state_topic = tuple.topic("/state"); let match_state_topic = tuple.topic("/state");
let payload = serde_json::to_string_pretty(&m.state).unwrap(); 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()); let match_schedule_resp = tm_connection.request(1004, tm::BackendMessageData::default());
event.parse_match_schedule(match_schedule_resp.data.match_schedule.unwrap()); 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 (_, division) in &mut event.divisions {
for m in &mut division.matches { for m in &mut division.matches {
let serialized = serde_json::to_string_pretty(&m.info).unwrap(); 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)); 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 { if let Some(score) = &m.score {
let serialized_score = serde_json::to_string_pretty(score).unwrap(); 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();
} }
} }
} }
@ -1235,7 +1278,13 @@ fn main() {
None => {}, None => {},
Some(m) => match field_set.fields.get_mut(&m.info.field.id) { Some(m) => match field_set.fields.get_mut(&m.info.field.id) {
None => {}, 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) { match get_match(&mut event.divisions, state_change.tuple) {
None => log::warn!("Received state change for unknown match {:#?}", state_change.tuple), None => log::warn!("Received state change for unknown match {:#?}", state_change.tuple),
Some(m) => { 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 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 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(); let payload = serde_json::to_vec_pretty(&state_change.next_state).unwrap();