/// <summary> /// Build packet and transmit it on bus /// </summary> /// <param name="msg">Message to be transmitted</param> /// <returns>true if success, false if error</returns> public bool Send(LinkMessage msg) { int len = msg.Data.Length; if (len > 9) { len = 9; } string raw = '#' + len.ToString() + msg.Data; byte[] data = Encoding.ASCII.GetBytes(raw); if (phy.Transmit(data) == true) { return(true); } return(false); }
/// <summary> /// Event handler for OnMessageReceived event of link /// </summary> /// <param name="sender">Link layer instance</param> /// <param name="msg">Event parameters</param> private void Link_OnMessageReceived(LinkLayer sender, LinkMessage msg) { if (!IsServer) { char addr = msg.Data[0]; if (value_tracker.Keys.Contains(addr)) { ApplicationPdu pdu = new ApplicationPdu() { Address = addr, Value = Convert.ToInt32(msg.Data.Substring(1)) }; value_tracker[pdu.Address] = pdu.Value; Debug.WriteLine("APP-ADDR:" + pdu.Address + "-VAL:" + msg.Data.Substring(1)); TriggerApplicationUpdate(pdu); } } }
/// <summary> /// Send application protocol data unit to lower layer /// </summary> /// <param name="pdu">Application protocol data unit to send</param> /// <returns>true if success, false if error</returns> private bool ServerBroadcastValue(ApplicationPdu pdu) { if (IsServer) { try { LinkMessage msg = new LinkMessage() { Data = pdu.Address + pdu.Value.ToString() }; link.Send(msg); } catch { return(false); } return(true); } else { return(false); } }
/// <summary> /// Handler for timers Elapsed event /// </summary> /// <param name="sender">Timer instance that triggered event</param> /// <param name="e">Arguments</param> private void TimeoutHandler(object sender, System.Timers.ElapsedEventArgs e) { if (status == LinkStatus.IDLE) { // Timeout occured but bus is idle (message processed) should not happen Debug.WriteLine("LINK-IDLE_TIMEOUT"); return; } if (actl_message_id != tkick_message_id) { // Timeout occured but link is already handling another message - should not happen Debug.WriteLine("LINK-BUSY_TIMEOUT"); return; } // Timeout occured and link is stuck, reset (required transport layer for handling possible data loss) Debug.WriteLine("LINK-STUCK_TIMEOUT"); actl_message = new LinkMessage(); rx_counter = 0; actl_message_id = 0; tkick_message_id = 0; status = LinkStatus.IDLE; return; }
/// <summary> /// Method for triggering OnMessageReceived event /// </summary> /// <param name="msg">Received message</param> protected virtual void TriggerMessageReceived(LinkMessage msg) { OnMessageReceived?.Invoke(this, msg); }
/// <summary> /// Task for processing received data running in thread /// </summary> private void LinkThreadTask() { while (true) { // Sleep delay Thread.Sleep(1); // Pop byte from receive ring buffer int value = phy.Receive(); if (value != -1) { char rx = Convert.ToChar(value); switch (status) { // Bus is idle and waiting for start character case LinkStatus.IDLE: if (rx == '#') { // Save actual message id and start timeout timer tkick_message_id = actl_message_id; timer.Start(); // Proceed to length reception status = LinkStatus.GET_LEN; } break; // Receiving message length case LinkStatus.GET_LEN: uint length = (uint)(rx - '0'); actl_message = new LinkMessage() { Length = length }; // Reset data counter rx_counter = 0; // Set link status to data reception status = LinkStatus.GET_DATA; break; // Receiving message data case LinkStatus.GET_DATA: // Save data and increment counter actl_message.Data += rx; rx_counter++; if (rx_counter == actl_message.Length) { // Message length achieved, assign id to next message actl_message_id++; // Stop timeout timer timer.Stop(); // Log received data to output window Debug.WriteLine("LINK-" + actl_message.ToString()); // Trigger OnMessageReceived event TriggerMessageReceived(actl_message); // Return link status back to idle state so next message can be processed status = LinkStatus.IDLE; } break; // Should not get there default: break; } } } }