/// <summary> /// Get the Number Message of a specific sent message /// </summary> /// <param name="FID">Message's FID</param> /// <param name="Command">Message's command</param> /// <returns>Number Message</returns> /// <remarks>This function use the FID if the frame window is greater than 1, otherwise use the command</remarks> public uint Response(byte FID, byte Command) { uint numMessage = (uint)0; CMessageCom message = null; if (m_frameWindow > 1) { for (var i = 0; i <= m_Messages.Count - 1; i++) { if (m_Messages[i].FID() == FID) { message = m_Messages[i]; m_Messages.RemoveAt(System.Convert.ToInt32(i)); break; } } } else { if (m_Messages.Count > 0) { if (m_Messages[0].Command() == Command) { message = m_Messages[0]; m_Messages.RemoveAt(0); } } } if (message != null) { //Desactivamos el timer de timeout ya que no esperamos respuesta m_TimerConnectTimeOut.Change(Timeout.Infinite, Timeout.Infinite); //Stop the Timer m_ToSendFrameWindow++; numMessage = message.NumberMessage(); //Si no hay mas mensajes para enviar empezamos el mantenimiento de la conexión if (m_Messages.Count == 0) { m_TimerConnectMaintenance.Change(TIMER_CONNECT_MAINTENANCE, TIMER_CONNECT_MAINTENANCE); //Start the Timer } } TryToSend(); return(numMessage); }
private void ConnectMaintenance(byte address) { //Incrementamos el Number Message m_NumberMessage = System.Convert.ToUInt32(m_NumberMessage + 1); //Incrementamos el FID if (m_FID >= MAX_FID) { m_FID = (byte)0; } m_FID += 1; // 11/05/2016 Se cambia a SYN (como originalmente) CMessageCom message = new CMessageCom((uint)0, m_FID, (byte)EnumCommandFrame.M_SYN, new byte[] { }, address); SendMessage(message); }
/// <summary> /// Send messages until the pending messages to response is equal to the frame window /// </summary> private void TryToSend() { while (m_ToSendFrameWindow > 0) { CMessageCom message = ReadMessage(); if (ReferenceEquals(message, null)) { break; } else { //Decrementamos la ventana de mensajes m_ToSendFrameWindow--; //Activamos el timer de timeout m_TimerConnectTimeOut.Change(Timeout.Infinite, Timeout.Infinite); //Stop the Timer if (message.DelayedResponse) { //No desactivamos el mantenimiento de la conexión ya que el tiempo de respuesta es demasiado elevado m_TimerConnectMaintenance.Change(TIMER_CONNECT_MAINTENANCE, TIMER_CONNECT_MAINTENANCE); //Start the Timer m_TimerConnectTimeOut.Change(TIME_TIMEOUT_MESSAGE_DELAYED_RESPONSE, TIME_TIMEOUT_MESSAGE_DELAYED_RESPONSE); //Start the Timer } else { //Desactivamos el mantenimiento de la conexión m_TimerConnectMaintenance.Change(Timeout.Infinite, Timeout.Infinite); //Stop the Timer m_TimerConnectTimeOut.Change(TIME_TIMEOUT_MESSAGE, TIME_TIMEOUT_MESSAGE); //Start the Timer } //FIXME . Modo BURST solo se utiliza para la DME. //Para la DME todas las comunicaciones van contra la dirección 0x00 pero cuando se envía un ACK se tiene que hacer contra la 0x10, sino, responde NACK if (m_frameWindow > 1 & message.Command() == (byte)EnumCommandFrame.M_ACK) { message.Address = (byte)(0x10); } if (SendMessageEvent != null) { SendMessageEvent(message); } } } }
public uint Send(byte[] Datos, byte command, byte address, bool delayedResponse = false) { //Incrementamos el Number Message m_NumberMessage = System.Convert.ToUInt32(m_NumberMessage + 1); uint NumMessage = m_NumberMessage; //Incrementamos el FID if (m_FID >= MAX_FID) { m_FID = (byte)0; } m_FID += 1; //Creamos el mensaje CMessageCom message = new CMessageCom(m_NumberMessage, m_FID, command, Datos, address); message.DelayedResponse = delayedResponse; CStackMessages stackAddressMessages = null; m_mutexStackAddressMessages.WaitOne(); //Los broadcast los enviamos directamente if ((address & (byte)EnumAddress.MASK_BROADCAST_ADDRESS) != (byte)EnumAddress.MASK_BROADCAST_ADDRESS) { //Si existe la cola lo ponemos en cola, sino, lo enviamos directamente if (StackAddressMessageContains(address & (byte)EnumAddress.MASK_STATION_ADDRESS)) { stackAddressMessages = StackAddressMessageGet(address & (byte)EnumAddress.MASK_STATION_ADDRESS); } } m_mutexStackAddressMessages.Release(); if (stackAddressMessages != null) { stackAddressMessages.Add(message); } else { SendMessage(message); } return(NumMessage); }
private void SendMessage(CMessageCom message) { m_mutexStackDll.WaitOne(); if (m_StackDll != null) { m_StackDll.SendData(message.Data(), message.Address, message.Command(), message.FID(), message.Response()); } m_mutexStackDll.Release(); //Se notifica de los Reset para poder continuar con el updater en las estaciones de protocolo 1 if (message.Command() == (byte)EnumCommandFrame.M_RESET) { if (ResetSendedEvent != null) { ResetSendedEvent(message.Address); } } }
/// <summary> /// Manage a timeout communication. Tries to resend the message. If attempts have been exhausted, raise an event /// </summary> /// <param name="state">Timer state</param> private void Elapsed_ConnectTimeOut(object state) { m_TimerConnectTimeOut.Change(Timeout.Infinite, Timeout.Infinite); //Stop the Timer if (m_Messages.Count > 0) { CMessageCom message = m_Messages[0]; if (message.TriesRemaining() > 0) { message.DecrementTriesRemaining(); m_Messages[0] = message; if (message.DelayedResponse) { m_TimerConnectTimeOut.Change(TIME_TIMEOUT_MESSAGE_DELAYED_RESPONSE, TIME_TIMEOUT_MESSAGE_DELAYED_RESPONSE); //Start the Timer } else { m_TimerConnectTimeOut.Change(TIME_TIMEOUT_MESSAGE, TIME_TIMEOUT_MESSAGE); //Start the Timer } if (SendMessageEvent != null) { SendMessageEvent(message); } } else { m_Messages.RemoveAt(0); if (ConnectionTimeOutEvent != null) { ConnectionTimeOutEvent(m_address, message.Command()); } } } }
/// <summary> /// Get the next message to send in the FIFO list /// </summary> /// <returns>Message to send</returns> private CMessageCom ReadMessage() { CMessageCom message = null; //Si está en modo BURST envía el siguiente que todavía no haya enviado if (m_frameWindow > 1) { for (var i = 0; i <= m_Messages.Count - 1; i++) { if (m_Messages[i].TriesRemaining() == CMessageCom.MAX_MESSAGE_TRIES) { message = m_Messages[i]; message.DecrementTriesRemaining(); m_Messages[i] = message; break; } } //Si está en modo SINGLE envía el primero } else { if (m_Messages.Count > 0) { if (m_Messages[0].TriesRemaining() == CMessageCom.MAX_MESSAGE_TRIES) { message = m_Messages[0]; message.DecrementTriesRemaining(); m_Messages[0] = message; } } } return(message); }
private void DataReceived(byte Origen, byte Command, byte[] Data, byte FID, bool Response) { uint NumMessage = (uint)0; CStackMessages stackAddressMessages = null; //Si es un HandShake respondemos directamente if (Command == (byte)EnumCommandFrame.M_NULL) { if (Response) { return; } byte[] Datos = new byte[1]; Datos[0] = (byte)EnumCommandFrame.M_ACK; CMessageCom message = new CMessageCom((uint)0, (byte)(0xFD), Command, Datos, Origen, true); SendMessage(message); } else if (Command == (byte)EnumCommandFrame.M_NACK) { m_mutexStackAddressMessages.WaitOne(); if (m_htStackAddressMessages != null) { //Respuesta de una dirección a la que hemos enviado un mensaje if (StackAddressMessageContains(Origen & (byte)EnumAddress.MASK_STATION_ADDRESS)) { stackAddressMessages = StackAddressMessageGet(Origen & (byte)EnumAddress.MASK_STATION_ADDRESS); } } m_mutexStackAddressMessages.Release(); //Recuperar número de mensaje y eliminarlo de la lista if (stackAddressMessages != null) { NumMessage = stackAddressMessages.Response(FID, Data[(byte)EnumErrorFrame.Opcode]); } } else { //FIXME . Modo BURST solo se utiliza para la DME. //Para la DME todas las comunicaciones van contra la dirección 00 pero cuando se envía un ACK se tiene que hacer contra la 10, sino, responde NACK if (m_flowControlMethod == EnumFrameFlowControl.BURST & Command == (byte)EnumCommandFrame.M_ACK) { Origen = (byte)0; } m_mutexStackAddressMessages.WaitOne(); if (m_htStackAddressMessages != null) { //Respuesta de una dirección a la que hemos enviado un mensaje if (StackAddressMessageContains(Origen & (byte)EnumAddress.MASK_STATION_ADDRESS)) { stackAddressMessages = StackAddressMessageGet(Origen & (byte)EnumAddress.MASK_STATION_ADDRESS); } } m_mutexStackAddressMessages.Release(); //Recuperar número de mensaje y eliminarlo de la lista if (stackAddressMessages != null) { NumMessage = stackAddressMessages.Response(FID, Command); } } if (MessageResponseEvent != null) { MessageResponseEvent(NumMessage, Data, Command, Origen); } }
/// <summary> /// Add a new message to the FIFO list /// </summary> /// <param name="message">New message to send</param> public void Add(CMessageCom message) { m_Messages.Add(message); TryToSend(); }