static void MyPrintEventCallback(sml.smlPrintEventId eventID, IntPtr callbackData, IntPtr agentPtr, String message) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Agent agent = (sml.Agent)((GCHandle)agentPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; System.Console.Out.WriteLine(eventID + " agent " + agent.GetAgentName() + " message " + message + " with user data " + userData); }
static void MyOutputNotificationCallback(IntPtr callbackData, IntPtr agentPtr) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Agent agent = (sml.Agent)((GCHandle)agentPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; System.Console.Out.WriteLine("Agent " + agent.GetAgentName() + " has just received some output"); for (int i = 0; i < agent.GetNumberOutputLinkChanges(); i++) { sml.WMElement wme = agent.GetOutputLinkChange(i); System.Console.Out.WriteLine("Output wme was " + wme.GetIdentifier().GetIdentifierSymbol() + " ^" + wme.GetAttribute() + " " + wme.GetValueAsString()); } }
static void MyAgentEventCallback(sml.smlAgentEventId eventID, IntPtr callbackData, IntPtr kernelPtr, String agentName) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Kernel kernel = (sml.Kernel)((GCHandle)kernelPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; // This callback returns the name of the agent as a string, to avoid having SWIG have to lookup the C# agent object // and pass that back. We do something similar in Java for the same reasons. sml.Agent agent = kernel.GetAgent(agentName); if (agent == null) { throw new Exception("Error looking up agent in callback"); } System.Console.Out.WriteLine(eventID + " agent " + agentName + " with user data " + userData); }
static void MyOutputEventCallback(IntPtr callbackData, IntPtr agentPtr, String commandName, IntPtr outputWME) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Agent agent = (sml.Agent)((GCHandle)agentPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; // Retrieve the wme. We don't own this object, so to keep it we'd need to copy it (or its contents). // This way when C# deallocated the object the underlying C++ object isn't deleted either (which is correct as the corresponding C++ code // doesn't pass ownership in the equivalent callback either). sml.WMElement wme = (sml.WMElement)((GCHandle)outputWME).Target; String id = wme.GetIdentifier().GetIdentifierSymbol(); String att = wme.GetAttribute(); String val = wme.GetValueAsString(); System.Console.Out.WriteLine("Output received under ^move attribute for agent " + agent.GetAgentName() + " output wme " + id + " ^" + att + " " + val); }
static void MyXMLEventCallback(sml.smlXMLEventId eventID, IntPtr callbackData, IntPtr agentPtr, IntPtr pXML) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Agent agent = (sml.Agent)((GCHandle)agentPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; // Retrieve the xml object. We don't own this object, so to keep it we'd need to copy it (or its contents). // This way when C# deallocated the object the underlying C++ object isn't deleted either (which is correct as the corresponding C++ code // doesn't pass ownership in the equivalent callback either). sml.ClientXML xml = (sml.ClientXML)((GCHandle)pXML).Target; // Convert the XML to string form so we can look at it. String xmlString = xml.GenerateXMLString(true); String name = agent.GetAgentName(); System.Console.Out.WriteLine(eventID + " agent " + name + " xml " + xmlString); }
static String MyTestRhsFunction(sml.smlRhsEventId eventID, IntPtr callbackData, IntPtr kernelPtr, String agentName, String functionName, String argument) { // Retrieve the original object reference from the GCHandle which is used to pass the value safely to and from C++ (unsafe/unmanaged) code. sml.Kernel kernel = (sml.Kernel)((GCHandle)kernelPtr).Target; // Retrieve arbitrary data from callback data object (note data here can be null, but the wrapper object callbackData won't be so this call is safe) // This field's usage is up to the user and passed in during registation call and passed back here. Can be used to provide context. Object userData = (Object)((GCHandle)callbackData).Target; // This callback returns the name of the agent as a string, to avoid having SWIG have to lookup the C# agent object // and pass that back. We do something similar in Java for the same reasons. sml.Agent agent = kernel.GetAgent(agentName); if (agent == null) { throw new Exception("Error looking up agent in callback"); } System.Console.Out.WriteLine(eventID + " agent " + agentName + " function " + functionName + " arg " + argument); // This is the result of the RHS function and can be placed into working memory as the result of the call // (whether this happens or not depends on how the RHS function is used in the production rule). return("result"); }
bool Test() { // // TODO: Add code to start application here // sml.Kernel kernel = sml.Kernel.CreateKernelInNewThread("SoarKernelSML"); // Make sure the kernel was ok if (kernel.HadError()) { throw new Exception("Error initializing kernel: " + kernel.GetLastErrorDescription()); } sml.Agent agent = kernel.CreateAgent("First"); // We test the kernel for an error after creating an agent as the agent // object may not be properly constructed if the create call failed so // we store errors in the kernel in this case. Once this create is done we can work directly with the agent. if (kernel.HadError()) { throw new Exception("Error creating agent: " + kernel.GetLastErrorDescription()); } bool ok = agent.LoadProductions("..\\Tests\\testcsharpsml.soar"); if (!ok) { System.Console.Out.WriteLine("Load failed"); return(false); } Agent pAgent = agent; // So it's easier copying existing C++ code here Kernel pKernel = kernel; Identifier pInputLink = agent.GetInputLink(); if (pInputLink == null) { throw new Exception("Error getting the input link"); } // Some random adds Identifier pID = pAgent.CreateIdWME(pInputLink, "plane"); StringElement pWME1 = pAgent.CreateStringWME(pID, "type", "Boeing747"); IntElement pWME2 = pAgent.CreateIntWME(pID, "speed", 200); // Then add some tic tac toe stuff which should trigger output Identifier pSquare = pAgent.CreateIdWME(pInputLink, "square"); StringElement pEmpty = pAgent.CreateStringWME(pSquare, "content", "RANDOM"); IntElement pRow = pAgent.CreateIntWME(pSquare, "row", 1); IntElement pCol = pAgent.CreateIntWME(pSquare, "col", 2); ok = pAgent.Commit(); // Quick test of init-soar pAgent.InitSoar(); // Update the square's value to be empty. This ensures that the update // call is doing something. Otherwise, when we run we won't get a match. pAgent.Update(pEmpty, "EMPTY"); ok = pAgent.Commit(); String myTestData = "my data"; sml.Agent.RunEventCallback runCall = new sml.Agent.RunEventCallback(MyRunEventCallback); sml.Agent.ProductionEventCallback prodCall = new sml.Agent.ProductionEventCallback(MyProductionEventCallback); sml.Agent.PrintEventCallback printCall = new sml.Agent.PrintEventCallback(MyPrintEventCallback); sml.Agent.OutputEventCallback outputCall = new sml.Agent.OutputEventCallback(MyOutputEventCallback); sml.Agent.XMLEventCallback xmlCall = new sml.Agent.XMLEventCallback(MyXMLEventCallback); sml.Agent.OutputNotificationCallback noteCall = new sml.Agent.OutputNotificationCallback(MyOutputNotificationCallback); sml.Kernel.AgentEventCallback agentCall = new sml.Kernel.AgentEventCallback(MyAgentEventCallback); sml.Kernel.SystemEventCallback systemCall = new sml.Kernel.SystemEventCallback(MySystemEventCallback); sml.Kernel.UpdateEventCallback updateCall = new sml.Kernel.UpdateEventCallback(MyUpdateEventCallback); sml.Kernel.StringEventCallback strCall = new sml.Kernel.StringEventCallback(MyStringEventCallback); sml.Kernel.RhsFunction rhsCall = new sml.Kernel.RhsFunction(MyTestRhsFunction); sml.Kernel.ClientMessageCallback clientCall = new sml.Kernel.ClientMessageCallback(MyTestClientMessageCallback); int runCallbackID = agent.RegisterForRunEvent(sml.smlRunEventId.smlEVENT_AFTER_DECISION_CYCLE, runCall, myTestData); int prodCallbackID = agent.RegisterForProductionEvent(sml.smlProductionEventId.smlEVENT_AFTER_PRODUCTION_FIRED, prodCall, myTestData); int printCallbackID = agent.RegisterForPrintEvent(sml.smlPrintEventId.smlEVENT_PRINT, printCall, myTestData); int outputCallbackID = agent.AddOutputHandler("move", outputCall, myTestData); int noteCallbackID = agent.RegisterForOutputNotification(noteCall, myTestData); int xmlCallbackID = agent.RegisterForXMLEvent(sml.smlXMLEventId.smlEVENT_XML_TRACE_OUTPUT, xmlCall, myTestData); int agentCallbackID = kernel.RegisterForAgentEvent(sml.smlAgentEventId.smlEVENT_BEFORE_AGENT_REINITIALIZED, agentCall, myTestData); int systemCallbackID = kernel.RegisterForSystemEvent(sml.smlSystemEventId.smlEVENT_SYSTEM_START, systemCall, myTestData); int updateCallbackID = kernel.RegisterForUpdateEvent(sml.smlUpdateEventId.smlEVENT_AFTER_ALL_OUTPUT_PHASES, updateCall, myTestData); int stringCallbackID = kernel.RegisterForStringEvent(sml.smlStringEventId.smlEVENT_EDIT_PRODUCTION, strCall, myTestData); int rhsCallbackID = kernel.AddRhsFunction("test-rhs", rhsCall, myTestData); int clientCallbackID = kernel.RegisterForClientMessageEvent("test-client", clientCall, myTestData); // Running the agent will trigger most of the events we're listening for so // we can check that they're working correctly. agent.RunSelf(3); //kernel.RunAllAgents(3) ; // Trigger an agent event agent.InitSoar(); ok = agent.UnregisterForRunEvent(runCallbackID); ok = ok && agent.UnregisterForProductionEvent(prodCallbackID); ok = ok && agent.UnregisterForPrintEvent(printCallbackID); ok = ok && agent.RemoveOutputHandler(outputCallbackID); ok = ok && agent.UnregisterForOutputNotification(noteCallbackID); ok = ok && agent.UnregisterForXMLEvent(xmlCallbackID); ok = ok && kernel.UnregisterForAgentEvent(agentCallbackID); ok = ok && kernel.UnregisterForSystemEvent(systemCallbackID); ok = ok && kernel.UnregisterForUpdateEvent(updateCallbackID); ok = ok && kernel.UnregisterForStringEvent(stringCallbackID); ok = ok && kernel.RemoveRhsFunction(rhsCallbackID); ok = ok && kernel.UnregisterForClientMessageEvent(clientCallbackID); if (!ok) { System.Console.Out.WriteLine("Failed to unregister an event"); return(false); } // Close down the kernel (or for a remote connection disconnect from the kernel w/o closing it down). kernel.Shutdown(); return(ok); }
public void InitializeSoar(SoarMSRState initialState) { if (_kernel != null) { throw new Exception("Soar: Already initialized"); } _kernel = sml.Kernel.CreateKernelInNewThread("SoarKernelSML"); if (_kernel.HadError()) { _kernel = null; throw new Exception("Soar: Error initializing kernel: " + _kernel.GetLastErrorDescription()); } _running = false; _stop = false; _agent = _kernel.CreateAgent(initialState.AgentName); // We test the kernel for an error after creating an agent as the agent // object may not be properly constructed if the create call failed so // we store errors in the kernel in this case. Once this create is done we can work directly with the agent. if (_kernel.HadError()) { throw new Exception("Soar: Error creating agent: " + _kernel.GetLastErrorDescription()); } _kernel.SetAutoCommit(false); _agent.SetBlinkIfNoChange(false); bool result = _agent.LoadProductions(initialState.Productions); if (!result) { throw new Exception("Soar: Error loading productions " + initialState.Productions + " (current working directory: " + _agent.ExecuteCommandLine("pwd") + ")"); } // reset state Bumper = new BumperState(); Override = new OverrideState(); Obstacle = false; // Prepare communication channel Identifier inputLink = _agent.GetInputLink(); if (inputLink == null) { throw new Exception("Soar: Error getting the input link"); } Identifier overrideWME = _agent.CreateIdWME(inputLink, "override"); _overrideActiveWME = _agent.CreateStringWME(overrideWME, "active", "false"); Identifier drivePowerWME = _agent.CreateIdWME(overrideWME, "drive-power"); _overrideLeftWME = _agent.CreateFloatWME(drivePowerWME, "left", 0); _overrideRightWME = _agent.CreateFloatWME(drivePowerWME, "right", 0); _overrideStopWME = _agent.CreateStringWME(drivePowerWME, "stop", "false"); Identifier configWME = _agent.CreateIdWME(inputLink, "config"); Identifier powerWME = _agent.CreateIdWME(configWME, "power"); _agent.CreateFloatWME(powerWME, "drive", initialState.DrivePower); _agent.CreateFloatWME(powerWME, "reverse", initialState.ReversePower); Identifier delayWME = _agent.CreateIdWME(configWME, "delay"); _agent.CreateFloatWME(delayWME, "stop", initialState.StopTimeout); _agent.CreateFloatWME(delayWME, "reverse", initialState.BackUpTimeout); _agent.CreateFloatWME(delayWME, "turn", initialState.TurnTimeout); _agent.CreateFloatWME(delayWME, "variance", initialState.TimeoutVariance); Identifier sensorsWME = _agent.CreateIdWME(inputLink, "sensors"); Identifier bumperWME = _agent.CreateIdWME(sensorsWME, "bumper"); Identifier frontWME = _agent.CreateIdWME(bumperWME, "front"); _frontBumperPressedWME = _agent.CreateStringWME(frontWME, "pressed", "false"); _frontBumperWasPressedWME = _agent.CreateStringWME(frontWME, "was-pressed", "false"); Identifier rearWME = _agent.CreateIdWME(bumperWME, "rear"); _rearBumperPressedWME = _agent.CreateStringWME(rearWME, "pressed", "false"); _rearBumperWasPressedWME = _agent.CreateStringWME(rearWME, "was-pressed", "false"); Identifier sickLRFWME = _agent.CreateIdWME(sensorsWME, "sicklrf"); _obstacleWME = _agent.CreateStringWME(sickLRFWME, "obstacle", "false"); // Current time WME _timeWME = _agent.CreateFloatWME(inputLink, "time", 0); // Random number WME and supporting state _randomWME = _agent.CreateFloatWME(inputLink, "random", 0); if (initialState.HasRandomSeed) { _random = new Random(initialState.RandomSeed); Trace.WriteLine("Seeding Soar's random number generator."); _agent.ExecuteCommandLine("srand " + initialState.RandomSeed); if (_agent.HadError()) { throw new Exception("Failed to seed Soar's random number generator"); } } else { _random = new Random(); } // commit input link structure _agent.Commit(); _updateCall = new sml.Kernel.UpdateEventCallback(UpdateEventCallback); _kernel.RegisterForUpdateEvent(sml.smlUpdateEventId.smlEVENT_AFTER_ALL_OUTPUT_PHASES, _updateCall, null); // spawn debugger if (initialState.SpawnDebugger) { SpawnDebugger(); } _simulationStart = DateTime.Now; OnLog("Soar initialized."); }
public void InitializeSoar(SoarMSRState initialState) { if (_kernel != null) { throw new Exception("Soar: Already initialized"); } _kernel = sml.Kernel.CreateKernelInNewThread("SoarKernelSML"); if (_kernel.HadError()) { _kernel = null; throw new Exception("Soar: Error initializing kernel: " + _kernel.GetLastErrorDescription()); } _running = false; _stop = false; _agent = _kernel.CreateAgent(initialState.AgentName); // We test the kernel for an error after creating an agent as the agent // object may not be properly constructed if the create call failed so // we store errors in the kernel in this case. Once this create is done we can work directly with the agent. if (_kernel.HadError()) throw new Exception("Soar: Error creating agent: " + _kernel.GetLastErrorDescription()); _kernel.SetAutoCommit(false); _agent.SetBlinkIfNoChange(false); bool result = _agent.LoadProductions(initialState.Productions); if (!result) { throw new Exception("Soar: Error loading productions " + initialState.Productions + " (current working directory: " + _agent.ExecuteCommandLine("pwd") + ")"); } // reset state Bumper = new BumperState(); Override = new OverrideState(); Obstacle = false; // Prepare communication channel Identifier inputLink = _agent.GetInputLink(); if (inputLink == null) throw new Exception("Soar: Error getting the input link"); Identifier overrideWME = _agent.CreateIdWME(inputLink, "override"); _overrideActiveWME = _agent.CreateStringWME(overrideWME, "active", "false"); Identifier drivePowerWME = _agent.CreateIdWME(overrideWME, "drive-power"); _overrideLeftWME = _agent.CreateFloatWME(drivePowerWME, "left", 0); _overrideRightWME = _agent.CreateFloatWME(drivePowerWME, "right", 0); _overrideStopWME = _agent.CreateStringWME(drivePowerWME, "stop", "false"); Identifier configWME = _agent.CreateIdWME(inputLink, "config"); Identifier powerWME = _agent.CreateIdWME(configWME, "power"); _agent.CreateFloatWME(powerWME, "drive", initialState.DrivePower); _agent.CreateFloatWME(powerWME, "reverse", initialState.ReversePower); Identifier delayWME = _agent.CreateIdWME(configWME, "delay"); _agent.CreateFloatWME(delayWME, "stop", initialState.StopTimeout); _agent.CreateFloatWME(delayWME, "reverse", initialState.BackUpTimeout); _agent.CreateFloatWME(delayWME, "turn", initialState.TurnTimeout); _agent.CreateFloatWME(delayWME, "variance", initialState.TimeoutVariance); Identifier sensorsWME = _agent.CreateIdWME(inputLink, "sensors"); Identifier bumperWME = _agent.CreateIdWME(sensorsWME, "bumper"); Identifier frontWME = _agent.CreateIdWME(bumperWME, "front"); _frontBumperPressedWME = _agent.CreateStringWME(frontWME, "pressed", "false"); _frontBumperWasPressedWME = _agent.CreateStringWME(frontWME, "was-pressed", "false"); Identifier rearWME = _agent.CreateIdWME(bumperWME, "rear"); _rearBumperPressedWME = _agent.CreateStringWME(rearWME, "pressed", "false"); _rearBumperWasPressedWME = _agent.CreateStringWME(rearWME, "was-pressed", "false"); Identifier sickLRFWME = _agent.CreateIdWME(sensorsWME, "sicklrf"); _obstacleWME = _agent.CreateStringWME(sickLRFWME, "obstacle", "false"); // Current time WME _timeWME = _agent.CreateFloatWME(inputLink, "time", 0); // Random number WME and supporting state _randomWME = _agent.CreateFloatWME(inputLink, "random", 0); if (initialState.HasRandomSeed) { _random = new Random(initialState.RandomSeed); Trace.WriteLine("Seeding Soar's random number generator."); _agent.ExecuteCommandLine("srand " + initialState.RandomSeed); if (_agent.HadError()) { throw new Exception("Failed to seed Soar's random number generator"); } } else { _random = new Random(); } // commit input link structure _agent.Commit(); _updateCall = new sml.Kernel.UpdateEventCallback(UpdateEventCallback); _kernel.RegisterForUpdateEvent(sml.smlUpdateEventId.smlEVENT_AFTER_ALL_OUTPUT_PHASES, _updateCall, null); // spawn debugger if (initialState.SpawnDebugger) { SpawnDebugger(); } _simulationStart = DateTime.Now; OnLog("Soar initialized."); }