Hola PepLluis.
Te agradezco a vos y al resto de los muchachos porque la informacion me fue de muchisima utilidad.
Estoy trabajando en la capa mas baja de un protocolo que utiliza el serial Port.
Me gustaria mostrarles lo que obtuve a partir de su informacion.
Es una clase que utiliza el serial port y todo lo recibido lo encola en un queue de recepcion. La capa superior solo tendra visible la existencia o no de un elemento recibido y en casi afirmativo podra pedir el primer recibido.
Ahora estoy trabajando en la queue de envio, a la cual la capa superior solo podra poner un elemento para ser enviado.
Les muestro el codigo para ver si les sirve de algo, y si encuentran algo para mejorar les agradezco desde ya su ayuda
//Delegate: Declaracion delegado del evento de recepcion de datos.
delegate void receiveDataDelegate();
public class LayerRS232
{
// Puerto serie
private SerialPort myPort;
//Buffer interno de recepcion
private Queue<string> queueReceiveBuffer;
//Buffer interno de envio
private Queue<string> queueSendBuffer;
private StreamWriter sw; //Para loguear errores de la capa
// Buffer temporal e Interno para al almacenar los datos recibidos en la interrupcion de recepcion.
private string receiveBuffer;
SaveFileDialog myFile = new SaveFileDialog(); //Lo uso para elegir donde grabar el log de errores
#region Constructor
public LayerRS232(SerialPort myPort)
{
//Puerto Serie
this.myPort = myPort;
//Handler para el evento de recepcion de datos
this.myPort.DataReceived += new SerialDataReceivedEventHandler(myPort_DataReceived);
//Buffer interno de recepcion
queueReceiveBuffer = new Queue<string>();
//Buffer interno de envio
queueSendBuffer = new Queue<string>();
//Frame Start
this.startFrame = (Convert.ToChar(192)).ToString() + (Convert.ToChar(63)).ToString();
//Frame End
this.EndFrame = (Convert.ToChar(206)).ToString() + (Convert.ToChar(49)).ToString();
myFile.ShowDialog();
}
#endregion
#region Handler: Evento de recepcion
//Tamaño minimo de una trama
private const int TAMANO_MIN = 13;
private void myPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
receiveBuffer += this.myPort.ReadExisting();
if (receiveBuffer.Length >= TAMANO_MIN)
{
receiveDataDelegate myDelegate = new receiveDataDelegate(receiveData);
myDelegate();
}
}
#endregion
#region Delegado: Recepcion
//Frame Start
private string startFrame;
//Frame End
private string EndFrame;
private void receiveData()
{
int Inicio = receiveBuffer.IndexOf(startFrame); // Posicion de Inicio de trama
int Final = receiveBuffer.IndexOf(EndFrame); // Posicion de Final de trama
// Si existe posicion de inicio y una despues del final
if ((Inicio > -1) & (Final > Inicio))
{
// Covertir la trama en un array de char's - Sin StartFrame y EndFrame
byte[] miTrama = StringToBytes(receiveBuffer.Substring(Inicio + 2, Final - 2 - Inicio));
// Eliminar la trama procesada del buffer
receiveBuffer = receiveBuffer.Substring(Final, receiveBuffer.Length - (Final + 2));
//FRAME SIZE
uint frameSize = (uint)((miTrama[0] << 8) + miTrama[1]);
if (frameSize != miTrama.Length) // Se quitaron 2 bytes del frame end, pero como el FrameSize ocupa 2 y no entra en la cuenta, se autojusta, sino hacer el calculo correcto.
{
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: FrameSize - {1} - {2}", DateTime.Now, frameSize, miTrama.Length);
sw.Close();
return;
}
//CHECKSUM
byte checksum = 0;
foreach (byte var in miTrama)
{
checksum += var;
}
checksum -= miTrama[miTrama.Length - 1];
checksum=(byte)(~checksum);
if (checksum != miTrama[miTrama.Length - 1])
{
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Checksum - {1} - {2}", DateTime.Now, checksum, miTrama[miTrama.Length - 1]);
sw.Close();
return;
}
else
{
queueReceiveBuffer.Enqueue(BytesToString(miTrama, 6, miTrama.Length - 7));
}
}
else
// De no cumplirse las condiciones de Inicio/Fin
{
// Si existe final
if (Final > -1)
{
// Eliminar bytes con un 0x3f detras y sin 0x01 delante
if (Final + 2 < receiveBuffer.Length)
{
//Elimino
receiveBuffer = receiveBuffer.Substring(Final + 2, receiveBuffer.Length - (Final + 2));
//Logueo
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Descarte Parcial - {1} - {2}",DateTime.Now,Final, receiveBuffer);
sw.Close();
}
// El final esta en la ultima posicion
else
{
//Logueo
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Descarte TOTAL - {1} - {2}", DateTime.Now, receiveBuffer.Length, receiveBuffer);
sw.Close();
//Elimino
receiveBuffer = "";
}
}
}
}
#endregion
#region Interfaz: Recepcion
// Indica si hay elementos en el buffer de recepcion
public bool isHaveFrame()
{
if (queueReceiveBuffer.Count > 0)
return true;
else
return false;
}
// Devuelve el primer elemento del buffer de recepcion
public string getFrame()
{
if (isHaveFrame())
return queueReceiveBuffer.Dequeue();
else
return "";
}
#endregion
private byte[] StringToBytes(String cadena)
{
return System.Text.Encoding.Default.GetBytes(cadena);
}
private string BytesToString(byte[] bytes)
{
return System.Text.Encoding.Default.GetString(bytes);
}
private string BytesToString(byte[] bytes, int index, int count)
{
return System.Text.Encoding.Default.GetString(bytes, index, count);
}
}
Como ven tome muchisimo de uds, e hice mis pequeñas acotaciones.
Obviamente la parte del Checksum, FrameSize son propias del protocolo. Y tambien el -2 o +2 que son debidos a que mi FrameStart y mi FrameEnd son 2 bytes.
Los ultimos 3 metodos me fueron muy utiles para trabajar de a bytes y recibir correctamente los datos enviados por el microcontrolador con el que me comunico.
Saludos
Te agradezco a vos y al resto de los muchachos porque la informacion me fue de muchisima utilidad.
Estoy trabajando en la capa mas baja de un protocolo que utiliza el serial Port.
Me gustaria mostrarles lo que obtuve a partir de su informacion.
Es una clase que utiliza el serial port y todo lo recibido lo encola en un queue de recepcion. La capa superior solo tendra visible la existencia o no de un elemento recibido y en casi afirmativo podra pedir el primer recibido.
Ahora estoy trabajando en la queue de envio, a la cual la capa superior solo podra poner un elemento para ser enviado.
Les muestro el codigo para ver si les sirve de algo, y si encuentran algo para mejorar les agradezco desde ya su ayuda
//Delegate: Declaracion delegado del evento de recepcion de datos.
delegate void receiveDataDelegate();
public class LayerRS232
{
// Puerto serie
private SerialPort myPort;
//Buffer interno de recepcion
private Queue<string> queueReceiveBuffer;
//Buffer interno de envio
private Queue<string> queueSendBuffer;
private StreamWriter sw; //Para loguear errores de la capa
// Buffer temporal e Interno para al almacenar los datos recibidos en la interrupcion de recepcion.
private string receiveBuffer;
SaveFileDialog myFile = new SaveFileDialog(); //Lo uso para elegir donde grabar el log de errores
#region Constructor
public LayerRS232(SerialPort myPort)
{
//Puerto Serie
this.myPort = myPort;
//Handler para el evento de recepcion de datos
this.myPort.DataReceived += new SerialDataReceivedEventHandler(myPort_DataReceived);
//Buffer interno de recepcion
queueReceiveBuffer = new Queue<string>();
//Buffer interno de envio
queueSendBuffer = new Queue<string>();
//Frame Start
this.startFrame = (Convert.ToChar(192)).ToString() + (Convert.ToChar(63)).ToString();
//Frame End
this.EndFrame = (Convert.ToChar(206)).ToString() + (Convert.ToChar(49)).ToString();
myFile.ShowDialog();
}
#endregion
#region Handler: Evento de recepcion
//Tamaño minimo de una trama
private const int TAMANO_MIN = 13;
private void myPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
receiveBuffer += this.myPort.ReadExisting();
if (receiveBuffer.Length >= TAMANO_MIN)
{
receiveDataDelegate myDelegate = new receiveDataDelegate(receiveData);
myDelegate();
}
}
#endregion
#region Delegado: Recepcion
//Frame Start
private string startFrame;
//Frame End
private string EndFrame;
private void receiveData()
{
int Inicio = receiveBuffer.IndexOf(startFrame); // Posicion de Inicio de trama
int Final = receiveBuffer.IndexOf(EndFrame); // Posicion de Final de trama
// Si existe posicion de inicio y una despues del final
if ((Inicio > -1) & (Final > Inicio))
{
// Covertir la trama en un array de char's - Sin StartFrame y EndFrame
byte[] miTrama = StringToBytes(receiveBuffer.Substring(Inicio + 2, Final - 2 - Inicio));
// Eliminar la trama procesada del buffer
receiveBuffer = receiveBuffer.Substring(Final, receiveBuffer.Length - (Final + 2));
//FRAME SIZE
uint frameSize = (uint)((miTrama[0] << 8) + miTrama[1]);
if (frameSize != miTrama.Length) // Se quitaron 2 bytes del frame end, pero como el FrameSize ocupa 2 y no entra en la cuenta, se autojusta, sino hacer el calculo correcto.
{
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: FrameSize - {1} - {2}", DateTime.Now, frameSize, miTrama.Length);
sw.Close();
return;
}
//CHECKSUM
byte checksum = 0;
foreach (byte var in miTrama)
{
checksum += var;
}
checksum -= miTrama[miTrama.Length - 1];
checksum=(byte)(~checksum);
if (checksum != miTrama[miTrama.Length - 1])
{
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Checksum - {1} - {2}", DateTime.Now, checksum, miTrama[miTrama.Length - 1]);
sw.Close();
return;
}
else
{
queueReceiveBuffer.Enqueue(BytesToString(miTrama, 6, miTrama.Length - 7));
}
}
else
// De no cumplirse las condiciones de Inicio/Fin
{
// Si existe final
if (Final > -1)
{
// Eliminar bytes con un 0x3f detras y sin 0x01 delante
if (Final + 2 < receiveBuffer.Length)
{
//Elimino
receiveBuffer = receiveBuffer.Substring(Final + 2, receiveBuffer.Length - (Final + 2));
//Logueo
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Descarte Parcial - {1} - {2}",DateTime.Now,Final, receiveBuffer);
sw.Close();
}
// El final esta en la ultima posicion
else
{
//Logueo
sw = new StreamWriter(myFile.FileName, true);
sw.WriteLine("{0} - ERROR: Descarte TOTAL - {1} - {2}", DateTime.Now, receiveBuffer.Length, receiveBuffer);
sw.Close();
//Elimino
receiveBuffer = "";
}
}
}
}
#endregion
#region Interfaz: Recepcion
// Indica si hay elementos en el buffer de recepcion
public bool isHaveFrame()
{
if (queueReceiveBuffer.Count > 0)
return true;
else
return false;
}
// Devuelve el primer elemento del buffer de recepcion
public string getFrame()
{
if (isHaveFrame())
return queueReceiveBuffer.Dequeue();
else
return "";
}
#endregion
private byte[] StringToBytes(String cadena)
{
return System.Text.Encoding.Default.GetBytes(cadena);
}
private string BytesToString(byte[] bytes)
{
return System.Text.Encoding.Default.GetString(bytes);
}
private string BytesToString(byte[] bytes, int index, int count)
{
return System.Text.Encoding.Default.GetString(bytes, index, count);
}
}
Como ven tome muchisimo de uds, e hice mis pequeñas acotaciones.
Obviamente la parte del Checksum, FrameSize son propias del protocolo. Y tambien el -2 o +2 que son debidos a que mi FrameStart y mi FrameEnd son 2 bytes.
Los ultimos 3 metodos me fueron muy utiles para trabajar de a bytes y recibir correctamente los datos enviados por el microcontrolador con el que me comunico.
Saludos