### Custom MID Implementation Example Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt This example demonstrates how to override an existing MID (e.g., Mid0081) to add custom functionality and how to create a completely new MID (e.g., NewMid0083) that is not part of the standard Open Protocol library. It also shows how to register these custom MIDs with the interpreter. ```APIDOC ## Custom MID Implementation You can create custom MID implementations for controllers that have non-standard MIDs or to extend existing MIDs with additional functionality. ### Overriding an Existing MID (CustomMid0081) This class extends `Mid0081` to add a `FormattedDate` property that provides a custom string representation of the time and allows setting the time from this formatted string. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Time; using System; using System.Collections.Generic; public class CustomMid0081 : Mid0081 { public string FormattedDate { get => Time.ToString("dd/MM/yyyy HH:mm:ss"); set => Time = DateTime.Parse(value); } public CustomMid0081() { } public override string Pack() { // Add custom logic before packing return base.Pack(); } } ``` ### Creating a New MID (NewMid0083) This class defines a completely new MID, `NewMid0083`, which includes `Time` and `TimeZone` fields. It inherits from `Mid` and implements `ITime`. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Time; using System; using System.Collections.Generic; public class NewMid0083 : Mid, ITime { private const int LAST_REVISION = 1; public const int MID = 83; public DateTime Time { get => GetField(1, (int)DataFields.TIME).GetValue(OpenProtocolConvert.ToDateTime); set => GetField(1, (int)DataFields.TIME).SetValue(OpenProtocolConvert.ToString, value); } public string TimeZone { get => GetField(1, (int)DataFields.TIMEZONE).Value; set => GetField(1, (int)DataFields.TIMEZONE).SetValue(value); } public NewMid0083() : base(MID, LAST_REVISION) { } protected override Dictionary> RegisterDatafields() { return new Dictionary>() { { 1, new List() { DataField.Timestamp(DataFields.TIME, 20), DataField.String(DataFields.TIMEZONE, 41, 2) } } }; } protected enum DataFields { TIME, TIMEZONE } } ``` ### Registering Custom MIDs This section shows how to register the custom MIDs with the `MidInterpreter`. ```csharp // Register custom MIDs with the interpreter var interpreter = new MidInterpreter() .UseAllMessages() // Override existing MID 81 with custom implementation .UseTimeMessages(new Dictionary() { { 81, typeof(CustomMid0081) } }) // Add completely new custom MID .UseCustomMessage(new Dictionary() { { 83, typeof(NewMid0083) } }); ``` ### Using a Custom MID This demonstrates how to create an instance of the custom MID and pack it. ```csharp // Use the custom MID var customTime = new NewMid0083 { Time = DateTime.Now, TimeZone = "US" }; string package = customTime.Pack(); Console.WriteLine($"Custom MID: {package}"); ``` ``` -------------------------------- ### Initiating Communication with Mid0001 Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Shows how to create and pack a Mid0001 communication start request and how to handle the resulting response from the controller, identifying whether the connection was accepted or rejected. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; var interpreter = new MidInterpreter().UseCommunicationMessages(); var startRequest = new Mid0001(revision: 1); string package = startRequest.Pack(); string mockResponse = "00570002001 01020201Controller Name Here "; var responseMid = interpreter.Parse(mockResponse); if (responseMid is Mid0002 accepted) { Console.WriteLine($"Connected to: {accepted.ControllerName}"); } else if (responseMid is Mid0004 error) { Console.WriteLine($"Connection failed: {error.ErrorCode}"); } ``` -------------------------------- ### POST /mid/0001 - Communication Start Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Initiates a communication session with the controller. This is the mandatory first step in the Open Protocol handshake. ```APIDOC ## POST /mid/0001 ### Description Initiates communication with the controller. The controller will respond with Mid0002 (Communication Accepted) or Mid0004 (Communication Error). ### Method POST ### Endpoint /mid/0001 ### Parameters #### Request Body - **revision** (int) - Required - The protocol revision number (e.g., 1, 7). - **optionalKeepAlive** (bool) - Optional - Enables keep-alive functionality (available in higher revisions). ### Request Example { "revision": 1 } ### Response #### Success Response (200) - **controllerName** (string) - Name of the connected controller. - **cellId** (int) - ID of the cell. - **channelId** (int) - ID of the communication channel. #### Response Example { "mid": "0002", "controllerName": "Controller Name", "cellId": 1, "channelId": 1 } ``` -------------------------------- ### Configure MidInterpreter with Message Types (C#) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Illustrates how to configure the MidInterpreter with specific Open Protocol MID parsers using the UseAllMessages extension method. It covers registering all available MIDs, filtering by interpreter role (Integrator, Controller), or registering a custom subset of MIDs for performance optimization. The example also shows how parsing fails for unregistered MIDs. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; using OpenProtocolInterpreter.Tightening; using OpenProtocolInterpreter.Alarm; using OpenProtocolInterpreter.Job; // Register all available MIDs var fullInterpreter = new MidInterpreter().UseAllMessages(); // Register only MIDs needed by an integrator var integratorInterpreter = new MidInterpreter() .UseAllMessages(InterpreterMode.Integrator); // Register only MIDs needed by a controller var controllerInterpreter = new MidInterpreter() .UseAllMessages(InterpreterMode.Controller); // Register only specific MID types for better performance var customInterpreter = new MidInterpreter() .UseAllMessages(new Type[] { typeof(Mid0001), // Communication start typeof(Mid0002), // Communication start acknowledge typeof(Mid0004), // Command error typeof(Mid0005), // Command accepted typeof(Mid0060), // Tightening subscribe typeof(Mid0061), // Last tightening result typeof(Mid0071) // Alarm }); // Parse will only work for registered MIDs string package = "00260004001 001802"; var mid = customInterpreter.Parse(package); // Works: Mid0004 is registered // This would throw NotImplementedException // customInterpreter.Parse("00200030001 "); // Mid0030 (Job ID upload) is not registered ``` -------------------------------- ### Parse and Access Mid0002 Communication Start Acknowledge (C#) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Demonstrates parsing a Mid0002 message, which acknowledges a communication start request. It shows how to access various controller details like Cell ID, Channel ID, controller name, software versions, and capabilities based on message revision. Requires the OpenProtocolInterpreter library. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; var interpreter = new MidInterpreter().UseCommunicationMessages(); // Parse a Mid0002 response (revision 6 with full details) string package = @"02220002006 01010201PowerFocus 6000 ABC1.0.0 1.2.3 1.0.0 RBU Type Here SN12345678001001110000000001Station Name Here A"; var mid = interpreter.Parse(package); // Access basic controller information (Rev 1) Console.WriteLine($"Controller: {mid.ControllerName}"); Console.WriteLine($"Cell ID: {mid.CellId}"); Console.WriteLine($"Channel ID: {mid.ChannelId}"); // Rev 2: Supplier code Console.WriteLine($"Supplier: {mid.SupplierCode}"); // Rev 3: Software versions Console.WriteLine($"Open Protocol Version: {mid.OpenProtocolVersion}"); Console.WriteLine($"Controller Software: {mid.ControllerSoftwareVersion}"); Console.WriteLine($"Tool Software: {mid.ToolSoftwareVersion}"); // Rev 4: Hardware info Console.WriteLine($"RBU Type: {mid.RBUType}"); Console.WriteLine($"Serial Number: {mid.ControllerSerialNumber}"); // Rev 5: System type Console.WriteLine($"System Type: {mid.SystemType}"); Console.WriteLine($"System SubType: {mid.SystemSubType}"); // Rev 6: Advanced features Console.WriteLine($"Sequence Number Support: {mid.SequenceNumberSupport}"); Console.WriteLine($"Linking Support: {mid.LinkingHandlingSupport}"); Console.WriteLine($"Station/Cell ID: {mid.StationCellId}"); Console.WriteLine($"Station/Cell Name: {mid.StationCellName}"); // Rev 7: Optional keep alive Console.WriteLine($"Optional Keep Alive: {mid.OptionalKeepAlive}"); ``` -------------------------------- ### Override Existing MIDs in Interpreter Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md This C# example shows how to override a default MID (Mid0081) with a custom implementation (`OverridedMid0081`). This is useful when the controller's implementation differs from the documentation or when you need to add custom properties and conversion logic. It uses a `Dictionary` to map MID numbers to their custom types. ```csharp //This will override Mid 81 with my custom Mid var _midInterpreter new MidInterpreter().UseAllMessages() .UseTimeMessages(new Dictionary() { { 81, typeof(OverridedMid0081) } }); public class OverridedMid0081 : Mid0081 { public string FormattedDate { get => Time.ToString("dd/MM/yyyy HH:mm:ss"); set => Time = DateTime.Parse(value); } public OverridedMid0081() { } public override string Pack() { Time = TestCustomMid.Now; return base.Pack(); } } ``` -------------------------------- ### Managing Job Messages with OpenProtocolInterpreter Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Demonstrates how to pack requests for job lists, specific job data, and job selection, as well as how to parse incoming job information responses using the OpenProtocolInterpreter library. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Job; var interpreter = new MidInterpreter().UseJobMessages(); // Request job ID list (Mid0030) var jobListRequest = new Mid0030(revision: 1); string requestPackage = jobListRequest.Pack(); Console.WriteLine($"Job List Request: {requestPackage}"); // Request specific job data (Mid0032) var jobDataRequest = new Mid0032(jobId: 1, revision: 2); string jobRequest = jobDataRequest.Pack(); Console.WriteLine($"Job Data Request: {jobRequest}"); // Select a job (Mid0038) var selectJob = new Mid0038(jobId: 5, revision: 1); string selectPackage = selectJob.Pack(); Console.WriteLine($"Select Job: {selectPackage}"); // Subscribe to job info (Mid0034) var jobSubscribe = new Mid0034(revision: 1); string subscribePackage = jobSubscribe.Pack(); Console.WriteLine($"Job Subscribe: {subscribePackage}"); // Parse job info response (Mid0035) string jobInfoPackage = "00350035001 0100103Job Name 01001"; var jobInfo = interpreter.Parse(jobInfoPackage); Console.WriteLine($"Job ID: {jobInfo.JobId}"); Console.WriteLine($"Job Status: {jobInfo.JobStatus}"); ``` -------------------------------- ### Implement and Register Custom MIDs in C# Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt This snippet shows how to extend an existing MID by overriding the Pack method and how to define a brand new MID by implementing the ITime interface and registering data fields. Finally, it demonstrates how to configure the MidInterpreter to recognize these custom implementations. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Time; using System; using System.Collections.Generic; public class CustomMid0081 : Mid0081 { public string FormattedDate { get => Time.ToString("dd/MM/yyyy HH:mm:ss"); set => Time = DateTime.Parse(value); } public CustomMid0081() { } public override string Pack() { return base.Pack(); } } public class NewMid0083 : Mid, ITime { private const int LAST_REVISION = 1; public const int MID = 83; public DateTime Time { get => GetField(1, (int)DataFields.TIME).GetValue(OpenProtocolConvert.ToDateTime); set => GetField(1, (int)DataFields.TIME).SetValue(OpenProtocolConvert.ToString, value); } public string TimeZone { get => GetField(1, (int)DataFields.TIMEZONE).Value; set => GetField(1, (int)DataFields.TIMEZONE).SetValue(value); } public NewMid0083() : base(MID, LAST_REVISION) { } protected override Dictionary> RegisterDatafields() { return new Dictionary>() { { 1, new List() { DataField.Timestamp(DataFields.TIME, 20), DataField.String(DataFields.TIMEZONE, 41, 2) } } }; } protected enum DataFields { TIME, TIMEZONE } } var interpreter = new MidInterpreter() .UseAllMessages() .UseTimeMessages(new Dictionary() { { 81, typeof(CustomMid0081) } }) .UseCustomMessage(new Dictionary() { { 83, typeof(NewMid0083) } }); var customTime = new NewMid0083 { Time = DateTime.Now, TimeZone = "US" }; string package = customTime.Pack(); Console.WriteLine($"Custom MID: {package}"); ``` -------------------------------- ### MidInterpreter - Parse and Build Open Protocol Messages (C#) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Demonstrates the core functionality of the MidInterpreter class for parsing raw Open Protocol package strings or byte arrays into strongly-typed Mid objects, and for generating package strings or byte arrays from Mid objects. It shows how to initialize the interpreter and handle different parsing scenarios, including type-specific parsing. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; using OpenProtocolInterpreter.Tightening; // Initialize interpreter with all available messages var interpreter = new MidInterpreter().UseAllMessages(); // Parse a raw package string to a typed Mid object string package = "00260004001 001802"; var mid = interpreter.Parse(package); Console.WriteLine($"Parsed MID: {mid.Header.Mid}"); // Output: Parsed MID: 4 // Parse with expected type (throws InvalidCastException if wrong type) var mid04 = interpreter.Parse(package); Console.WriteLine($"Failed MID: {mid04.FailedMid}, Error: {mid04.ErrorCode}"); // Output: Failed MID: 18, Error: ParameterSetIdNotPresent // Parse from byte array byte[] bytes = System.Text.Encoding.ASCII.GetBytes(package); var parsedMid = interpreter.Parse(bytes); // Generate a package string from a Mid object var startRequest = new Mid0001(revision: 1); string outputPackage = startRequest.Pack(); Console.WriteLine($"Generated: {outputPackage}"); // Output: Generated: 00200001001 // Generate as byte array byte[] outputBytes = startRequest.PackBytes(); ``` -------------------------------- ### Generate Open Protocol Message from Object (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Illustrates how to create an Open Protocol message object from scratch and then pack it into its string representation. This is useful for sending commands or data to devices that use the Open Protocol. ```csharp var jobUploadRequest = new Mid0032(1, 2); //Job id 1, revision 2 var package = jobUploadRequest.Pack(); //Generated package => 00240032002 0001 ``` -------------------------------- ### Registering Message Categories and Parsing MIDs Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Demonstrates how to configure the MidInterpreter by registering specific message categories to handle various Open Protocol MIDs. It also shows how to parse a raw string package into a strongly-typed MID object. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; using OpenProtocolInterpreter.Tightening; using OpenProtocolInterpreter.Alarm; using OpenProtocolInterpreter.Job; using OpenProtocolInterpreter.Tool; using OpenProtocolInterpreter.Vin; var interpreter = new MidInterpreter() .UseCommunicationMessages() .UseTighteningMessages() .UseAlarmMessages() .UseJobMessages() .UseToolMessages() .UseVinMessages() .UseParameterSetMessages() .UseKeepAlive(); string tighteningPackage = "00980061001 0001020203Tool Name Here VIN12345678901234567890001001000410011 010000102500000100000101001999902022-01-15:10:30:002021-12-01:08:00:00100000000001"; var tighteningResult = interpreter.Parse(tighteningPackage); Console.WriteLine($"Torque: {tighteningResult.Torque}, Angle: {tighteningResult.Angle}"); ``` -------------------------------- ### Handle Mid0004 Command Errors and Create Error Responses (C#) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Illustrates how to parse a Mid0004 message to understand command failures, extracting the failed MID and error code. It also shows how to handle common error codes using a switch statement and how to construct a Mid0004 error response message to be sent by a controller. Requires the OpenProtocolInterpreter library. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; var interpreter = new MidInterpreter().UseCommunicationMessages(); // Parse an error response string errorPackage = "00260004001 001802"; var errorMid = interpreter.Parse(errorPackage); Console.WriteLine($"Failed MID: {errorMid.FailedMid}"); Console.WriteLine($"Error Code: {errorMid.ErrorCode}"); // Output: Failed MID: 18, Error Code: ParameterSetIdNotPresent // Handle common error codes switch (errorMid.ErrorCode) { case Error.ClientAlreadyConnected: Console.WriteLine("Another client is already connected to the controller"); break; case Error.MidRevisionUnsupported: Console.WriteLine("The requested MID revision is not supported"); break; case Error.ParameterSetIdNotPresent: Console.WriteLine("The specified parameter set ID does not exist"); break; case Error.LastTighteningResultSubscriptionAlreadyExists: Console.WriteLine("Already subscribed to tightening results"); break; case Error.JobIdNotPresent: Console.WriteLine("The specified job ID does not exist"); break; default: Console.WriteLine($"Error: {errorMid.ErrorCode}"); break; } // Create an error response (as controller) var error = new Mid0004(revision: 1) { FailedMid = 60, ErrorCode = Error.LastTighteningResultSubscriptionAlreadyExists }; string packed = error.Pack(); Console.WriteLine($"Error package: {packed}"); ``` -------------------------------- ### Handle Tightening MID and Send Acknowledge (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Demonstrates the 'OnTighteningReceived' method, which is called when a MID_0061 (tightening) is received. It casts the received MID to 'Mid0061', calls 'BuildAndSendAcknowledge', and logs a message. The 'BuildAndSendAcknowledge' method prepares and sends a MID_0062 acknowledge message. ```csharp protected void OnTighteningReceived(ReceivedMidEventArgs e) { try { Mid0061 tighteningMid = e.ReceivedMID as Mid0061; //Casting to the right mid //This method just send the ack from tightening mid BuildAndSendAcknowledge(tighteningMid); Console.log("TIGHTENING ARRIVED") } catch (Exception ex) { Console.log(ex.Message); } } protected void BuildAndSendAcknowledge(Mid mid) { TcpClient.GetStream().Write(new Mid0062().Pack()); //Send acknowledge to controller } ``` -------------------------------- ### Manage Alarm Notifications with OpenProtocolInterpreter Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Shows how to subscribe to, parse, and acknowledge controller alarm messages using Mid0070 through Mid0073. It highlights handling different revisions of Mid0071 to access alarm text and status flags. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Alarm; var interpreter = new MidInterpreter().UseAlarmMessages(); string alarmPackage = "00530071001 01E10102112022-01-15:14:30:00"; var alarm = interpreter.Parse(alarmPackage); string alarmPackageV2 = "01050071002 01E1010102112022-01-15:14:30:0002Motor overheated - please wait for cooldown "; var alarmV2 = interpreter.Parse(alarmPackageV2); var alarmSubscribe = new OpenProtocolInterpreter.Alarm.Mid0070(); string subscribePackage = alarmSubscribe.Pack(); var alarmAck = new Mid0072(); string ackPackage = alarmAck.Pack(); var unsubscribe = new Mid0073(); string unsubPackage = unsubscribe.Pack(); ``` -------------------------------- ### Handle Tightening Results with OpenProtocolInterpreter Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Demonstrates subscribing to tightening results using Mid0060, parsing tightening data from Mid0061, and acknowledging receipt with Mid0062. It utilizes the MidInterpreter to process raw protocol strings into strongly-typed objects. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; using OpenProtocolInterpreter.Tightening; var interpreter = new MidInterpreter() .UseCommunicationMessages() .UseTighteningMessages(); var subscribeRequest = new Mid0060(revision: 1, noAckFlag: false); string subscribePackage = subscribeRequest.Pack(); string tighteningPackage = @"02310061001 0101020203Tool Controller Name VIN Number Here 01001000410011 010100100025000010000010100199990122-01-15:10:30:002021-12-01:08:00:00100000000001"; var result = interpreter.Parse(tighteningPackage); var ack = new Mid0062(); string ackPackage = ack.Pack(); ``` -------------------------------- ### Parse Open Protocol Message to Object (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Demonstrates how to use the MidInterpreter to parse a string representation of an Open Protocol message (MID) into a strongly-typed object. It shows how to access data fields from the parsed object, such as the Failed MID and Error Code from a Mid0004. ```csharp var interpreter = new MidInterpreter(); var midPackage = @"00260004001 001802"; var myMid04 = interpreter.Parse(midPackage); //MID 0004 is an error mid which contains which MID Failed and its error code //Int value of the Failed Mid int myFailedMid = myMid04.FailedMid; //An enum with Error Code Error errorCode = myMid04.ErrorCode; ``` -------------------------------- ### Register MID Delegates with Dictionary (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Implements a method 'RegisterOnAsyncReceivedMids' that creates and populates a dictionary. This dictionary maps MID types to their corresponding 'ReceivedCommandActionDelegate' handlers, enabling a structured way to manage MID processing. ```csharp protected Dictionary RegisterOnAsyncReceivedMids() { var receivedMids = new Dictionary(); receivedMids.Add(typeof(Mid0005), new ReceivedCommandActionDelegate(OnCommandAcceptedReceived)); receivedMids.Add(typeof(Mid0004), new ReceivedCommandActionDelegate(OnErrorReceived)); receivedMids.Add(typeof(Mid0071), new ReceivedCommandActionDelegate(OnAlarmReceived)); receivedMids.Add(typeof(Mid0061), new ReceivedCommandActionDelegate(OnTighteningReceived)); receivedMids.Add(typeof(Mid0035), new ReceivedCommandActionDelegate(OnJobInfoReceived)); return receivedMids; } ``` -------------------------------- ### Add Custom MIDs Not in Documentation Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md This C# code illustrates how to add MIDs that are not part of the standard Open Protocol documentation to the `MidInterpreter`. It uses `UseCustomMessage` with a dictionary mapping the custom MID number (e.g., 83) to its corresponding type (`NewMid0083`). Note that custom messages may have performance implications. ```csharp var _midInterpreter new MidInterpreter().UseAllMessages() .UseCustomMessage(new Dictionary() { { 83, typeof(NewMid0083) } }); public class NewMid0083 : Mid { private readonly IValueConverter _dateConverter; private const int LAST_REVISION = 1; public const int MID = 83; public DateTime Time { get => GetField(1, (int)DataFields.TIME).GetValue(_dateConverter.Convert); set => GetField(1, (int)DataFields.TIME).SetValue(_dateConverter.Convert, value); } public string TimeZone { get => GetField(1, (int)DataFields.TIMEZONE).Value; set => GetField(1, (int)DataFields.TIMEZONE).SetValue(value); } public NewMid0083() : base(MID, LAST_REVISION) { _dateConverter = new DateConverter(); } protected override Dictionary> RegisterDatafields() { return new Dictionary>() { { 1, new List() { new DataField((int)DataFields.TIME, 20, 19), new DataField((int)DataFields.TIMEZONE, 41, 2) } } }; } public enum DataFields { TIME, TIMEZONE } } ``` -------------------------------- ### Implementing Keep-Alive Mechanism Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Shows how to generate and send Mid9999 keep-alive messages to maintain controller connectivity, including a timer-based implementation to handle inactivity timeouts. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.KeepAlive; using System.Diagnostics; var interpreter = new MidInterpreter().UseAllMessages(); // Create keep alive message var keepAlive = new Mid9999(); string keepAlivePackage = keepAlive.Pack(); // Example: Implementing keep alive timer var lastActivity = Stopwatch.StartNew(); int keepAliveIntervalMs = 10000; void CheckKeepAlive() { if (lastActivity.ElapsedMilliseconds > keepAliveIntervalMs) { var ka = new Mid9999(); Console.WriteLine("Sending keep alive..."); lastActivity.Restart(); } } // Parsing response string response = "00209999000 "; var mirroredKeepAlive = interpreter.Parse(response); if (mirroredKeepAlive.Header.Mid == Mid9999.MID) { Console.WriteLine("Keep alive acknowledged by controller"); } ``` -------------------------------- ### C# Open Protocol Driver Event-Driven Handler Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Implements an event-driven Open Protocol driver in C#. It uses a dictionary to map MID types to specific handler actions. The driver can parse incoming messages, dispatch them to the appropriate handler, and send acknowledgments or other responses. Dependencies include the OpenProtocolInterpreter library. ```csharp using OpenProtocolInterpreter; using OpenProtocolInterpreter.Communication; using OpenProtocolInterpreter.Tightening; using OpenProtocolInterpreter.Alarm; using OpenProtocolInterpreter.Job; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; public class ReceivedMidEventArgs : EventArgs { public Mid ReceivedMid { get; set; } } public class OpenProtocolDriver { private readonly MidInterpreter _interpreter; private readonly Dictionary> _handlers; private TcpClient _tcpClient; private NetworkStream _stream; public OpenProtocolDriver() { _interpreter = new MidInterpreter().UseAllMessages(); _handlers = new Dictionary>(); // Register handlers for expected MIDs RegisterHandler(OnCommandAccepted); RegisterHandler(OnCommandError); RegisterHandler(OnTighteningReceived); RegisterHandler(OnAlarmReceived); RegisterHandler(OnJobInfoReceived); } public void RegisterHandler(Action handler) where T : Mid { _handlers[typeof(T)] = handler; } public void OnPackageReceived(string message) { try { var mid = _interpreter.Parse(message); var handler = _handlers.FirstOrDefault(x => x.Key == mid.GetType()); if (handler.Value == null) { Console.WriteLine($"No handler for MID: {mid.GetType().Name}"); return; } handler.Value(new ReceivedMidEventArgs { ReceivedMid = mid }); } catch (Exception ex) { Console.WriteLine($"Parse error: {ex.Message}"); } } private void OnCommandAccepted(ReceivedMidEventArgs e) { var mid = (Mid0005)e.ReceivedMid; Console.WriteLine($"Command {mid.AcceptedMid} accepted"); } private void OnCommandError(ReceivedMidEventArgs e) { var mid = (Mid0004)e.ReceivedMid; Console.WriteLine($"Command {mid.FailedMid} failed: {mid.ErrorCode}"); } private void OnTighteningReceived(ReceivedMidEventArgs e) { var mid = (Mid0061)e.ReceivedMid; Console.WriteLine($"Tightening: Torque={mid.Torque}, Angle={mid.Angle}, OK={mid.TighteningStatus}"); // Send acknowledgement SendMessage(new Mid0062().Pack()); } private void OnAlarmReceived(ReceivedMidEventArgs e) { var mid = (Mid0071)e.ReceivedMid; Console.WriteLine($"ALARM: {mid.ErrorCode} at {mid.Time}"); // Send acknowledgement SendMessage(new Mid0072().Pack()); } private void OnJobInfoReceived(ReceivedMidEventArgs e) { var mid = (Mid0035)e.ReceivedMid; Console.WriteLine($"Job {mid.JobId}: Status={mid.JobStatus}"); } public void SendMessage(string message) { // Send message via TCP/IP Console.WriteLine($"Sending: {message}"); // _stream?.Write(Encoding.ASCII.GetBytes(message)); } public void StartCommunication() { // Send Mid0001 to initiate communication var startComm = new Mid0001(revision: 1); SendMessage(startComm.Pack()); } public void SubscribeToTightenings() { var subscribe = new Mid0060(revision: 1); SendMessage(subscribe.Pack()); } public void SubscribeToAlarms() { var subscribe = new Mid0070(); SendMessage(subscribe.Pack()); } } // Usage example var driver = new OpenProtocolDriver(); driver.StartCommunication(); // Simulate receiving messages driver.OnPackageReceived("00240005001 0060"); // Command accepted driver.OnPackageReceived("02310061001 0101020203Tool Controller VIN12345 01001000410011 010100100025000010000010100199990122-01-15:10:30:002021-12-01:08:00:00100000000001"); ``` -------------------------------- ### Process Incoming Packages and Invoke Delegates (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md The 'OnPackageReceived' method parses an incoming message string into a MID object. It then looks up the appropriate delegate in the 'OnReceivedMid' dictionary based on the MID's type and invokes it, passing the MID data encapsulated in 'ReceivedMidEventArgs'. Includes error handling for parsing and delegate invocation. ```csharp protected void OnPackageReceived(string message) { try { //Parse to mid class var mid = Interpreter.Parse(message); //Get Registered delegate for the MID that was identified var action = OnReceivedMid.FirstOrDefault(x => x.Key == mid.GetType()); if (action.Equals(default(KeyValuePair))) return; //Stop if there is no delegate registered for the message that arrived action.Value(new ReceivedMidEventArgs() { ReceivedMid = mid }); //Call delegate } catch (Exception ex) { Console.log(ex.Message); } } ``` -------------------------------- ### Specify Custom MIDs for Interpreter Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md This C# code demonstrates how to configure the MidInterpreter to only consider a specific set of MIDs. This improves performance by reducing the number of MIDs the interpreter needs to process. It takes an array of `Type` objects representing the MIDs to be used. ```csharp string package = "00260004001 001802"; var myCustomInterpreter = new MidInterpreter() .UseAllMessages(new Type[] { typ eof(Mid0001), typ eof(Mid0002), typ eof(Mid0003), typ eof(Mid0004), typ eof(Mid0106) }); //Will work: var myMid04 = myCustomInterpreter.Parse(package); //Won't work, will throw NotImplementedException: var myMid30 = myCustomInterpreter.Parse(package); //Won't work, will throw InvalidCastException: var myMid01 = myCustomInterpreter.Parse(package); ``` -------------------------------- ### Category-Specific Message Registration Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Explains how to register specific message categories to the MidInterpreter for granular control over supported message types. ```APIDOC ## Message Registration ### Description Registers specific message categories to the interpreter instance to enable parsing and packing of corresponding MIDs. ### Usage Use the fluent API on the `MidInterpreter` instance to include desired message categories. ### Example ```csharp var interpreter = new MidInterpreter() .UseCommunicationMessages() .UseTighteningMessages() .UseAlarmMessages(); ``` ``` -------------------------------- ### Inject Custom MIDs Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Enables the addition of custom or undocumented MIDs to the interpreter by inheriting from the base Mid class. ```APIDOC ## Add Custom MIDs ### Description Registers new, non-standard MIDs that are not included in the default Open Protocol documentation. ### Method C# Method Call ### Parameters - **customMessages** (Dictionary) - Required - A dictionary mapping the custom MID integer ID to the new class type. ### Request Example var _midInterpreter = new MidInterpreter().UseCustomMessage(new Dictionary() { { 83, typeof(NewMid0083) } }); ### Response - **MidInterpreter** (Object) - Returns the interpreter instance with custom message support. ``` -------------------------------- ### Job Management MIDs (0030-0039) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Endpoints for managing job workflows, including requesting job lists, retrieving job data, selecting jobs, and subscribing to job information updates. ```APIDOC ## Job Management MIDs (0030-0039) ### Description These messages handle job management operations including listing jobs, selecting specific jobs, and receiving detailed job information from the controller. ### Method N/A (Binary Protocol) ### Endpoint Mid0030, Mid0032, Mid0034, Mid0035, Mid0038 ### Parameters #### Request Body - **jobId** (int) - Optional - The unique identifier for the job (used in Mid0032, Mid0038) - **revision** (int) - Required - The protocol revision level ### Request Example // Request job ID list (Mid0030) var jobListRequest = new Mid0030(revision: 1); ### Response #### Success Response (200) - **JobId** (int) - The ID of the job - **JobStatus** (int) - Current status of the job - **JobBatchMode** (int) - Batch mode configuration - **JobBatchSize** (int) - Total size of the batch - **JobBatchCounter** (int) - Current progress of the batch #### Response Example // Parsed Mid0035 response { "JobId": 1, "JobStatus": 0, "JobBatchMode": 1, "JobBatchSize": 3, "JobBatchCounter": 1 } ``` -------------------------------- ### Register Specific MIDs Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Configures the interpreter to only recognize and parse a specific subset of MIDs to improve performance and restrict message handling. ```APIDOC ## Configure MID Registration ### Description Limits the interpreter to a specific set of MIDs, preventing the processing of unnecessary message types. ### Method C# Method Call ### Parameters - **types** (Type[]) - Required - An array of types representing the MIDs to be registered. ### Request Example var myCustomInterpreter = new MidInterpreter().UseAllMessages(new Type[] { typeof(Mid0001), typeof(Mid0004) }); ### Response - **MidInterpreter** (Object) - Returns the configured interpreter instance. ``` -------------------------------- ### Override Existing MIDs Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Allows developers to replace standard MID implementations with custom classes to handle specific business logic or data conversions. ```APIDOC ## Override MID Implementation ### Description Injects a custom class to override the default behavior of a specific MID. ### Method C# Method Call ### Parameters - **overrides** (Dictionary) - Required - A dictionary mapping the MID integer ID to the custom class type. ### Request Example var _midInterpreter = new MidInterpreter().UseTimeMessages(new Dictionary() { { 81, typeof(OverridedMid0081) } }); ### Response - **MidInterpreter** (Object) - Returns the interpreter instance with overridden logic. ``` -------------------------------- ### Define Delegate for Received Commands (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Declares a delegate type 'ReceivedCommandActionDelegate' used for handling received MID events. This delegate specifies the signature for methods that will process MID-specific data. ```csharp protected delegate void ReceivedCommandActionDelegate(ReceivedMIDEventArgs e); ``` -------------------------------- ### ReceivedMIDEventArgs Class Definition (C#) Source: https://github.com/rickedb/openprotocolinterpreter/blob/master/README.md Defines the 'ReceivedMidEventArgs' class, which encapsulates data related to a received MID. It contains a 'ReceivedMid' property to hold the parsed MID object. ```csharp public class ReceivedMidEventArgs : EventArgs { public Mid ReceivedMid { get; set; } } ``` -------------------------------- ### Keep Alive (Mid9999) Source: https://context7.com/rickedb/openprotocolinterpreter/llms.txt Maintains the connection between the client and the controller by sending periodic heartbeat signals. ```APIDOC ## Mid9999 - Keep Alive ### Description The Mid9999 message is used to maintain the connection with the controller. It is recommended to send this message every 10 seconds during inactivity to avoid the controller's 15-second timeout. ### Method N/A (Binary Protocol) ### Endpoint Mid9999 ### Parameters None ### Request Example var keepAlive = new Mid9999(); string keepAlivePackage = keepAlive.Pack(); ### Response #### Success Response (200) - **Header.Mid** (int) - Returns 9999 to acknowledge the connection is active. #### Response Example { "Header": { "Mid": 9999 } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.