// Send a message representing new page info to the controller. // Typically will be called when the user presses previous or next. // Sends until success, in a new thread. public void SendStorybookPageInfoAction(StorybookPageInfo pageInfo) { Thread thread = new Thread(() => { Dictionary <string, object> publish = new Dictionary <string, object>(); publish.Add("topic", Constants.STORYBOOK_PAGE_INFO_TOPIC); publish.Add("op", "publish"); Dictionary <string, object> data = new Dictionary <string, object>(); data.Add("header", RosbridgeUtilities.GetROSHeader()); data.Add("story_name", pageInfo.storyName); data.Add("page_number", pageInfo.pageNumber); data.Add("sentences", pageInfo.sentences); List <Dictionary <string, object> > tinkerTexts = new List <Dictionary <string, object> > (); foreach (StorybookTinkerText t in pageInfo.tinkerTexts) { Dictionary <string, object> tinkerText = new Dictionary <string, object>(); tinkerText.Add("has_scene_object", t.hasSceneObject); tinkerText.Add("scene_object_id", t.sceneObjectId); tinkerText.Add("word", t.word); tinkerTexts.Add(tinkerText); } data.Add("tinkertexts", tinkerTexts); List <Dictionary <string, object> > sceneObjects = new List <Dictionary <string, object> >(); foreach (StorybookSceneObject o in pageInfo.sceneObjects) { Dictionary <string, object> sceneObject = new Dictionary <string, object>(); sceneObject.Add("id", o.id); sceneObject.Add("label", o.label); sceneObject.Add("in_text", o.inText); sceneObjects.Add(sceneObject); } data.Add("scene_objects", sceneObjects); List <Dictionary <string, object> > prompts = new List <Dictionary <string, object> >(); foreach (JiboPrompt p in pageInfo.prompts) { Dictionary <string, object> prompt = new Dictionary <string, object>(); prompt.Add("question", p.question); prompt.Add("response", p.response); prompt.Add("hint", p.hint); prompts.Add(prompt); } data.Add("prompts", prompts); publish.Add("msg", data); Logger.Log("Sending page info ROS message: " + Json.Serialize(publish)); bool sent = false; while (!sent) { sent = this.rosClient.SendMessage(Json.Serialize(publish)); } Logger.Log("Successfully sent page info ROS message."); }); thread.Start(); }
// Send a message representing storybook state to the controller. // Doesn't need to return Action because it's only used as a timer elapsed handler. private void sendStorybookState(object _, System.Timers.ElapsedEventArgs __) { Dictionary <string, object> publish = new Dictionary <string, object>(); publish.Add("topic", Constants.STORYBOOK_STATE_TOPIC); publish.Add("op", "publish"); // TODO: could devise a better scheme to make sure states are sent in order. // Can also use the sequence numbers provided in the header. Probably overkill. Dictionary <string, object> data = StorybookStateManager.GetRosMessageData(); data.Add("header", RosbridgeUtilities.GetROSHeader()); // Don't allow audio_file to be null, ROS will get upset. if (data["audio_file"] == null) { data["audio_file"] = ""; } publish.Add("msg", data); bool success = this.rosClient.SendMessage(Json.Serialize(publish)); if (!success) { // Logger.Log("Failed to send StorybookState message: " + Json.Serialize((publish))); } }
// Send a message representing storybook state to the controller, in a new thread. // Doesn't need to return Action because it's only used as a timer elapsed handler. private void sendStorybookState(object _, System.Timers.ElapsedEventArgs __) { Dictionary <string, object> publish = new Dictionary <string, object>(); publish.Add("topic", Constants.STORYBOOK_STATE_TOPIC); publish.Add("op", "publish"); // Note that this is protected by a lock, so although ROS messages could // send out of order, the information within them will be consistent. // And if the sending rate isn't too high, the likelihood of out of order messages // is low, and inconsequential for the controller anyway. // TODO: should devise a better scheme to make sure states are sent in order. // Can also use the sequence numbers provided in the header. // Or use a lock in this class so that only one state message can be sent at a time. Dictionary <string, object> data = StorybookStateManager.GetRosMessageData(); data.Add("header", RosbridgeUtilities.GetROSHeader()); // Don't allow audio_file to be null, ROS will get upset. if (data["audio_file"] == null) { data["audio_file"] = ""; } publish.Add("msg", data); bool success = this.rosClient.SendMessage(Json.Serialize(publish)); if (!success) { // Logger.Log("Failed to send StorybookState message: " + Json.Serialize((publish))); } }
// Send a message representing storybook state to the controller, in a new thread. // Doesn't need to return Action because it's only used as a timer elapsed handler. private void sendStorybookState(object sender, System.Timers.ElapsedEventArgs e) { Thread t = new Thread(() => { Dictionary <string, object> publish = new Dictionary <string, object>(); publish.Add("topic", Constants.STORYBOOK_STATE_TOPIC); publish.Add("op", "publish"); Dictionary <string, object> data = new Dictionary <string, object>(); // Note that this is protected by a lock, so although ROS messages could // send out of order, the information within them will be consistent. // And if the sending rate isn't too high, the likelihood of out of order messages // is low, and inconsequential for the controller anyway. // TODO: should devise a better scheme to make sure states are sent in order. // Can also use the sequence numbers provided in the header. // Or use a lock in this class so that only one state message can be sent at a time. StorybookState currentStorybookState = this.storybookStateManager.getCurrentState(); data.Add("header", RosbridgeUtilities.GetROSHeader()); data.Add("audio_playing", currentStorybookState.audioPlaying); // ROS freaks out if it gets a null value, so just fill it in with an empty string // if there is no provided audio file. string audioFile = currentStorybookState.audioFile; if (audioFile == null) { audioFile = ""; } data.Add("audio_file", audioFile); data.Add("storybook_mode", (int)currentStorybookState.storybookMode); data.Add("current_story", currentStorybookState.currentStory); data.Add("num_pages", currentStorybookState.numPages); data.Add("evaluating_stanza_index", currentStorybookState.evaluatingStanzaIndex); publish.Add("msg", data); bool success = this.rosClient.SendMessage(Json.Serialize(publish)); if (!success) { Logger.Log("Failed to send StorybookState message: " + Json.Serialize((publish))); } }); t.Start(); }
// Send StorybookEvent message until received, in a new thread. private void sendEventMessageToController(StorybookEventType messageType, string message) { Thread t = new Thread(() => { Dictionary <string, object> publish = new Dictionary <string, object>(); publish.Add("topic", Constants.STORYBOOK_EVENT_TOPIC); publish.Add("op", "publish"); // Build data to send. Dictionary <string, object> data = new Dictionary <string, object>(); data.Add("event_type", (int)messageType); data.Add("header", RosbridgeUtilities.GetROSHeader()); data.Add("message", message); publish.Add("msg", data); Logger.Log("Sending event ROS message: " + Json.Serialize(publish)); bool sent = false; while (!sent) { sent = this.rosClient.SendMessage(Json.Serialize(publish)); } }); t.Start(); }